Windows2003-3790/enduser/netmeeting/av/nac/msivcaps.cpp
2020-09-30 16:53:55 +02:00

2727 lines
88 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* File: msivcaps.cpp
*
* VCM implementation of Microsoft Network Video capability object.
*
* Revision History:
*
* 06/06/96 mikev created msiacaps.cpp
* 07/28/96 philf created (added support for video)
*/
#define _MSIAV_ TRUE
#include "precomp.h"
BOOL GetFormatBuffer();
extern PVCMFORMATDETAILS pvfd_g;
#define PREF_ORDER_UNASSIGNED 0xffff
//External function (in msiacaps.cpp) to read reg info in one shot
#ifdef DEBUG
extern ULONG ReadRegistryFormats (LPCSTR lpszKeyName,CHAR ***pppName,BYTE ***pppData,PUINT pnFormats,DWORD dwDebugSize);
#else
extern ULONG ReadRegistryFormats (LPCSTR lpszKeyName,CHAR ***pppName,BYTE ***pppData,PUINT pnFormats);
#endif
//This can be used as an export, so give it a unique name!
#ifndef _ALPHA_
VIDCAP_DETAILS default_vid_table[] =
{
#ifdef USE_BILINEAR_MSH26X
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Small, 128, 96},0,TRUE,TRUE,1,245760*8,245760*8,10,10,5,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 128x096"},
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Medium, 176, 144},0,TRUE,TRUE,1,245760*8,245760*8,10,10,4,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Large, 352, 288},0,TRUE,TRUE,1,245760*8*4,245760*8*4,10,10,6,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 352x288"},
{VIDEO_FORMAT_MSH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Medium, 176, 144},0,TRUE,TRUE,1,245760*8,245760*8,10,10,7,0,NULL,0,NULL,"Microsoft H.261 Video Codec, vidc.M261, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_MSH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Large, 352, 288},0,TRUE,TRUE,1,245760*8*4,245760*8*4,10,10,8,0,NULL,0,NULL,"Microsoft H.261 Video Codec, vidc.M261, 24bit, 30fps, 352x288"},
{VIDEO_FORMAT_MSH26X,NONSTD_VID_TERMCAP,STD_VID_PARAMS,{RTP_DYNAMIC_MIN+1,0,24, Small, 80, 64},0,TRUE,TRUE,1,245760*8,245760*8,10,10,2,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M26X, 24bit, 30fps, 080x064"},
{VIDEO_FORMAT_MSH26X,NONSTD_VID_TERMCAP,STD_VID_PARAMS,{RTP_DYNAMIC_MIN+1,0,30, 24, Medium, 128, 96},0,TRUE,TRUE,1,245760*8,245760*8,10,10,1,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M26X, 24bit, 30fps, 128x096"},
{VIDEO_FORMAT_MSH26X,NONSTD_VID_TERMCAP,STD_VID_PARAMS,{RTP_DYNAMIC_MIN+1,0,24, Large, 176, 144},0,TRUE,TRUE,1,245760*8,245760*8,10,10,3,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M26X, 24bit, 30fps, 176x144"}
#else
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Small, 128, 96},0,TRUE,TRUE,1,245760*8,245760*8,10,10,5,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 128x096"},
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Medium, 176, 144},0,TRUE,TRUE,1,245760*8,245760*8,10,10,2,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_MSH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Large, 352, 288},0,TRUE,TRUE,1,245760*8*4,245760*8*4,10,10,14,0,NULL,0,NULL,"Microsoft H.263 Video Codec, vidc.M263, 24bit, 30fps, 352x288"},
{VIDEO_FORMAT_MSH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Medium, 176, 144},0,TRUE,TRUE,1,245760*8,245760*8,10,10,9,0,NULL,0,NULL,"Microsoft H.261 Video Codec, vidc.M261, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_MSH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Large, 352, 288},0,TRUE,TRUE,1,245760*8*4,245760*8*4,10,10,20,0,NULL,0,NULL,"Microsoft H.261 Video Codec, vidc.M261, 24bit, 30fps, 352x288"},
#endif
};
#else
VIDCAP_DETAILS default_vid_table[] =
{
{VIDEO_FORMAT_DECH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Small,128, 96},0,TRUE,TRUE,1,53760,53760,10,10,10,0,0,5,0,NULL,0,NULL, "Digital H263 Video CODEC, vidc.D263, 24bit, 30fps, 128x096"},
{VIDEO_FORMAT_DECH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Medium,176, 144},0,TRUE,TRUE,1,53760,53760,10,10,10,0,0,2,0,NULL,0,NULL,"Digital H263 Video Codec, vidc.D263, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_DECH263,STD_VID_TERMCAP(H245_CLIENT_VID_H263),STD_VID_PARAMS,{RTP_PAYLOAD_H263,0,30, 24, Large,352, 288},0,TRUE,TRUE,1,53760,53760,10,10,10,0,0,14,0,NULL,0,NULL,"Digital H263 Video Codec, vidc.D263, 24bit, 30fps, 352x288"},
{VIDEO_FORMAT_DECH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Medium,176, 144},0,TRUE,TRUE,1,53760,53760,10,10,10,0,0,9,0,NULL,0,NULL,"Digital H261 Video Codec, vidc.D261, 24bit, 30fps, 176x144"},
{VIDEO_FORMAT_DECH261,STD_VID_TERMCAP(H245_CLIENT_VID_H261),STD_VID_PARAMS,{RTP_PAYLOAD_H261,0,30, 24, Large,352, 288},0,TRUE,TRUE,1,53760,53760,10,10,10,0,0,20,0,NULL,0,NULL,"Digital H261 Video Codec, vidc.D261, 24bit, 30fps, 352x288"},
};
#endif
static UINT uDefVidTableEntries = sizeof(default_vid_table) /sizeof(VIDCAP_DETAILS);
static BOOL bCreateDefTable = FALSE;
//
// static members of CMsivCapability
//
MEDIA_FORMAT_ID CMsivCapability::IDsByRank[MAX_CAPS_PRESORT];
UINT CMsivCapability::uNumLocalFormats = 0; // # of active entries in pLocalFormats
UINT CMsivCapability::uStaticRef = 0; // global ref count
UINT CMsivCapability::uCapIDBase = 0; // rebase capability ID to index into IDsByRank
UINT CMsivCapability::uLocalFormatCapacity = 0; // size of pLocalFormats (in multiples of AUDCAP_DETAILS)
VIDCAP_DETAILS * CMsivCapability::pLocalFormats = NULL;
CMsivCapability::CMsivCapability()
:uRef(1),
wMaxCPU(95),
uNumRemoteDecodeFormats(0),
uRemoteDecodeFormatCapacity(0),
pRemoteDecodeFormats(NULL),
bPublicizeTXCaps(FALSE),
bPublicizeTSTradeoff(TRUE)
{
m_IAppVidCap.Init(this);
}
CMsivCapability::~CMsivCapability()
{
UINT u;
VIDCAP_DETAILS *pDetails;
// release global static memory (the local capabilities) if this is the last delete
if(uStaticRef <= 1)
{
if (pLocalFormats)
{
pDetails = pLocalFormats;
for(u=0; u <uNumLocalFormats; u++)
{
if(pDetails->lpLocalFormatDetails)
{
MEMFREE(pDetails->lpLocalFormatDetails);
}
// there really should never be remote details associated with the local
// formats........
if(pDetails->lpRemoteFormatDetails)
{
MEMFREE(pDetails->lpRemoteFormatDetails);
}
pDetails++;
}
MEMFREE(pLocalFormats);
pLocalFormats=NULL;
uLocalFormatCapacity = 0;
}
uStaticRef--;
}
else
{
uStaticRef--;
}
if (pRemoteDecodeFormats)
{
pDetails = pRemoteDecodeFormats;
for(u=0; u <uNumRemoteDecodeFormats; u++)
{
if(pDetails->lpLocalFormatDetails)
{
MEMFREE(pDetails->lpLocalFormatDetails);
}
// there really should never be remote details associated with the local
// formats........
if(pDetails->lpRemoteFormatDetails)
{
MEMFREE(pDetails->lpRemoteFormatDetails);
}
pDetails++;
}
MEMFREE(pRemoteDecodeFormats);
pRemoteDecodeFormats=NULL;
uRemoteDecodeFormatCapacity = 0;
}
}
UINT CMsivCapability::GetNumCaps(BOOL bRXCaps)
{
UINT u, uOut=0;
VIDCAP_DETAILS *pDecodeDetails = pLocalFormats;
if(bRXCaps)
{
for(u=0; u <uNumLocalFormats; u++)
{
if(pDecodeDetails->bRecvEnabled)
uOut++;
pDecodeDetails++;
}
return uOut;
}
else
{
for(u=0; u <uNumLocalFormats; u++)
{
if(pDecodeDetails->bSendEnabled)
uOut++;
pDecodeDetails++;
}
return uOut;
}
}
STDMETHODIMP CMsivCapability::QueryInterface( REFIID iid, void ** ppvObject)
{
HRESULT hr = E_NOINTERFACE;
if(!ppvObject)
return hr;
*ppvObject = 0;
if(iid == IID_IAppVidCap )
{
*ppvObject = (LPAPPVIDCAPPIF)&m_IAppVidCap;
AddRef();
hr = hrSuccess;
}
else if(iid == IID_IH323MediaCap)
{
*ppvObject = (IH323MediaCap *)this;
AddRef();
hr = hrSuccess;
}
else if (iid == IID_IUnknown)
{
*ppvObject = this;
AddRef();
hr = hrSuccess;
}
return hr;
}
ULONG CMsivCapability::AddRef()
{
uRef++;
return uRef;
}
ULONG CMsivCapability::Release()
{
uRef--;
if(uRef == 0)
{
delete this;
return 0;
}
return uRef;
}
HRESULT CMsivCapability::GetNumFormats(UINT *puNumFmtOut)
{
*puNumFmtOut = uNumLocalFormats;
return hrSuccess;
}
VOID CMsivCapability::FreeRegistryKeyName(LPTSTR lpszKeyName)
{
if (lpszKeyName)
{
LocalFree(lpszKeyName);
}
}
LPTSTR CMsivCapability::AllocRegistryKeyName(LPTSTR lpDriverName,
UINT uSampleRate, UINT uBitsPerSample, UINT uBitsPerSec,UINT uWidth,UINT uHeight)
{
FX_ENTRY(("AllocRegistryKeyName"));
BOOL bRet = FALSE;
LPTSTR lpszKeyName = NULL;
if(!lpDriverName)
{
return NULL;
}
// build a subkey name (drivername_samplerate_bitspersample)
// allow room for THREE underscore chars + 2x17 bytes of string returned
// from _itoa
// NOTE: use wsprintf instead of itoa - because of dependency on runtime lib
//Added 2 UINTs for video...
lpszKeyName = (LPTSTR)LocalAlloc (LPTR, lstrlen(lpDriverName) * sizeof(*lpDriverName) +5*20);
if (!lpszKeyName)
{
ERRORMESSAGE(("%s: LocalAlloc failed\r\n",_fx_));
return(NULL);
}
// build a subkey name ("drivername_samplerate_bitspersample")
wsprintf(lpszKeyName,
"%s_%u_%u_%u_%u_%u",
lpDriverName,
uSampleRate,
uBitsPerSample,
uBitsPerSec,
uWidth,
uHeight);
return (lpszKeyName);
}
VOID CMsivCapability::SortEncodeCaps(SortMode sortmode)
{
UINT iSorted=0;
UINT iInsert = 0;
UINT iCache=0;
UINT iTemp =0;
BOOL bInsert;
VIDCAP_DETAILS *pDetails1, *pDetails2;
if(!uNumLocalFormats)
return;
if(uNumLocalFormats ==1)
{
IDsByRank[0]=0;
return;
}
// look at every cached format, build index array
for(iCache=0;iCache<uNumLocalFormats;iCache++)
{
pDetails1 = pLocalFormats+iCache;
for(iInsert=0;iInsert < iSorted; iInsert++)
{
pDetails2 = pLocalFormats+IDsByRank[iInsert];
// if existing stuff is less than new stuff....
bInsert = FALSE;
switch(sortmode)
{
case SortByAppPref:
if(pDetails2->wApplicationPrefOrder > pDetails1->wApplicationPrefOrder)
bInsert = TRUE;
break;
default:
break;
}
if(bInsert)
{
if(iSorted < MAX_CAPS_PRESORT)
{
iSorted++;
}
// make room, if there is something in the last element,
// it gets overwritten
for(iTemp = iSorted-1; iTemp > iInsert; iTemp--)
{
IDsByRank[iTemp] = IDsByRank[iTemp-1];
}
// insert at iInsert
IDsByRank[iInsert] = iCache;
break;
}
}
// check end boundary
if((iInsert == iSorted) && (iInsert < MAX_CAPS_PRESORT))
{
IDsByRank[iInsert] = iCache;
iSorted++;
}
}
}
BOOL CMsivCapability::Init()
{
BOOL bRet;
if(uStaticRef == 0)
{
if(bRet = ReInit())
{
uStaticRef++;
}
}
else
{
uStaticRef++;
bRet = TRUE;
}
return bRet;
}
BOOL CMsivCapability::ReInit()
{
DWORD dwDisposition;
BOOL bRet = TRUE;
//CVcmCapability::ReInit(); // base class ReInit MUST ALWAYS BE CALLED
SYSTEM_INFO si;
ZeroMemory(&IDsByRank, sizeof(IDsByRank));
// LOOKLOOK - this supports a hack to disable CPU intensive codecs if not running on a pentium
GetSystemInfo(&si);
wMaxCPU = (si.dwProcessorType == PROCESSOR_INTEL_PENTIUM )? 100 : 95;
UINT uNumRemoteDecodeFormats; // # of entries for remote decode capabilities
UINT uRemoteDecodeFormatCapacity; // size of pRemoteDecodeFormats (in multiples of VIDCAP_DETAILS)
if (pLocalFormats)
{
UINT u;
VIDCAP_DETAILS *pDetails = pLocalFormats;
for(u=0; u <uNumLocalFormats; u++)
{
if(pDetails->lpLocalFormatDetails)
{
MEMFREE(pDetails->lpLocalFormatDetails);
}
// there really should never be remote details associated with the local
// formats........
if(pDetails->lpRemoteFormatDetails)
{
MEMFREE(pDetails->lpRemoteFormatDetails);
}
pDetails++;
}
MEMFREE(pLocalFormats);
pLocalFormats = NULL;
uLocalFormatCapacity = 0;
}
uNumLocalFormats = 0;
uCapIDBase = 0;
uLocalFormatCapacity =0;
// m_pAppParam should be non-NULL only if we want to add a VCM format
// and not for standard enumeration
m_pAppParam = NULL;
if(!FormatEnum(this, VCM_FORMATENUMF_APP))
{
bRet = FALSE;
goto RELEASE_AND_EXIT;
}
SortEncodeCaps(SortByAppPref);
RELEASE_AND_EXIT:
return bRet;
}
STDMETHODIMP CMsivCapability::GetDecodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
{
// validate input
UINT uIndex = IDToIndex(FormatID);
if(uIndex >= (UINT)uNumLocalFormats)
{
*puSize = 0;
*ppFormat = NULL;
return E_INVALIDARG;
}
*ppFormat = (pLocalFormats + uIndex)->lpLocalFormatDetails;
*puSize = sizeof(VIDEOFORMATEX);
return S_OK;
}
STDMETHODIMP CMsivCapability::GetEncodeFormatDetails(MEDIA_FORMAT_ID FormatID, VOID **ppFormat, UINT *puSize)
{
// same as GetDecodeFormatDetails
return GetDecodeFormatDetails(FormatID, ppFormat, puSize);
}
VOID CMsivCapability::CalculateFormatProperties(VIDCAP_DETAILS *pFmtBuf, PVIDEOFORMATEX lpvfx)
{
if(!pFmtBuf)
{
return;
}
// Estimate input bit rate
UINT uBitrateIn = lpvfx->nSamplesPerSec * WIDTHBYTES(lpvfx->bih.biWidth * lpvfx->bih.biBitCount) * lpvfx->bih.biHeight * 8;
// set the maximum bitrate (uMaxBitrate). we're not setting the average bitrate (uAvgBitrate),
// since the nAvgBytesPerSec reported by VCM is really worst case. uAvgBitrate will be set
// from the hardcoded numbers for our known codecs and from the provided VIDCAP_INFO for
// installable codecs
pFmtBuf->uMaxBitrate = (lpvfx->nAvgBytesPerSec)? lpvfx->nAvgBytesPerSec*8:uBitrateIn;
}
VIDEO_FORMAT_ID CMsivCapability::AddFormat(VIDCAP_DETAILS *pFmtBuf,
LPVOID lpvMappingData, UINT uSize)
{
VIDCAP_DETAILS *pTemp;
VIDEO_PARAMS *pVidCapInfo;
UINT format;
if(!pFmtBuf)
{
return INVALID_VIDEO_FORMAT;
}
// check room
if(uLocalFormatCapacity <= uNumLocalFormats)
{
// get more mem, realloc memory by CAP_CHUNK_SIZE for pLocalFormats
pTemp = (VIDCAP_DETAILS *)MEMALLOC((uNumLocalFormats + CAP_CHUNK_SIZE)*sizeof(VIDCAP_DETAILS));
if(!pTemp)
goto ERROR_EXIT;
// remember how much capacity we now have
uLocalFormatCapacity = uNumLocalFormats + CAP_CHUNK_SIZE;
#ifdef DEBUG
if((uNumLocalFormats && !pLocalFormats) || (!uNumLocalFormats && pLocalFormats))
{
ERRORMESSAGE(("AddFormat:leak! uNumLocalFormats:0x%08lX, pLocalFormats:0x%08lX\r\n", uNumLocalFormats,pLocalFormats));
}
#endif
// copy old stuff, discard old mem
if(uNumLocalFormats && pLocalFormats)
{
memcpy(pTemp, pLocalFormats, uNumLocalFormats*sizeof(VIDCAP_DETAILS));
MEMFREE(pLocalFormats);
}
pLocalFormats = pTemp;
}
// pTemp is where the stuff is cached
pTemp = pLocalFormats+uNumLocalFormats;
memcpy(pTemp, pFmtBuf, sizeof(VIDCAP_DETAILS));
pTemp->uLocalDetailsSize = 0; // clear this now
if(uSize && lpvMappingData)
{
pTemp->lpLocalFormatDetails = MEMALLOC(uSize);
if(pTemp->lpLocalFormatDetails)
{
memcpy(pTemp->lpLocalFormatDetails, lpvMappingData, uSize);
pTemp->uLocalDetailsSize = uSize;
}
#ifdef DEBUG
else
{
ERRORMESSAGE(("AddFormat:allocation failed!\r\n"));
}
#endif
}
else
{
}
// LOOKLOOK NEED TO FIXUP channel parameters
// pTemp->dwDefaultSamples
// pTemp->nonstd_params.wFramesPerPkt
// pTemp->nonstd_params.wFramesPerPktMax
// pTemp->nonstd_params.wFramesPerPktMin
// pTemp->nonstd_params.wDataRate
// pTemp->nonstd_params.wFrameSize
// fixup the H245 parameters. Use the index of the cap entry as the cap ID
pTemp->H245Cap.CapId = (USHORT)IndexToId(uNumLocalFormats);
if(pTemp->H245Cap.ClientType ==0
|| pTemp->H245Cap.ClientType ==H245_CLIENT_VID_NONSTD)
{
pTemp->H245Cap.Cap.H245Vid_NONSTD.nonStandardIdentifier.choice = h221NonStandard_chosen;
// NOTE: there is some question about the correct byte order
// of the codes in the h221NonStandard structure
pTemp->H245Cap.Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35CountryCode = USA_H221_COUNTRY_CODE;
pTemp->H245Cap.Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35Extension = USA_H221_COUNTRY_EXTENSION;
pTemp->H245Cap.Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.manufacturerCode = MICROSOFT_H_221_MFG_CODE;
// Set the nonstandard data fields to null for now. The nonstandard cap data will be
// created when capabilities are serialized.
pTemp->H245Cap.Cap.H245Vid_NONSTD.data.length = 0;
pTemp->H245Cap.Cap.H245Vid_NONSTD.data.value = NULL;
}
else
{
switch (pTemp->H245Cap.ClientType )
{
case H245_CLIENT_VID_H263: {
pVidCapInfo=&pTemp->video_params;
format=get_format (pVidCapInfo->biWidth,pVidCapInfo->biHeight);
switch (format) {
case SQCIF: {
pTemp->H245Cap.Cap.H245Vid_H263.bit_mask =H263VideoCapability_sqcifMPI_present;
//MPI minimum interval in units of 1/29.97sec so 30/ (frames/sec) is reasonable
pTemp->H245Cap.Cap.H245Vid_H263.sqcifMPI = 30/pVidCapInfo->uSamplesPerSec;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_qcifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_cifMPI =0;
break;
}
case QCIF: {
pTemp->H245Cap.Cap.H245Vid_H263.bit_mask =H263VideoCapability_qcifMPI_present;
pTemp->H245Cap.Cap.H245Vid_H263.sqcifMPI = 0;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_qcifMPI =30/pVidCapInfo->uSamplesPerSec;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_cifMPI =0;
break;
}
case CIF: {
pTemp->H245Cap.Cap.H245Vid_H263.bit_mask =H263VideoCapability_cifMPI_present;
pTemp->H245Cap.Cap.H245Vid_H263.sqcifMPI = 0;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_qcifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.H263VdCpblty_cifMPI =30/pVidCapInfo->uSamplesPerSec;
break;
}
default:
break;
}
pTemp->H245Cap.Cap.H245Vid_H263.cif4MPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.cif16MPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.maxBitRate = pFmtBuf->uMaxBitrate / 100; // in units of 100 bits/s
pTemp->H245Cap.Cap.H245Vid_H263.unrestrictedVector = FALSE;
pTemp->H245Cap.Cap.H245Vid_H263.arithmeticCoding = FALSE;
pTemp->H245Cap.Cap.H245Vid_H263.advancedPrediction = FALSE;
pTemp->H245Cap.Cap.H245Vid_H263.pbFrames = FALSE;
pTemp->H245Cap.Cap.H245Vid_H263.tmprlSptlTrdOffCpblty = FALSE;
pTemp->H245Cap.Cap.H245Vid_H263.hrd_B = 0;
pTemp->H245Cap.Cap.H245Vid_H263.bppMaxKb = 0;
/* Optional, and not supported pTemp->H245Cap.Cap.H245Vid_H263.slowQcifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.slowSqcifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.slowCifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.slowCif4MPI =0;
pTemp->H245Cap.Cap.H245Vid_H263.slowCif16MPI =0;
*/
pTemp->H245Cap.Cap.H245Vid_H263.H263VCy_errrCmpnstn = TRUE;
break;
}
case H245_CLIENT_VID_H261:
pVidCapInfo=&pTemp->video_params;
format=get_format (pVidCapInfo->biWidth,pVidCapInfo->biHeight);
switch (format) {
case QCIF: {
pTemp->H245Cap.Cap.H245Vid_H261.bit_mask =H261VdCpblty_qcifMPI_present;
pTemp->H245Cap.Cap.H245Vid_H261.H261VdCpblty_qcifMPI =max (1,min (4,30/pVidCapInfo->uSamplesPerSec));
pTemp->H245Cap.Cap.H245Vid_H261.H261VdCpblty_cifMPI =0;
break;
}
case CIF: {
pTemp->H245Cap.Cap.H245Vid_H261.bit_mask =H261VdCpblty_cifMPI_present;
pTemp->H245Cap.Cap.H245Vid_H261.H261VdCpblty_qcifMPI =0;
pTemp->H245Cap.Cap.H245Vid_H261.H261VdCpblty_cifMPI =max (1,min(4,30/pVidCapInfo->uSamplesPerSec));
break;
}
default:
break;
}
pTemp->H245Cap.Cap.H245Vid_H261.maxBitRate = pFmtBuf->uMaxBitrate / 100; // in units of 100 bits/s
pTemp->H245Cap.Cap.H245Vid_H261.tmprlSptlTrdOffCpblty = FALSE;
pTemp->H245Cap.Cap.H245Vid_H261.stillImageTransmission = FALSE;
break;
}
}
uNumLocalFormats++;
return pTemp->H245Cap.CapId;
ERROR_EXIT:
return INVALID_VIDEO_FORMAT;
}
/***************************************************************************
Name : CMsivCapability::BuildFormatName
Purpose : Builds a format name for a format, from the format name and
the tag name
Parameters: pVidcapDetails [out] - pointer to an VIDCAP_DETAILS structure, where the
created value name will be stored
pszDriverName [in] - pointer to the name of the driver
pszFormatName [in] - pointer to name of the format
Returns : BOOL
Comment :
***************************************************************************/
BOOL CMsivCapability::BuildFormatName( PVIDCAP_DETAILS pVidcapDetails,
WCHAR *pszDriverName,
WCHAR *pszFormatName)
{
int iLen, iLen2;
BOOL bRet=TRUE;
char szTemp[260];
if (!pVidcapDetails ||
!pszDriverName ||
!pszFormatName)
{
bRet = FALSE;
goto out;
}
// concatenate VCM strings to form the first part of the registry key - the
// format is szFormatTag (actually pVidcapDetails->szFormat)
// (the string which describes the format tag followed by szFormatDetails
// (the string which describes parameters, e.g. sample rate)
iLen2 = WideCharToMultiByte(GetACP(), 0, pszDriverName, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(GetACP(), 0, pszDriverName, iLen2, szTemp, iLen2, NULL, NULL);
lstrcpyn(pVidcapDetails->szFormat, szTemp, sizeof(pVidcapDetails->szFormat));
iLen = lstrlen(pVidcapDetails->szFormat);
// if the format tag description string takes up all the space, don't
// bother with the format details (need space for ", " also).
// we're going to say that if we don't have room for 4 characters
// of the format details string + " ,", then it's not worth it if the
// point is generating a unique string -if it is not unique by now, it
// will be because some VCM driver writer was misinformed
if(iLen < (sizeof(pVidcapDetails->szFormat) + 8*sizeof(TCHAR)))
{
// ok to concatenate
lstrcat(pVidcapDetails->szFormat,", ");
// must check for truncation. so do the final concatenation via lstrcpyn
// lstrcat(pFormatPrefsBuf->szFormat, pvfd->szFormat);
iLen2 = WideCharToMultiByte(GetACP(), 0, pszFormatName, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(GetACP(), 0, pszFormatName, iLen2, szTemp, iLen2, NULL, NULL);
iLen = lstrlen(pVidcapDetails->szFormat);
lstrcpyn(pVidcapDetails->szFormat+iLen, szTemp,
sizeof(pVidcapDetails->szFormat) - iLen - sizeof(TCHAR));
}
out:
return bRet;
}
/***************************************************************************
Name : CMsivCapability::GetFormatName
Purpose : Gets a driver and format info from VCM and builds a format name
Parameters: pVidcapDetails [out] - pointer to an VIDCAP_DETAILS structure, where the
created value name will be stored
pvfx [in] - pointer to the VIDEOFORMATEX structure for which we
need the driver name and the format name
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CMsivCapability::GetFormatName( PVIDCAP_DETAILS pVidcapDetails,
PVIDEOFORMATEX pvfx)
{
VCMDRIVERDETAILS vdd;
VCMFORMATDETAILS vfd;
HRESULT hr=NOERROR;
// get the driver details info in order to build correct format name
vdd.fccHandler = pvfx->dwFormatTag;
if (vcmDriverDetails(&vdd) != MMSYSERR_NOERROR)
{
ERRORMESSAGE(("CMsivCapability::GetFormatName: can't get the driver details\r\n"));
hr = CAPS_E_NOMATCH;
goto out;
}
// have the driver details. get the format details
vfd.pvfx = pvfx;
if (vcmFormatDetails(&vfd) != MMSYSERR_NOERROR)
{
ERRORMESSAGE(("CMsivCapability::GetFormatName: can't get the format details\r\n"));
hr = CAPS_E_NOMATCH;
goto out;
}
// have the format details too. build the name to store in the registry
if (!BuildFormatName(pVidcapDetails, vdd.szDescription, vfd.szFormat))
{
ERRORMESSAGE(("CMsivCapability::GetFormatName: can't build format name\r\n"));
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
out:
return hr;
}
BOOL CMsivCapability::FormatEnumHandler(HVCMDRIVERID hvdid,
PVCMFORMATDETAILS pvfd, VCMDRIVERDETAILS *pvdd, DWORD_PTR dwInstance)
{
CMsivCapability *pCapObject = (CMsivCapability *)dwInstance;
VIDCAP_DETAILS vidcap_entry;
UINT i;
// evaluate the details
if(IsFormatSpecified(pvfd->pvfx, pvfd, pvdd, &vidcap_entry))
{
DEBUGMSG(ZONE_VCM,("FormatEnumHandler: tag 0x%08X\r\n",
pvfd->pvfx->dwFormatTag));
DEBUGMSG(ZONE_VCM,("FormatEnumHandler: nSamplesPerSec 0x%08lX, nAvgBytesPerSec 0x%08lX,\r\n",
pvfd->pvfx->nSamplesPerSec, pvfd->pvfx->nAvgBytesPerSec));
DEBUGMSG(ZONE_VCM,("FormatEnumHandler: nBlockAlign 0x%08X, wBitsPerSample 0x%04X\r\n",
pvfd->pvfx->nBlockAlign, pvfd->pvfx->wBitsPerSample));
DEBUGMSG(ZONE_VCM,("FormatEnumHandler: szFormat %s,\r\n",
pvfd->szFormat));
// done inside IsFormatSpecified and/or whatever it calls
// CalculateFormatProperties(&audcap_details, pvfd->pvfx);
i=AddFormat(&vidcap_entry, (LPVOID)pvfd->pvfx,
(pvfd->pvfx) ? sizeof(VIDEOFORMATEX):0);
if (i != INVALID_VIDEO_FORMAT) {
//Set the Send/Recv Flags...
//This now needs to set bSendEnabled, and bRecvEnabled, according to pvfd->dwFlags
//So, we need to find the format, and update the flags accordingly.
//OUTPUT IS RECV!!!!
if (pvfd->dwFlags == VCM_FORMATENUMF_BOTH) {
pLocalFormats[i].bSendEnabled=TRUE;
pLocalFormats[i].bRecvEnabled=TRUE;
}else {
if(pvfd->dwFlags == VCM_FORMATENUMF_OUTPUT) {
pLocalFormats[i].bSendEnabled=FALSE;
pLocalFormats[i].bRecvEnabled=TRUE;
} else {
pLocalFormats[i].bSendEnabled=TRUE;
pLocalFormats[i].bRecvEnabled=FALSE;
}
}
}
}
return TRUE;
}
BOOL CMsivCapability::IsFormatSpecified(PVIDEOFORMATEX lpFormat, PVCMFORMATDETAILS pvfd,
VCMDRIVERDETAILS *pvdd, VIDCAP_DETAILS *pVidcapDetails)
{
VIDCAP_DETAILS *pcap_entry;
BOOL bRet = FALSE;
LPTSTR lpszKeyName = NULL;
DWORD dwRes;
UINT i;
if(!lpFormat || !pVidcapDetails)
{
return FALSE;
}
RtlZeroMemory((PVOID) pVidcapDetails, sizeof(VIDCAP_DETAILS));
// fixup the VIDEOFORMAT fields of video_params so that the key name can be built
pVidcapDetails->video_params.uSamplesPerSec = lpFormat->nSamplesPerSec;
pVidcapDetails->video_params.uBitsPerSample = MAKELONG(lpFormat->bih.biBitCount,0);
pVidcapDetails->video_params.biWidth=lpFormat->bih.biWidth;
pVidcapDetails->video_params.biHeight=lpFormat->bih.biHeight;
pVidcapDetails->uMaxBitrate=lpFormat->nAvgBytesPerSec * 8;
// build the name of the format out of the driver and the VCM format name
if ((!pvdd) ||
!BuildFormatName(pVidcapDetails, pvdd->szDescription, pvfd->szFormat))
{
ERRORMESSAGE(("IsFormatSpecified: Coludn't build format name\r\n"));
return(FALSE);
}
lpszKeyName = AllocRegistryKeyName( pVidcapDetails->szFormat,
pVidcapDetails->video_params.uSamplesPerSec,
pVidcapDetails->video_params.uBitsPerSample,
pVidcapDetails->uMaxBitrate,
pVidcapDetails->video_params.biWidth,
pVidcapDetails->video_params.biHeight);
if (!lpszKeyName)
{
ERRORMESSAGE(("IsFormatSpecified: Alloc failed\r\n"));
return(FALSE);
}
RegEntry reVidCaps(szRegInternetPhone TEXT("\\") szRegInternetPhoneVCMEncodings,
HKEY_LOCAL_MACHINE,
FALSE,
KEY_READ);
dwRes = reVidCaps.GetBinary(lpszKeyName, (PVOID *) &pcap_entry);
// use current registry setting if it exists
if(dwRes && (dwRes == sizeof(VIDCAP_DETAILS)))
{
// do a quick sanity check on the contents
if((lpFormat->dwFormatTag == pcap_entry->dwFormatTag)
&& (lpFormat->nSamplesPerSec == (DWORD)pcap_entry->video_params.uSamplesPerSec)
&& (lpFormat->wBitsPerSample == LOWORD(pcap_entry->video_params.uBitsPerSample))
&& (lpFormat->bih.biWidth == (LONG) pcap_entry->video_params.biWidth)
&& (lpFormat->bih.biHeight == (LONG) pcap_entry->video_params.biHeight))
{
CopyMemory(pVidcapDetails, pcap_entry, sizeof(VIDCAP_DETAILS));
bRet = TRUE;
}
}
else // check the static default table, and recreate the default entries
{
for(i=0;i< uDefVidTableEntries; i++)
{
if((lpFormat->dwFormatTag == default_vid_table[i].dwFormatTag)
&& (lpFormat->nSamplesPerSec == (DWORD)default_vid_table[i].video_params.uSamplesPerSec)
&& (lpFormat->wBitsPerSample == LOWORD(default_vid_table[i].video_params.uBitsPerSample))
&& (lpFormat->bih.biWidth == (LONG) default_vid_table[i].video_params.biWidth)
&& (lpFormat->bih.biHeight == (LONG) default_vid_table[i].video_params.biHeight))
{
// found matching default entry - copy stuff from table
// (but don't overwrite the string)
memcpy(pVidcapDetails, &default_vid_table[i],
sizeof(VIDCAP_DETAILS) - sizeof(pVidcapDetails->szFormat));
// LOOKLOOK - test against CPU limitations.
// this supports a hack to disable CPU intensive codecs if not running
//on a pentium
if(default_vid_table[i].wCPUUtilizationEncode > wMaxCPU)
{
pVidcapDetails->bSendEnabled = FALSE;
pVidcapDetails->bRecvEnabled = FALSE;
}
// add this to the registry
CalculateFormatProperties(pVidcapDetails, lpFormat);
bRet = UpdateFormatInRegistry(pVidcapDetails);
break;
}
}
}
if (lpszKeyName)
{
FreeRegistryKeyName(lpszKeyName);
}
return(bRet);
}
/***************************************************************************
Name : CMsivCapability::CopyVidcapInfo
Purpose : Copies basic video info from an VIDCAP_INFO structure to an
VIDCAP_DETAILS structure, or vice versa. VIDCAP_INFO is external
representation. VIDCAP_DETAILS is internal one.
Parameters: pDetails - pointer to an VIDCAP_DETAILS structure
pInfo - pointer to an VIDCAP_INFO structure
bDirection - 0 = ->, 1 = <-
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CMsivCapability::CopyVidcapInfo(PVIDCAP_DETAILS pDetails,
PVIDCAP_INFO pInfo,
BOOL bDirection)
{
WORD wSortIndex;
VIDEO_FORMAT_ID Id;
UINT uIndex;
HRESULT hr=NOERROR;
if(!pInfo || !pDetails)
{
hr = CAPS_E_INVALID_PARAM;
goto out;
}
if (bDirection)
{
// VIDCAP_INFO -> VIDCAP_DETAILS
// the caller cannot modify szFormat, Id, wSortIndex and uMaxBitrate, all calculated fields
// nAvgBitrate can be provided, but will be overriden if the codec provided a non-zero
// value in the VIDEOFORMATEX structure
pDetails->dwFormatTag = pInfo->dwFormatTag;
pDetails->uAvgBitrate = pInfo->uAvgBitrate;
pDetails->wCPUUtilizationEncode = pInfo->wCPUUtilizationEncode;
pDetails->wCPUUtilizationDecode = pInfo->wCPUUtilizationDecode;
pDetails->bSendEnabled = pInfo->bSendEnabled;
pDetails->bRecvEnabled = pInfo->bRecvEnabled;
pDetails->video_params.enumVideoSize = pInfo->enumVideoSize;
pDetails->video_params.biHeight = pInfo->bih.biHeight;
pDetails->video_params.biWidth = pInfo->bih.biWidth;
// lpLocalFormatDetails is updated in AddFormat
// DO NOT overwrite any of the fields used to construct the regkey name
// pDetails->video_params.uSamplesPerSec = pInfo->uFrameRate;
pDetails->video_params.uBitsPerSample = pInfo->dwBitsPerSample;
//Re-adjust to frame rate. MPI is Interval in units of 1/29.97 seconds
//No div by zero error
pInfo->uFrameRate= max(1,pInfo->uFrameRate);
pDetails->nonstd_params.MPI = 30/pInfo->uFrameRate;
}
else
{
// VIDCAP_DETAILS -> VIDCAP_INFO
PVIDEOFORMATEX pvfx = (PVIDEOFORMATEX) pDetails->lpLocalFormatDetails;
// find the sort index.
uIndex = (UINT)(pDetails - pLocalFormats);
Id = IndexToId(uIndex);
for(wSortIndex=0; wSortIndex<uNumLocalFormats && wSortIndex < MAX_CAPS_PRESORT; wSortIndex++)
{
if (uIndex == IDsByRank[wSortIndex])
break; // found it
}
// note: recall that only MAX_CAPS_PRESORT are sorted and the rest are in random order.
// the rest all have a value of MAX_CAPS_PRESORT for the sort index
pInfo->dwFormatTag = pDetails->dwFormatTag;
pInfo->Id = Id;
memcpy(pInfo->szFormat, pDetails->szFormat, sizeof(pInfo->szFormat));
pInfo->wCPUUtilizationEncode = pDetails->wCPUUtilizationEncode;
pInfo->wCPUUtilizationDecode = pDetails->wCPUUtilizationDecode;
pInfo->bSendEnabled = pDetails->bSendEnabled;
pInfo->bRecvEnabled = pDetails->bRecvEnabled;
pInfo->wSortIndex = wSortIndex;
pInfo->enumVideoSize = pDetails->video_params.enumVideoSize;
if (pvfx)
RtlCopyMemory(&pInfo->bih, &pvfx->bih, sizeof(BITMAPINFOHEADER));
//The h.323 nonstd params for bitrate is in units of 100 bits/sec
pInfo->dwBitsPerSample = pDetails->video_params.uBitsPerSample;
pInfo->uAvgBitrate = pDetails->uAvgBitrate;
pInfo->uMaxBitrate = pDetails->nonstd_params.maxBitRate*100;
//Re-adjust to frame rate. MPI is Interval in units of 1/29.97 seconds
//No div by zero error
pDetails->nonstd_params.MPI= max(1,pDetails->nonstd_params.MPI);
pInfo->uFrameRate = min(30,30/pDetails->nonstd_params.MPI);
}
out:
return hr;
}
HRESULT CMsivCapability::EnumCommonFormats(PBASIC_VIDCAP_INFO pFmtBuf, UINT uBufsize,
UINT *uNumFmtOut, BOOL bTXCaps)
{
UINT u, uNumOut = 0;;
HRESULT hr = hrSuccess;
VIDCAP_DETAILS *pDetails = pLocalFormats;
MEDIA_FORMAT_ID FormatIDRemote;
HRESULT hrIsCommon;
// validate input
if(!pFmtBuf || !uNumFmtOut || (uBufsize < (sizeof(BASIC_VIDCAP_INFO)*uNumLocalFormats)))
{
return CAPS_E_INVALID_PARAM;
}
if(!uNumLocalFormats || !pDetails)
{
return CAPS_E_NOCAPS;
}
// temporary - enumerating requestable receive formats is not yet supported
if(!bTXCaps)
return CAPS_E_NOT_SUPPORTED;
for(u=0; (u <uNumLocalFormats) && (u <MAX_CAPS_PRESORT); u++)
{
pDetails = pLocalFormats + IDsByRank[u];
// if there is a session, then return formats that are common to local and remote.
if(uNumRemoteDecodeFormats)
{
hrIsCommon = ResolveToLocalFormat(IndexToId(IDsByRank[u]), &FormatIDRemote);
if(HR_SUCCEEDED(hrIsCommon))
{
hr = CopyVidcapInfo (pDetails, pFmtBuf, 0);
if(!HR_SUCCEEDED(hr))
goto EXIT;
uNumOut++;
pFmtBuf++;
}
}
else // no remote capabilities exist because there is no current session
{
hr = CAPS_E_NOCAPS;
}
}
*uNumFmtOut = uNumOut;
EXIT:
return hr;
}
HRESULT CMsivCapability::EnumFormats(PBASIC_VIDCAP_INFO pFmtBuf, UINT uBufsize,
UINT *uNumFmtOut)
{
UINT u;
HRESULT hr = hrSuccess;
VIDCAP_DETAILS *pDetails = pLocalFormats;
// validate input
if(!pFmtBuf || !uNumFmtOut || (uBufsize < (sizeof(BASIC_VIDCAP_INFO)*uNumLocalFormats)))
{
return CAPS_E_INVALID_PARAM;
}
if(!uNumLocalFormats || !pDetails)
{
return CAPS_E_NOCAPS;
}
for(u=0; (u <uNumLocalFormats) && (u <MAX_CAPS_PRESORT); u++)
{
pDetails = pLocalFormats + IDsByRank[u];
hr = CopyVidcapInfo (pDetails, pFmtBuf, 0);
if(!HR_SUCCEEDED(hr))
goto EXIT;
pFmtBuf++;
}
*uNumFmtOut = min(uNumLocalFormats, MAX_CAPS_PRESORT);
EXIT:
return hr;
}
HRESULT CMsivCapability::GetBasicVidcapInfo (VIDEO_FORMAT_ID Id, PBASIC_VIDCAP_INFO pFormatPrefsBuf)
{
VIDCAP_DETAILS *pFmt;
UINT uIndex = IDToIndex(Id);
if(!pFormatPrefsBuf || (uNumLocalFormats <= uIndex))
{
return CAPS_E_INVALID_PARAM;
}
pFmt = pLocalFormats + uIndex;
return (CopyVidcapInfo(pFmt,pFormatPrefsBuf,0));
}
HRESULT CMsivCapability::ApplyAppFormatPrefs (PBASIC_VIDCAP_INFO pFormatPrefsBuf,
UINT uNumFormatPrefs)
{
FX_ENTRY ("CMsivCapability::ApplyAppFormatPrefs");
UINT u, v;
PBASIC_VIDCAP_INFO pTemp;
VIDCAP_DETAILS *pFmt;
if(!pFormatPrefsBuf || (uNumLocalFormats != uNumFormatPrefs))
{
ERRORMESSAGE(("%s invalid param: pFbuf:0x%08lx, uNumIN:%d, uNum:%d\r\n",
_fx_, pFormatPrefsBuf, uNumFormatPrefs, uNumLocalFormats));
return CAPS_E_INVALID_PARAM;
}
// validate
for(u=0; u <uNumLocalFormats; u++)
{
pTemp = pFormatPrefsBuf+u;
// make sure that the format ID is real
if(IDToIndex(pTemp->Id) >= uNumLocalFormats)
{
return CAPS_E_INVALID_PARAM;
}
// look for bad sort indices, duplicate sort indices and duplicate format IDs
if(pTemp->wSortIndex >= uNumLocalFormats)
return CAPS_E_INVALID_PARAM;
for(v=u+1; v <uNumLocalFormats; v++)
{
if((pTemp->wSortIndex == pFormatPrefsBuf[v].wSortIndex)
|| (pTemp->Id == pFormatPrefsBuf[v].Id))
{
ERRORMESSAGE(("%s invalid param: wSI1:0x%04x, wSI2:0x%04x, ID1:%d, ID2:%d\r\n",
_fx_, pTemp->wSortIndex, pFormatPrefsBuf[v].wSortIndex, pTemp->Id,
pFormatPrefsBuf[v].Id));
return CAPS_E_INVALID_PARAM;
}
}
}
// all seems well
for(u=0; u <uNumLocalFormats; u++)
{
pTemp = pFormatPrefsBuf+u; // next entry of the input
pFmt = pLocalFormats + IDToIndex(pTemp->Id); // identifies this local format
// apply the new sort order
pFmt->wApplicationPrefOrder = pTemp->wSortIndex;
// update the updatable parameters (CPU utilization, bitrate)
pFmt->bSendEnabled = pTemp->bSendEnabled;
pFmt->bRecvEnabled = pTemp->bRecvEnabled;
// DO NOT overwrite any of the fields used to construct the regkey name
// pFmt->video_params.uSamplesPerSec = pTemp->uFrameRate;
//Units of 100 bits/sec
pFmt->nonstd_params.maxBitRate= (pTemp->uMaxBitrate/100);
// pFmt->nonstd_params.maxBPP= 0;
pFmt->nonstd_params.MPI= 30/max(pTemp->uFrameRate, 1);
// only the tuning wizard or other profiling app can write wCPUUtilizationEncode,
// wCPUUtilizationDecode, uAvgBitrate
// update the registry
UpdateFormatInRegistry(pFmt);
// now update the sort order contained in VIDsByRank
// note: recall that only MAX_CAPS_PRESORT are sorted and the rest are in random order.
// LOOKLOOK - maybe need a separate sort order array? - the order in VIDsByRank
// is being overriden here
// the array holds the sorted indices into the array of formats in pLocalFormats
if(pTemp->wSortIndex < MAX_CAPS_PRESORT)
{
// insert the format at the position indicated by the input
IDsByRank[pTemp->wSortIndex] = (MEDIA_FORMAT_ID)(pFmt - pLocalFormats);
}
}
return hrSuccess;
}
// update the registry
BOOL CMsivCapability::UpdateFormatInRegistry(VIDCAP_DETAILS *pVidcapDetails)
{
FX_ENTRY(("CMsivCapability::UpdateFormatInRegistry"));
LPTSTR lpszKeyName = NULL;
BOOL bRet;
if(!pVidcapDetails)
{
return FALSE;
}
lpszKeyName = AllocRegistryKeyName( pVidcapDetails->szFormat,
pVidcapDetails->video_params.uSamplesPerSec,
pVidcapDetails->video_params.uBitsPerSample,
pVidcapDetails->uMaxBitrate,
pVidcapDetails->video_params.biWidth,
pVidcapDetails->video_params.biHeight);
if (!lpszKeyName)
{
ERRORMESSAGE(("%s:Alloc failed\r\n",_fx_));
return(FALSE);
}
DEBUGMSG(ZONE_VCM,("%s:updating %s, wPref:0x%04x, bS:%d, bR:%d\r\n",
_fx_, lpszKeyName, pVidcapDetails->wApplicationPrefOrder,
pVidcapDetails->bSendEnabled, pVidcapDetails->bRecvEnabled));
// add this to the registry
RegEntry reVidCaps(szRegInternetPhone TEXT("\\") szRegInternetPhoneVCMEncodings,
HKEY_LOCAL_MACHINE);
bRet = (ERROR_SUCCESS == reVidCaps.SetValue(lpszKeyName,
pVidcapDetails,
sizeof(VIDCAP_DETAILS)));
FreeRegistryKeyName(lpszKeyName);
return(bRet);
}
/***************************************************************************
Name : CMsivCapability::AddVCMFormat
Purpose : Adds an VCM format to the list of formats we support
Parameters: pvfx - pointer to the videoformat structure for the added codec
pVidcapInfo - additional format info that is not in the videoformat
structure
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CMsivCapability::AddVCMFormat (PVIDEOFORMATEX pvfx, PVIDCAP_INFO pVidcapInfo)
{
HRESULT hr = hrSuccess;
// initialize cap entry with default values
VIDCAP_DETAILS cap_entry =
{VIDEO_FORMAT_UNKNOWN, NONSTD_VID_TERMCAP,STD_VID_PARAMS,
{RTP_DYNAMIC_MIN+1, 0, 30, 7680, Small, 0, 0},0,
TRUE, TRUE,
1, // default number of samples per packet
245760*8, // default to 16kbs bitrate
245760*8, // unknown average bitrate
10, 10, // default CPU utilization
PREF_ORDER_UNASSIGNED, // unassigned sort order
0,NULL,0,NULL,
""};
if(!pvfx || !pVidcapInfo)
{
hr = CAPS_E_INVALID_PARAM;
goto out;
}
/*
* Build the VIDCAP_DETAILS structure for this format
*/
// now add VIDCAP_INFO information
CopyVidcapInfo(&cap_entry, pVidcapInfo, 1);
// calculate whatever parameters can be calculated
// use actual bits per sample unless the bps field is zero, in which case
// assume 16 bits (worst case).
CalculateFormatProperties(&cap_entry, pvfx);
// Make sure it's an upper case FourCC
if (cap_entry.dwFormatTag > 256)
CharUpperBuff((LPTSTR)&cap_entry.dwFormatTag, sizeof(DWORD));
// set the RTP payload number. We are using a random number from the dynamic range
// for the installable codecs
cap_entry.video_params.RTPPayload = RTP_DYNAMIC_MIN+1;
// get the format name and driver name for this format from VCM and
// build a format name to add to the registry
hr = GetFormatName(&cap_entry, pvfx);
if (FAILED(hr))
goto out;
// add this to the registry
if(!UpdateFormatInRegistry(&cap_entry))
{
ERRORMESSAGE(("CMsivCapability::AddVCMFormat: can't update registry\r\n"));
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
// reinit to update the list of local formats
if (!ReInit())
{
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
out:
return hr;
}
/***************************************************************************
Name : CMsivCapability::RemoveVCMFormat
Purpose : Removes an VCM format to the list of formats we support
Parameters: pvfx - pointer to the videoformat structure for the added codec
Returns : HRESULT
Comment :
***************************************************************************/
HRESULT CMsivCapability::RemoveVCMFormat (PVIDEOFORMATEX pvfx)
{
HRESULT hr = hrSuccess;
HKEY hKey = NULL;
LPTSTR lpszValueName = NULL;
DWORD dwErr;
VIDCAP_DETAILS cap_entry;
if(!pvfx)
{
return CAPS_E_INVALID_PARAM;
}
// get the format name and driver name for this format from VCM and
// build a format name to add to the registry
hr = GetFormatName(&cap_entry, pvfx);
if (FAILED(hr))
goto out;
lpszValueName = AllocRegistryKeyName(cap_entry.szFormat,
pvfx->nSamplesPerSec,
MAKELONG(pvfx->wBitsPerSample,0),
pvfx->nAvgBytesPerSec*8,
pvfx->bih.biWidth,
pvfx->bih.biHeight);
if (!lpszValueName)
{
ERRORMESSAGE(("CMsivCapability::RemoveVCMFormat: Alloc failed\r\n"));
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
// Get the key handle
if (dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szRegInternetPhone TEXT("\\") szRegInternetPhoneVCMEncodings,
0, KEY_ALL_ACCESS, &hKey))
{
ERRORMESSAGE(("CMsivCapability::RemoveVCMFormat: can't open key to delete\r\n"));
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
dwErr = RegDeleteValue(hKey, lpszValueName );
if(dwErr != ERROR_SUCCESS)
{
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
// reinit to update the list of local formats
if (!ReInit())
{
hr = CAPS_E_SYSTEM_ERROR;
goto out;
}
out:
if (hKey)
RegCloseKey(hKey);
if(lpszValueName)
MEMFREE(lpszValueName);
return hr;
}
UINT CMsivCapability::GetLocalSendParamSize(MEDIA_FORMAT_ID dwID)
{
return (sizeof(VIDEO_CHANNEL_PARAMETERS));
}
UINT CMsivCapability::GetLocalRecvParamSize(PCC_TERMCAP pCapability)
{
return (sizeof(VIDEO_CHANNEL_PARAMETERS));
}
HRESULT CMsivCapability::CreateCapList(LPVOID *ppCapBuf)
{
HRESULT hr = hrSuccess;
UINT u;
VIDCAP_DETAILS *pDecodeDetails = pLocalFormats;
PCC_TERMCAPLIST pTermCapList = NULL;
PPCC_TERMCAP ppCCThisTermCap = NULL;
PCC_TERMCAP pCCThisCap = NULL;
PNSC_VIDEO_CAPABILITY pNSCapNext = NULL;
PVIDEOFORMATEX lpvcd;
VIDEO_PARAMS *pVidCapInfo;
UINT format;
FX_ENTRY ("CreateCapList");
// validate input
if(!ppCapBuf)
{
hr = CAPS_E_INVALID_PARAM;
goto ERROR_OUT;
}
*ppCapBuf = NULL;
if(!uNumLocalFormats || !pDecodeDetails)
{
hr = CAPS_E_NOCAPS;
goto ERROR_OUT;
}
pTermCapList = (PCC_TERMCAPLIST)MemAlloc(sizeof(CC_TERMCAPLIST));
if(!pTermCapList)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
ppCCThisTermCap = (PPCC_TERMCAP)MemAlloc(uNumLocalFormats * sizeof(PCC_TERMCAP));
if(!ppCCThisTermCap)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
pTermCapList->wLength = 0;
// point the CC_TERMCAPLIST pTermCapArray at the array of PCC_TERMCAP
pTermCapList->pTermCapArray = ppCCThisTermCap;
/*
CC_TERMCAPLIST PCC_TERMCAP CC_TERMCAP
pTermCapList-> {
wLength
pTermCapArray--->pTermCap----------->{single capability.....}
}
pTermCap----------->{single capability.}
pTermCap----------->{single capability...}
*/
for(u=0; u <uNumLocalFormats; u++)
{
// check if enabled for receive, skip if false
// also skip if public version of capabilities is to be advertised via a
// separate local capability entry
if((!pDecodeDetails->bRecvEnabled ) || (pDecodeDetails->dwPublicRefIndex))
{
pDecodeDetails++;
continue;
}
if(pDecodeDetails->H245Cap.ClientType ==0
|| pDecodeDetails->H245Cap.ClientType ==H245_CLIENT_VID_NONSTD)
{
lpvcd = (PVIDEOFORMATEX)pDecodeDetails->lpLocalFormatDetails;
if(!lpvcd)
{
pDecodeDetails++;
continue;
}
// allocate for this one capability
pCCThisCap = (PCC_TERMCAP)MemAlloc(sizeof(CC_TERMCAP));
pNSCapNext = (PNSC_VIDEO_CAPABILITY)MemAlloc(sizeof(NSC_VIDEO_CAPABILITY));
if((!pCCThisCap)|| (!pNSCapNext))
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
// set type of nonstandard capability
pNSCapNext->cvp_type = NSC_VCM_VIDEOFORMATEX;
// stuff both chunks of nonstandard capability info into buffer
// first stuff the "channel parameters" (the format independent communication options)
memcpy(&pNSCapNext->cvp_params, &pDecodeDetails->nonstd_params, sizeof(NSC_CHANNEL_VIDEO_PARAMETERS));
// then the VCM stuff
memcpy(&pNSCapNext->cvp_data.vfx, lpvcd, sizeof(VIDEOFORMATEX));
pCCThisCap->ClientType = H245_CLIENT_VID_NONSTD;
pCCThisCap->DataType = H245_DATA_VIDEO;
pCCThisCap->Dir = (pDecodeDetails->bSendEnabled && bPublicizeTXCaps)
? H245_CAPDIR_LCLRXTX :H245_CAPDIR_LCLRX;
// LOOKLOOK use the index of the cap entry as the ID
// The ID is already preset in local formats by AddCapabilityBase()
// pCCThisCap->CapId = (USHORT)IndexToId(u);
pCCThisCap->CapId = pDecodeDetails->H245Cap.CapId;
// all nonstandard identifier fields are unsigned short
// two possibilities for choice are "h221NonStandard_chosen" and "object_chosen"
pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.choice = h221NonStandard_chosen;
// NOTE: there is some question about the correct byte order
// of the codes in the h221NonStandard structure
pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35CountryCode = USA_H221_COUNTRY_CODE;
pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35Extension = USA_H221_COUNTRY_EXTENSION;
pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.manufacturerCode = MICROSOFT_H_221_MFG_CODE;
// set size of buffer
pCCThisCap->Cap.H245Vid_NONSTD.data.length = sizeof(NSC_VIDEO_CAPABILITY) - BMIH_SLOP_BYTES;
pCCThisCap->Cap.H245Vid_NONSTD.data.value = (BYTE *)pNSCapNext; // point to nonstandard stuff
// pNSCapNext is now referenced by the pTermCapList and will
// be cleaned up via DeleteCapList(). Null the ptr so that error cleanup
// won't try redundant cleanup.
pNSCapNext = NULL;
}
else
{
// allocate for this one capability
pCCThisCap = (PCC_TERMCAP)MemAlloc(sizeof(CC_TERMCAP));
if(!pCCThisCap)
{
hr = CAPS_E_NOMEM;
goto ERROR_OUT;
}
pCCThisCap->ClientType = (H245_CLIENT_T)pDecodeDetails->H245Cap.ClientType;
pCCThisCap->DataType = H245_DATA_VIDEO;
pCCThisCap->Dir = H245_CAPDIR_LCLRX; // should this be H245_CAPDIR_LCLRX for receive caps?
pCCThisCap->CapId = pDecodeDetails->H245Cap.CapId;
pVidCapInfo=&pDecodeDetails->video_params;
switch (pCCThisCap->ClientType )
{
case H245_CLIENT_VID_H263:
#pragma message ("Collapse H.263 formats")
// refer to the hack that sets H245Vid_H263 parameters
// when formats are enumerated. if that was always done right, then
// all that needs to happen here is collapsing
// This is where the formats need to collapse. H.263 probably
// should not be collapsed into 1 format. Given M specific local
// formats, collapse into N.
format=get_format (pVidCapInfo->biWidth,pVidCapInfo->biHeight);
switch (format) {
case SQCIF: {
pCCThisCap->Cap.H245Vid_H263.bit_mask =H263VideoCapability_sqcifMPI_present;
//MPI minimum interval in units of 1/29.97sec so 30/ (frames/sec) is reasonable
pCCThisCap->Cap.H245Vid_H263.sqcifMPI = max (1,pDecodeDetails->nonstd_params.MPI); //30/pVidCapInfo->uSamplesPerSec;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_qcifMPI =0;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_cifMPI =0;
break;
}
case QCIF: {
pCCThisCap->Cap.H245Vid_H263.bit_mask =H263VideoCapability_qcifMPI_present;
pCCThisCap->Cap.H245Vid_H263.sqcifMPI = 0;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_qcifMPI =max (1,pDecodeDetails->nonstd_params.MPI);//30/pVidCapInfo->uSamplesPerSec; ;;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_cifMPI =0;
break;
}
case CIF: {
pCCThisCap->Cap.H245Vid_H263.bit_mask =H263VideoCapability_cifMPI_present;
pCCThisCap->Cap.H245Vid_H263.sqcifMPI = 0;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_qcifMPI =0;
pCCThisCap->Cap.H245Vid_H263.H263VdCpblty_cifMPI = max (1,pDecodeDetails->nonstd_params.MPI);//30/pVidCapInfo->uSamplesPerSec;
break;
}
default:
break;
}
pCCThisCap->Cap.H245Vid_H263.cif4MPI =0;
pCCThisCap->Cap.H245Vid_H263.cif16MPI =0;
pCCThisCap->Cap.H245Vid_H263.maxBitRate =
pDecodeDetails->nonstd_params.maxBitRate;
pCCThisCap->Cap.H245Vid_H263.unrestrictedVector = FALSE;
pCCThisCap->Cap.H245Vid_H263.arithmeticCoding = FALSE;
pCCThisCap->Cap.H245Vid_H263.advancedPrediction = FALSE;
pCCThisCap->Cap.H245Vid_H263.pbFrames = FALSE;
pCCThisCap->Cap.H245Vid_H263.tmprlSptlTrdOffCpblty = (ASN1bool_t)bPublicizeTSTradeoff;
pCCThisCap->Cap.H245Vid_H263.hrd_B = 0;
pCCThisCap->Cap.H245Vid_H263.bppMaxKb =
pDecodeDetails->nonstd_params.maxBPP;
/* Optional, and not supported pCCThisCap->Cap.H245Vid_H263.slowQcifMPI =0;
pCCThisCap->Cap.H245Vid_H263.slowSqcifMPI =0;
pCCThisCap->Cap.H245Vid_H263.slowCifMPI =0;
pCCThisCap->Cap.H245Vid_H263.slowCif4MPI =0;
pCCThisCap->Cap.H245Vid_H263.slowCif16MPI =0;
*/
pCCThisCap->Cap.H245Vid_H263.H263VCy_errrCmpnstn = TRUE;
break;
case H245_CLIENT_VID_H261:
#pragma message ("Collapse H.261 formats")
// refer to the hack that sets H245Vid_H261 parameters
// when formats are enumerated. if that was always done right, then
// all that needs to happen here is collapsing
// This is where the formats need to collapse. H.261 probably
// should not be collapsed into 1 format. Given M specific local
// formats, collapse into N.
format=get_format (pVidCapInfo->biWidth,pVidCapInfo->biHeight);
switch (format) {
case QCIF: {
pCCThisCap->Cap.H245Vid_H261.bit_mask =H261VdCpblty_qcifMPI_present;
pCCThisCap->Cap.H245Vid_H261.H261VdCpblty_qcifMPI =max (1,min(4,pDecodeDetails->nonstd_params.MPI));//30/pVidCapInfo->uSamplesPerSec; ;;
pCCThisCap->Cap.H245Vid_H261.H261VdCpblty_cifMPI =0;
break;
}
case CIF: {
pCCThisCap->Cap.H245Vid_H261.bit_mask =H261VdCpblty_cifMPI_present;
pCCThisCap->Cap.H245Vid_H261.H261VdCpblty_qcifMPI =0;
pCCThisCap->Cap.H245Vid_H261.H261VdCpblty_cifMPI =max (1,min(4,pDecodeDetails->nonstd_params.MPI));//30/pVidCapInfo->uSamplesPerSec;
break;
}
default:
break;
}
pCCThisCap->Cap.H245Vid_H261.maxBitRate = (ASN1uint16_t)pDecodeDetails->nonstd_params.maxBitRate;
pCCThisCap->Cap.H245Vid_H261.tmprlSptlTrdOffCpblty = (ASN1bool_t)bPublicizeTSTradeoff;
pCCThisCap->Cap.H245Vid_H261.stillImageTransmission = FALSE;
break;
default:
case H245_CLIENT_VID_NONSTD:
break;
}
}
pDecodeDetails++;
*ppCCThisTermCap++ = pCCThisCap;// add ptr to this capability to the array
pTermCapList->wLength++; // count this entry
// pCCThisCap is now referenced by the pTermCapList and will
// be cleaned up via DeleteCapList(). Null the ptr so that error cleanup
// won't try redundant cleanup.
pCCThisCap = NULL;
}
*ppCapBuf = pTermCapList;
return hr;
ERROR_OUT:
if(pTermCapList)
{
DeleteCapList(pTermCapList);
}
if(pCCThisCap)
MemFree(pCCThisCap);
if(pNSCapNext)
MemFree(pNSCapNext);
return hr;
}
HRESULT CMsivCapability::DeleteCapList(LPVOID pCapBuf)
{
UINT u;
PCC_TERMCAPLIST pTermCapList = (PCC_TERMCAPLIST)pCapBuf;
PCC_TERMCAP pCCThisCap;
PNSC_VIDEO_CAPABILITY pNSCap;
if(!pTermCapList)
{
return CAPS_E_INVALID_PARAM;
}
if(pTermCapList->pTermCapArray)
{
while(pTermCapList->wLength--)
{
pCCThisCap = *(pTermCapList->pTermCapArray + pTermCapList->wLength);
if(pCCThisCap)
{
if(pCCThisCap->ClientType == H245_CLIENT_VID_NONSTD)
{
if(pCCThisCap->Cap.H245Vid_NONSTD.data.value)
{
MemFree(pCCThisCap->Cap.H245Vid_NONSTD.data.value);
}
}
MemFree(pCCThisCap);
}
}
MemFree(pTermCapList->pTermCapArray);
}
MemFree(pTermCapList);
return hrSuccess;
}
BOOL CMsivCapability::IsCapabilityRecognized(PCC_TERMCAP pCCThisCap)
{
FX_ENTRY ("CMsivCapability::IsCapabilityRecognized");
if(pCCThisCap->DataType != H245_DATA_VIDEO)
return FALSE;
if(pCCThisCap->ClientType == H245_CLIENT_VID_NONSTD)
{
// do we recognize this?
if(pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.choice == h221NonStandard_chosen)
{
if((pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35CountryCode == USA_H221_COUNTRY_CODE)
&& (pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35Extension == USA_H221_COUNTRY_EXTENSION)
&& (pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.manufacturerCode == MICROSOFT_H_221_MFG_CODE))
{
// ok, this is ours so far. Now what data type is contained therein?
// welllll, lets keep a copy of this regardless ????. If we can't understand
// future versions of ourselves, then what???
return TRUE;
}
else
{
// unrecognized nonstandard capability
ERRORMESSAGE(("%s:unrecognized nonstd capability\r\n",_fx_));
#ifdef DEBUG
VOID DumpNonstdParameters(PCC_TERMCAP , PCC_TERMCAP );
DumpNonstdParameters(NULL, pCCThisCap);
#endif
return FALSE;
}
}
}
return TRUE;
}
// the intent is to keep a copy of the channel parameters used to open a send channel
// that the remote end can decode.
VIDEO_FORMAT_ID CMsivCapability::AddRemoteDecodeFormat(PCC_TERMCAP pCCThisCap)
{
FX_ENTRY ("CMsivCapability::AddRemoteDecodeFormat");
VIDCAP_DETAILS vidcapdetails =
{VIDEO_FORMAT_UNKNOWN,NONSTD_VID_TERMCAP, STD_VID_PARAMS,
{RTP_DYNAMIC_MIN+1, 0, 30, 7680, Small, 0, 0},0,
TRUE, TRUE, 1, 245760*8,245760*8,10,10,0,0,NULL,0,NULL,""};
VIDCAP_DETAILS *pTemp;
LPVOID lpData = NULL;
UINT uSize = 0;
if(!pCCThisCap)
{
return INVALID_VIDEO_FORMAT;
}
// check room
if(uRemoteDecodeFormatCapacity <= uNumRemoteDecodeFormats)
{
// get more mem, realloc memory by CAP_CHUNK_SIZE for pRemoteDecodeFormats
pTemp = (VIDCAP_DETAILS *)MEMALLOC((uNumRemoteDecodeFormats + CAP_CHUNK_SIZE)*sizeof(VIDCAP_DETAILS));
if(!pTemp)
goto ERROR_EXIT;
// remember how much capacity we now have
uRemoteDecodeFormatCapacity = uNumRemoteDecodeFormats + CAP_CHUNK_SIZE;
#ifdef DEBUG
if((uNumRemoteDecodeFormats && !pRemoteDecodeFormats) || (!uNumRemoteDecodeFormats && pRemoteDecodeFormats))
{
ERRORMESSAGE(("%s:leak! uNumRemoteDecodeFormats:0x%08lX, pRemoteDecodeFormats:0x%08lX\r\n",
_fx_, uNumRemoteDecodeFormats,pRemoteDecodeFormats));
}
#endif
// copy old stuff, discard old mem
if(uNumRemoteDecodeFormats && pRemoteDecodeFormats)
{
memcpy(pTemp, pRemoteDecodeFormats, uNumRemoteDecodeFormats*sizeof(AUDCAP_DETAILS));
MEMFREE(pRemoteDecodeFormats);
}
pRemoteDecodeFormats = pTemp;
}
// pTemp is where the stuff is cached
pTemp = pRemoteDecodeFormats+uNumRemoteDecodeFormats;
// fixup the capability structure being added. First thing: initialize defaults
memcpy(pTemp, &vidcapdetails, sizeof(VIDCAP_DETAILS));
// next, the H245 parameters
memcpy(&pTemp->H245Cap, pCCThisCap, sizeof(pTemp->H245Cap));
// Note: if nonstandard data exists, the nonstd pointers need to be fixed up
if(pCCThisCap->ClientType == H245_CLIENT_VID_NONSTD)
{
// do we recognize this?
if(pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.choice == h221NonStandard_chosen)
{
if((pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35CountryCode == USA_H221_COUNTRY_CODE)
&& (pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.t35Extension == USA_H221_COUNTRY_EXTENSION)
&& (pCCThisCap->Cap.H245Vid_NONSTD.nonStandardIdentifier.u.h221NonStandard.manufacturerCode == MICROSOFT_H_221_MFG_CODE))
{
// ok, this is ours so far. Now what data type is contained therein?
// welllll, lets keep a copy of this regardless ????. If we can't understand
// future versions of ourselves, then what???
uSize = pCCThisCap->Cap.H245Vid_NONSTD.data.length;
lpData = pCCThisCap->Cap.H245Vid_NONSTD.data.value;
}
}
}
// this is not really necessary to set RTP payload type of what is received - it should
// be obvious.
else if (pCCThisCap->ClientType == H245_CLIENT_VID_H263 )
{
pTemp->video_params.RTPPayload = RTP_PAYLOAD_H263;
}
else if(pCCThisCap->ClientType == H245_CLIENT_VID_H261)
{
pTemp->video_params.RTPPayload = RTP_PAYLOAD_H261;
}
pTemp->uLocalDetailsSize = 0; // we're not keeping another copy of local encode details
pTemp->lpLocalFormatDetails =0; // we're not keeping another copy of local encode details
pTemp->uRemoteDetailsSize = 0; // clear this now
if(uSize && lpData)
{
pTemp->H245Cap.Cap.H245Vid_NONSTD.data.length = uSize;
pTemp->H245Cap.Cap.H245Vid_NONSTD.data.value = (unsigned char *)lpData;
pTemp->lpRemoteFormatDetails = MEMALLOC(uSize);
if(pTemp->lpRemoteFormatDetails)
{
memcpy(pTemp->lpRemoteFormatDetails, lpData, uSize);
pTemp->uRemoteDetailsSize = uSize;
}
#ifdef DEBUG
else
{
ERRORMESSAGE(("%s:allocation failed!\r\n",_fx_));
}
#endif
}
else
{
pTemp->lpRemoteFormatDetails = NULL;
pTemp->uRemoteDetailsSize =0;
}
uNumRemoteDecodeFormats++;
// use the index as the ID
return (uNumRemoteDecodeFormats-1);
ERROR_EXIT:
return INVALID_VIDEO_FORMAT;
}
VOID CMsivCapability::FlushRemoteCaps()
{
if(pRemoteDecodeFormats)
{
MEMFREE(pRemoteDecodeFormats);
pRemoteDecodeFormats = NULL;
uNumRemoteDecodeFormats = 0;
uRemoteDecodeFormatCapacity = 0;
}
}
HRESULT CMsivCapability::AddRemoteDecodeCaps(PCC_TERMCAPLIST pTermCapList)
{
FX_ENTRY ("CMsivCapability::AddRemoteDecodeCaps");
HRESULT hr = hrSuccess;
PPCC_TERMCAP ppCCThisCap;
PCC_TERMCAP pCCThisCap;
WORD wNumCaps;
//ERRORMESSAGE(("%s,\r\n", _fx_));
if(!pTermCapList) // additional capability descriptors may be added
{ // at any time
return CAPS_E_INVALID_PARAM;
}
// cleanup old term caps if term caps are being addded and old caps exist
FlushRemoteCaps();
wNumCaps = pTermCapList->wLength;
ppCCThisCap = pTermCapList->pTermCapArray;
/*
CC_TERMCAPLIST TERMCAPINFO CC_TERMCAP
pTermCapList-> {
wLength
pTermCapInfo--->pTermCap----------->{single capability.....}
}
pTermCap----------->{single capability.}
pTermCap----------->{single capability...}
*/
while(wNumCaps--)
{
if(!(pCCThisCap = *ppCCThisCap++))
{
ERRORMESSAGE(("%s:null pTermCap, 0x%04x of 0x%04x\r\n",
_fx_, pTermCapList->wLength - wNumCaps, pTermCapList->wLength));
continue;
}
if(!IsCapabilityRecognized(pCCThisCap))
{
continue;
}
AddRemoteDecodeFormat(pCCThisCap);
}
return hr;
}
// Given the ID of a local format, gets the channel parameters that are sent to the
// remote end as part of the capability exchange. This function is not used by the
// capability exchange code (because it sends more than just these parameters).
// However, this is useful information by itself - it can be used for validating the
// parameters of channel open requests against the expected parameters
HRESULT CMsivCapability::GetPublicDecodeParams(LPVOID pBufOut, UINT uBufSize, VIDEO_FORMAT_ID id)
{
UINT uIndex = IDToIndex(id);
// validate input
if(!pBufOut|| (uIndex >= (UINT)uNumLocalFormats))
{
return CAPS_E_INVALID_PARAM;
}
if(uBufSize < sizeof(CC_TERMCAP))
{
return CAPS_E_BUFFER_TOO_SMALL;
}
memcpy(pBufOut, &((pLocalFormats + uIndex)->H245Cap), sizeof(CC_TERMCAP));
return hrSuccess;
}
HRESULT CMsivCapability::SetAudioPacketDuration(UINT uPacketDuration)
{
return CAPS_E_INVALID_PARAM;
}
// Given the IDs of "matching" local and remote formats, gets the preferred channel parameters
// that will be used in requests to open a channel for sending to the remote.
HRESULT CMsivCapability::GetEncodeParams(LPVOID pBufOut, UINT uBufSize,LPVOID pLocalParams, UINT uSizeLocal,
VIDEO_FORMAT_ID idRemote, VIDEO_FORMAT_ID idLocal)
{
UINT uLocalIndex = IDToIndex(idLocal);
VIDCAP_DETAILS *pLocalDetails = pLocalFormats + uLocalIndex;
VIDCAP_DETAILS *pFmtTheirs;
VIDEO_CHANNEL_PARAMETERS local_params;
UINT u;
PCC_TERMCAP pTermCap = (PCC_TERMCAP)pBufOut;
// validate input
// AddCapabilityBase adds to the ID below. Make sure we're checking Video Formats
if(!pBufOut)
{
return CAPS_E_INVALID_PARAM;
}
if(uBufSize < sizeof(CC_TERMCAP))
{
return CAPS_E_BUFFER_TOO_SMALL;
}
if(!pLocalParams|| uSizeLocal < sizeof(VIDEO_CHANNEL_PARAMETERS)
||(uLocalIndex >= (UINT)uNumLocalFormats))
{
return CAPS_E_INVALID_PARAM;
}
pFmtTheirs = pRemoteDecodeFormats; // start at the beginning of the remote formats
for(u=0; u<uNumRemoteDecodeFormats; u++)
{
if(pFmtTheirs->H245Cap.CapId == idRemote)
{
// copy CC_TERMCAP struct. Any data referenced by CC_TERMCAP now has
// two references to it. i.e. pTermCap->extrablah is the same
// location as pFmtTheirs->extrablah
memcpy(pBufOut, &(pFmtTheirs->H245Cap), sizeof(CC_TERMCAP));
break;
}
pFmtTheirs++; // next entry in receiver's caps
}
// check for an unfound format
if(u >= uNumRemoteDecodeFormats)
goto ERROR_EXIT;
// select channel parameters if appropriate. The audio formats that have variable parameters
// are :
#pragma message ("Are H.26? variable parameter formats?")
// H245_CAP_H261 H245Vid_H261;
// H245_CAP_H263 H245Vid_H263;
// and of course all nonstandard formats
// Select parameters based on local capability info
if(pTermCap->ClientType == H245_CLIENT_VID_H263)
{
unsigned short bit_mask;
// select frames per packet based on minimum latency value that is acceptable
#define H263_QCIF 0x4000
#define H263_MAXBP 0x0200
//H263_QCIF | H263_MAXBP;
pTermCap->Cap.H245Vid_H263.bit_mask= H263_MAXBP | pLocalDetails->H245Cap.Cap.H245Vid_H263.bit_mask;
local_params.ns_params.maxBitRate = pTermCap->Cap.H245Vid_H263.maxBitRate
= min (pLocalDetails->nonstd_params.maxBitRate , pFmtTheirs->H245Cap.Cap.H245Vid_H263.maxBitRate);
local_params.ns_params.maxBPP = pTermCap->Cap.H245Vid_H263.bppMaxKb
= min (pLocalDetails->nonstd_params.maxBPP, pFmtTheirs->H245Cap.Cap.H245Vid_H263.bppMaxKb);
// we (the local end) need to know that actual MPI is going to be used!
// like everywhere else in this module, the assumption is that local H.263 capabilities are
// fanned out with one local cap entry per frame size.
// MPI minimum interval in units of 1/29.97sec so take the longest interval
// there is no pretty way to do this
bit_mask = pLocalDetails->H245Cap.Cap.H245Vid_H263.bit_mask;
if(bit_mask & H263VideoCapability_sqcifMPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H263.sqcifMPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H263.sqcifMPI);
}
else if (bit_mask & H263VideoCapability_qcifMPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H263.H263VdCpblty_qcifMPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H263.H263VdCpblty_qcifMPI);
}
else if (bit_mask & H263VideoCapability_cifMPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H263.H263VdCpblty_cifMPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H263.H263VdCpblty_cifMPI);
}
else if (bit_mask & H263VideoCapability_cif4MPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H263.cif4MPI =
max(pLocalDetails->H245Cap.Cap.H245Vid_H263.cif4MPI,
pTermCap->Cap.H245Vid_H263.cif4MPI);
}
else if (bit_mask & H263VideoCapability_cif16MPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H263.cif16MPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H263.cif16MPI);
}
// else // impossible. Doom, as MikeG and JonT would say
}
else if(pTermCap->ClientType == H245_CLIENT_VID_H261)
{
unsigned short bit_mask;
// select frames per packet based on minimum latency value that is acceptable
pTermCap->Cap.H245Vid_H261.bit_mask= pLocalDetails->H245Cap.Cap.H245Vid_H261.bit_mask;
local_params.ns_params.maxBitRate = pTermCap->Cap.H245Vid_H261.maxBitRate
= min (pLocalDetails->nonstd_params.maxBitRate , pFmtTheirs->H245Cap.Cap.H245Vid_H261.maxBitRate);
// we (the local end) need to know that actual MPI is going to be used!
// like everywhere else in this module, the assumption is that local H.261 capabilities are
// fanned out with one local cap entry per frame size.
// MPI minimum interval in units of 1/29.97sec so take the longest interval
// there is no pretty way to do this
bit_mask = pLocalDetails->H245Cap.Cap.H245Vid_H261.bit_mask;
if (bit_mask & H261VdCpblty_qcifMPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H261.H261VdCpblty_qcifMPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H261.H261VdCpblty_qcifMPI);
}
else if (bit_mask & H261VdCpblty_cifMPI_present)
{
local_params.ns_params.MPI = pTermCap->Cap.H245Vid_H261.H261VdCpblty_cifMPI =
max(pLocalDetails->nonstd_params.MPI,
pTermCap->Cap.H245Vid_H261.H261VdCpblty_cifMPI);
}
// else // impossible. Doom, as MikeG and JonT would say
}
else if (pTermCap->ClientType == H245_CLIENT_VID_NONSTD)
{
// NOT YET IMPLEMENTED!!!!. even the nonstandard parameters need to be fixed
// up here based on mutual maxes and mins
memcpy(&local_params.ns_params, &pLocalDetails->nonstd_params,
sizeof(NSC_CHANNEL_VIDEO_PARAMETERS));
}
local_params.RTP_Payload = pLocalDetails->video_params.RTPPayload;
//Fixup local
memcpy(pLocalParams, &local_params, sizeof(VIDEO_CHANNEL_PARAMETERS));
return hrSuccess;
ERROR_EXIT:
return CAPS_E_INVALID_PARAM;
}
BOOL NonStandardCapsCompareV(VIDCAP_DETAILS *pFmtMine, PNSC_VIDEO_CAPABILITY pCap2,
UINT uSize2)
{
PVIDEOFORMATEX lpvcd;
if(!pFmtMine || !pCap2)
return FALSE;
if(!(lpvcd = (PVIDEOFORMATEX)pFmtMine->lpLocalFormatDetails))
return FALSE;
if(pCap2->cvp_type == NSC_VCM_VIDEOFORMATEX)
{
// check sizes first
if(lpvcd->bih.biSize != pCap2->cvp_data.vfx.bih.biSize)
{
return FALSE;
}
// compare structures, including extra bytes
if(memcmp(lpvcd, &pCap2->cvp_data.vfx,
sizeof(VIDEOFORMATEX) - BMIH_SLOP_BYTES)==0)
{
return TRUE;
}
}
else if(pCap2->cvp_type == NSC_VCMABBREV)
{
if((LOWORD(pCap2->cvp_data.vcm_brief.dwFormatTag) == lpvcd->dwFormatTag)
&& (pCap2->cvp_data.vcm_brief.dwSamplesPerSec == lpvcd->nSamplesPerSec)
&& (LOWORD(pCap2->cvp_data.vcm_brief.dwBitsPerSample) == lpvcd->wBitsPerSample))
{
return TRUE;
}
}
return FALSE;
}
BOOL HasNonStandardCapsTS(VIDCAP_DETAILS *pFmtMine, PNSC_VIDEO_CAPABILITY pCap2)
{
PVIDEOFORMATEX lpvcd;
if(!pFmtMine || !pCap2)
return FALSE;
if(!(lpvcd = (PVIDEOFORMATEX)pFmtMine->lpLocalFormatDetails))
return FALSE;
if(pCap2->cvp_type == NSC_VCM_VIDEOFORMATEX)
if(lpvcd->dwSupportTSTradeOff && pCap2->cvp_data.vfx.dwSupportTSTradeOff)
return TRUE;
return FALSE;
}
HRESULT CMsivCapability::ResolveToLocalFormat(MEDIA_FORMAT_ID FormatIDLocal,
MEDIA_FORMAT_ID * pFormatIDRemote)
{
VIDCAP_DETAILS *pFmtLocal;
VIDCAP_DETAILS *pFmtRemote;
UINT format_mask;
UINT uIndex = IDToIndex(FormatIDLocal);
UINT i;
if(!pFormatIDRemote || (FormatIDLocal == INVALID_MEDIA_FORMAT)
|| (uIndex >= (UINT)uNumLocalFormats))
{
return CAPS_E_INVALID_PARAM;
}
pFmtLocal = pLocalFormats + uIndex;
pFmtRemote = pRemoteDecodeFormats; // start at the beginning of the remote formats
for(i=0; i<uNumRemoteDecodeFormats; i++)
{
if(!pFmtLocal->bSendEnabled)
continue;
// compare capabilities - start by comparing the format tag. a.k.a. "ClientType" in H.245 land
if(pFmtLocal->H245Cap.ClientType == pFmtRemote->H245Cap.ClientType)
{
// if this is a nonstandard cap, compare nonstandard parameters
if(pFmtLocal->H245Cap.ClientType == H245_CLIENT_VID_NONSTD)
{
if(NonStandardCapsCompareV(pFmtLocal,
(PNSC_VIDEO_CAPABILITY)pFmtRemote->H245Cap.Cap.H245Vid_NONSTD.data.value,
pFmtRemote->H245Cap.Cap.H245Vid_NONSTD.data.length))
{
goto RESOLVED_EXIT;
}
}
else // compare standard parameters, if any
{
// well, so far, there aren't any parameters that are significant enough
// to affect the match/no match decision
if (pFmtLocal->H245Cap.ClientType == H245_CLIENT_VID_H263)
{
format_mask= H263VideoCapability_sqcifMPI_present
| H263VideoCapability_qcifMPI_present | H263VideoCapability_cifMPI_present
| H263VideoCapability_cif4MPI_present | H263VideoCapability_cif16MPI_present;
if ((pFmtRemote->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask) & (pFmtLocal->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask))
{
// compatible basic format
goto RESOLVED_EXIT;
}
}
else if (pFmtLocal->H245Cap.ClientType == H245_CLIENT_VID_H261)
{
format_mask= H261VdCpblty_qcifMPI_present | H261VdCpblty_cifMPI_present;
if ((pFmtRemote->H245Cap.Cap.H245Vid_H261.bit_mask & format_mask) & (pFmtLocal->H245Cap.Cap.H245Vid_H261.bit_mask & format_mask))
{
// compatible basic format
goto RESOLVED_EXIT;
}
}
else
{
//Some other standard format
goto RESOLVED_EXIT;
}
}
}
pFmtRemote++; // next entry in remote caps
}
return CAPS_E_NOMATCH;
RESOLVED_EXIT:
// Match!
// return ID of remote decoding (receive fmt) caps that match our
// send caps
*pFormatIDRemote = pFmtRemote->H245Cap.CapId;
return hrSuccess;
}
// resolve using currently cached local and remote formats
HRESULT CMsivCapability::ResolveEncodeFormat(
VIDEO_FORMAT_ID *pIDEncodeOut,
VIDEO_FORMAT_ID *pIDRemoteDecode)
{
UINT i,j=0,format_mask;
VIDCAP_DETAILS *pFmtMine = pLocalFormats;
VIDCAP_DETAILS *pFmtTheirs;
if(!pIDEncodeOut || !pIDRemoteDecode)
{
return CAPS_E_INVALID_PARAM;
}
if(!uNumLocalFormats || !pLocalFormats)
{
*pIDEncodeOut = *pIDRemoteDecode = INVALID_VIDEO_FORMAT;
return CAPS_E_NOCAPS;
}
if(!pRemoteDecodeFormats || !uNumRemoteDecodeFormats)
{
*pIDEncodeOut = *pIDRemoteDecode = INVALID_VIDEO_FORMAT;
return CAPS_E_NOMATCH;
}
// decide how to encode. my caps are ordered by my preference according to
// the contents of IDsByRank[]
//If given a salt, find the position and add it
if (*pIDEncodeOut != INVALID_MEDIA_FORMAT)
{
UINT uIndex = IDToIndex(*pIDEncodeOut);
if (uIndex > uNumLocalFormats)
{
return CAPS_W_NO_MORE_FORMATS;
}
for(i=0; i<uNumLocalFormats; i++)
{
if (pLocalFormats[IDsByRank[i]].H245Cap.CapId == *pIDEncodeOut)
{
j=i+1;
break;
}
}
}
// start at index j
for(i=j; i<uNumLocalFormats; i++)
{
pFmtMine = pLocalFormats + IDsByRank[i];
// check to see if this format is enabled for encoding
if(!pFmtMine->bSendEnabled)
continue;
pFmtTheirs = pRemoteDecodeFormats; // start at the beginning of the remote formats
for(j=0; j<uNumRemoteDecodeFormats; j++)
{
// compare capabilities - start by comparing the format tag. a.k.a. "ClientType" in H.245 land
if(pFmtMine->H245Cap.ClientType == pFmtTheirs->H245Cap.ClientType)
{
// if this is a nonstandard cap, compare nonstandard parameters
if(pFmtMine->H245Cap.ClientType == H245_CLIENT_VID_NONSTD)
{
if(NonStandardCapsCompareV(pFmtMine,
(PNSC_VIDEO_CAPABILITY)pFmtTheirs->H245Cap.Cap.H245Vid_NONSTD.data.value,
pFmtTheirs->H245Cap.Cap.H245Vid_NONSTD.data.length))
{
goto RESOLVED_EXIT;
}
}
else // compare standard parameters, if any
{
// well, so far, there aren't any parameters that are significant enough
// to affect the match/no match decision
if (pFmtMine->H245Cap.ClientType == H245_CLIENT_VID_H263)
{
format_mask= H263VideoCapability_sqcifMPI_present| H263VideoCapability_qcifMPI_present
|H263VdCpblty_cifMPI_present
|H263VideoCapability_cif4MPI_present
|H263VideoCapability_cif16MPI_present;
if ((pFmtTheirs->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask) & (pFmtMine->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask))
{
// compatible basic format
goto RESOLVED_EXIT;
}
}
else if (pFmtMine->H245Cap.ClientType == H245_CLIENT_VID_H261)
{
format_mask= H261VdCpblty_qcifMPI_present | H261VdCpblty_cifMPI_present;
if ((pFmtTheirs->H245Cap.Cap.H245Vid_H261.bit_mask & format_mask) & (pFmtMine->H245Cap.Cap.H245Vid_H261.bit_mask & format_mask))
{
// compatible basic format
goto RESOLVED_EXIT;
}
} else {
//Some other standard format
goto RESOLVED_EXIT;
}
}
}
pFmtTheirs++; // next entry in receiver's caps
}
}
return CAPS_E_NOMATCH;
RESOLVED_EXIT:
// Match!
// return ID of our encoding (sending fmt) caps that match
*pIDEncodeOut = pFmtMine->H245Cap.CapId;
// return ID of remote decoding (receive fmt) caps that match our
// send caps
*pIDRemoteDecode = pFmtTheirs->H245Cap.CapId;
return hrSuccess;
}
HRESULT CMsivCapability::GetDecodeParams(PCC_RX_CHANNEL_REQUEST_CALLBACK_PARAMS pChannelParams,
VIDEO_FORMAT_ID * pFormatID, LPVOID lpvBuf, UINT uBufSize)
{
UINT i,j=0;
VIDCAP_DETAILS *pFmtMine = pLocalFormats;
VIDCAP_DETAILS *pFmtTheirs = pRemoteDecodeFormats;
VIDEO_CHANNEL_PARAMETERS local_params;
PNSC_CHANNEL_VIDEO_PARAMETERS pNSCap = &local_params.ns_params;
PCC_TERMCAP pCapability;
if(!pChannelParams || !(pCapability = pChannelParams->pChannelCapability) || !pFormatID || !lpvBuf ||
(uBufSize < sizeof(VIDEO_CHANNEL_PARAMETERS)))
{
return CAPS_E_INVALID_PARAM;
}
if(!uNumLocalFormats || !pLocalFormats)
{
return CAPS_E_NOCAPS;
}
local_params.TS_Tradeoff = FALSE; // initialize TS tradeoff
for(i=0; i<uNumLocalFormats; i++)
{
pFmtMine = pLocalFormats + IDsByRank[i];
// compare capabilities - start by comparing the format tag. a.k.a. "ClientType" in H.245 land
if(pFmtMine->H245Cap.ClientType == pCapability->ClientType)
{
// if this is a nonstandard cap, compare nonstandard parameters
if(pFmtMine->H245Cap.ClientType == H245_CLIENT_VID_NONSTD)
{
if(NonStandardCapsCompareV(pFmtMine, (PNSC_VIDEO_CAPABILITY)pCapability->Cap.H245Vid_NONSTD.data.value,
pCapability->Cap.H245Vid_NONSTD.data.length))
{
#pragma message ("someday may need need fixup of nonstd params")
// for now, the remote & local nonstandard params are what we want
// and the remote's version of NSC_CHANNEL_VIDEO_PARAMETERS will
// be copied out
pNSCap = (PNSC_CHANNEL_VIDEO_PARAMETERS)
&((PNSC_VIDEO_CAPABILITY)pCapability->Cap.H245Vid_NONSTD.data.value)->cvp_params;
// Does this format support temporal/spatial tradeoff
if(HasNonStandardCapsTS(pFmtMine, (PNSC_VIDEO_CAPABILITY)pCapability->Cap.H245Vid_NONSTD.data.value))
local_params.TS_Tradeoff = TRUE;
else
local_params.TS_Tradeoff = FALSE;
goto RESOLVED_EXIT;
}
}
else // compare standard parameters, if any
{
switch (pFmtMine->H245Cap.ClientType)
{
unsigned short bit_mask, format_mask, usMyMPI, usTheirMPI;
case H245_CLIENT_VID_H263:
// like everywhere else in this module, the assumption is that
// local H.263 capabilities are fanned out with one local cap entry
// per frame size.
format_mask= H263VideoCapability_sqcifMPI_present
| H263VideoCapability_qcifMPI_present
| H263VideoCapability_cifMPI_present
| H263VideoCapability_cif4MPI_present
| H263VideoCapability_cif16MPI_present;
// bail out if no match or nonexistent frame size
if (!((pCapability->Cap.H245Vid_H263.bit_mask & format_mask) & (pFmtMine->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask)))
continue;
// get the maximum bitrate
local_params.ns_params.maxBitRate = min(pFmtMine->H245Cap.Cap.H245Vid_H263.maxBitRate,
pCapability->Cap.H245Vid_H263.maxBitRate);
local_params.ns_params.maxBPP = min (pFmtMine->H245Cap.Cap.H245Vid_H263.bppMaxKb ,
pCapability->Cap.H245Vid_H263.bppMaxKb);
// FIND THE MAXIMUM MPI!!!!. (minimum frame rate)
// there is no pretty way to do this
bit_mask = pFmtMine->H245Cap.Cap.H245Vid_H263.bit_mask;
if(bit_mask & H263VideoCapability_sqcifMPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H263.sqcifMPI,
pCapability->Cap.H245Vid_H263.sqcifMPI);
}
else if (bit_mask & H263VideoCapability_qcifMPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H263.H263VdCpblty_qcifMPI,
pCapability->Cap.H245Vid_H263.H263VdCpblty_qcifMPI);
}
else if (bit_mask & H263VideoCapability_cifMPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H263.H263VdCpblty_cifMPI,
pCapability->Cap.H245Vid_H263.H263VdCpblty_cifMPI);
}
else if (bit_mask & H263VideoCapability_cif4MPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H263.cif4MPI,
pCapability->Cap.H245Vid_H263.cif4MPI);
}
else if (bit_mask & H263VideoCapability_cif16MPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H263.cif16MPI,
pCapability->Cap.H245Vid_H263.cif16MPI);
}
else // impossible. Doom, as MikeG and JonT would say
continue;
// Fallout (And the format is found!)
// And one more special thing: find out if the other end
// advertised Temporal/Spatial tradeoff in it's send capabilities.
// First try the obvious. Technically, it only makes sense for
// transmit capabilities, but if the channel params have it, then
// the other end must have the capability
if(pCapability->Cap.H245Vid_H263.tmprlSptlTrdOffCpblty)
{
local_params.TS_Tradeoff = TRUE;
}
else
{
// Search for a H.263 SEND capability that has the T/S tradoff set
for(j=0; j<uNumRemoteDecodeFormats; j++)
{
if((pFmtTheirs->H245Cap.ClientType == H245_CLIENT_VID_H263)
// exclude RX capabilities
&& (pFmtTheirs->H245Cap.Dir != H245_CAPDIR_LCLRX)
&& (pFmtTheirs->H245Cap.Dir != H245_CAPDIR_RMTRX))
{
if ((pFmtTheirs->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask) & (pFmtMine->H245Cap.Cap.H245Vid_H263.bit_mask & format_mask))
{
local_params.TS_Tradeoff = TRUE;
break;
}
}
pFmtTheirs++; // next entry in receiver's caps
}
}
goto RESOLVED_EXIT;
break;
case H245_CLIENT_VID_H261:
// like everywhere else in this module, the assumption is that
// local H.261 capabilities are fanned out with one local cap entry
// per frame size.
format_mask= H261VdCpblty_qcifMPI_present |H261VdCpblty_cifMPI_present;
// bail out if no match or nonexistent frame size
if (!((pCapability->Cap.H245Vid_H261.bit_mask & format_mask) & (pFmtMine->H245Cap.Cap.H245Vid_H261.bit_mask & format_mask)))
continue;
// get the maximum bitrate
local_params.ns_params.maxBitRate = min(pFmtMine->H245Cap.Cap.H245Vid_H261.maxBitRate,
pCapability->Cap.H245Vid_H261.maxBitRate);
// FIND THE MAXIMUM MPI!!!!. (minimum frame rate)
// there is no pretty way to do this
bit_mask = pFmtMine->H245Cap.Cap.H245Vid_H261.bit_mask;
if (bit_mask & H261VdCpblty_qcifMPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H261.H261VdCpblty_qcifMPI,
pCapability->Cap.H245Vid_H261.H261VdCpblty_qcifMPI);
}
else if (bit_mask & H261VdCpblty_cifMPI_present)
{
local_params.ns_params.MPI =
max(pFmtMine->H245Cap.Cap.H245Vid_H261.H261VdCpblty_cifMPI,
pCapability->Cap.H245Vid_H261.H261VdCpblty_cifMPI);
}
else // impossible. Doom, as MikeG and JonT would say
continue;
// Fallout (And the format is found!)
// And one more special thing: find out if the other end
// advertised Temporal/Spatial tradeoff in it's send capabilities.
// First try the obvious. Technically, it only makes sense for
// transmit capabilities, but if the channel params have it, then
// the other end must have the capability
if(pCapability->Cap.H245Vid_H261.tmprlSptlTrdOffCpblty)
{
local_params.TS_Tradeoff = TRUE;
}
else
{
// Search for a H.261 SEND capability that has the T/S tradoff set
for(j=0; j<uNumRemoteDecodeFormats; j++)
{
if((pFmtTheirs->H245Cap.ClientType == H245_CLIENT_VID_H261)
// exclude RX capabilities
&& (pFmtTheirs->H245Cap.Dir != H245_CAPDIR_LCLRX)
&& (pFmtTheirs->H245Cap.Dir != H245_CAPDIR_RMTRX))
{
if ((pFmtTheirs->H245Cap.Cap.H245Vid_H261.bit_mask
& format_mask)
& (pFmtMine->H245Cap.Cap.H245Vid_H261.bit_mask
& format_mask))
{
local_params.TS_Tradeoff = TRUE;
break;
}
}
pFmtTheirs++; // next entry in receiver's caps
}
}
goto RESOLVED_EXIT;
break;
default:
goto RESOLVED_EXIT;
break;
}
}// end else compare standard parameters, if any
}// end if(pFmtMine->H245Cap.ClientType == pCapability->ClientType)
}
return CAPS_E_NOMATCH;
RESOLVED_EXIT:
// Match!
// return ID of the decoding caps that match
*pFormatID = pFmtMine->H245Cap.CapId;
local_params.RTP_Payload = pChannelParams->bRTPPayloadType;;
memcpy(lpvBuf, &local_params, sizeof(VIDEO_CHANNEL_PARAMETERS));
return hrSuccess;
}
HRESULT CMsivCapability::SetCapIDBase (UINT uNewBase)
{
uCapIDBase = uNewBase;
UINT u;
for (u=0;u<uNumLocalFormats;u++)
{
pLocalFormats[u].H245Cap.CapId = u + uCapIDBase;
}
return hrSuccess;
}
BOOL CMsivCapability::IsHostForCapID(MEDIA_FORMAT_ID CapID)
{
if((CapID >= uCapIDBase) && ((CapID - uCapIDBase) < uNumLocalFormats))
return TRUE;
else
return FALSE;
}
HRESULT CMsivCapability::IsFormatEnabled (MEDIA_FORMAT_ID FormatID, PBOOL bRecv, PBOOL bSend)
{
UINT uIndex = IDToIndex(FormatID);
// validate input
if(uIndex >= (UINT)uNumLocalFormats)
{
return CAPS_E_INVALID_PARAM;
}
*bSend=((pLocalFormats + uIndex)->bSendEnabled);
*bRecv=((pLocalFormats + uIndex)->bRecvEnabled);
return hrSuccess;
}
BOOL CMsivCapability::IsFormatPublic (MEDIA_FORMAT_ID FormatID)
{
UINT uIndex = IDToIndex(FormatID);
// validate input
if(uIndex >= (UINT)uNumLocalFormats)
return FALSE;
// test if this is format is a duplicate of a public format
if((pLocalFormats + uIndex)->dwPublicRefIndex)
return FALSE; // then we keep this format to ourselves
else
return TRUE;
}
MEDIA_FORMAT_ID CMsivCapability::GetPublicID(MEDIA_FORMAT_ID FormatID)
{
UINT uIndex = IDToIndex(FormatID);
// validate input
if(uIndex >= (UINT)uNumLocalFormats)
return INVALID_MEDIA_FORMAT;
if((pLocalFormats + uIndex)->dwPublicRefIndex)
{
return (pLocalFormats + ((pLocalFormats + uIndex)->dwPublicRefIndex))->H245Cap.CapId;
}
else
{
return FormatID;
}
}
// Returns the Id of the format with the smallest wSortIndex - preferred format.
HRESULT CMsivCapability::GetPreferredFormatId (VIDEO_FORMAT_ID *pId)
{
HRESULT hr = hrSuccess;
VIDCAP_DETAILS *pDetails = pLocalFormats;
UINT u, uIndex;
WORD wSortIndex, wMinSortIndex = SHRT_MAX;
// Validate input param
if (!pId)
return((HRESULT)CAPS_E_INVALID_PARAM);
// Validate state
if(!uNumLocalFormats || !pDetails)
return((HRESULT)CAPS_E_NOCAPS);
// Look for the format with the smallest wSortIndex
for (u = 0; (u < uNumLocalFormats) && (u < MAX_CAPS_PRESORT); u++)
{
pDetails = pLocalFormats + IDsByRank[u];
// Find the sort index.
uIndex = (UINT)(pDetails - pLocalFormats);
for (wSortIndex = 0; (wSortIndex < uNumLocalFormats) && (wSortIndex < MAX_CAPS_PRESORT); wSortIndex++)
{
if (uIndex == IDsByRank[wSortIndex])
break; // Found it
}
if (wSortIndex <= wMinSortIndex)
{
*pId = IndexToId(uIndex);
wMinSortIndex = wSortIndex;
}
}
return(hr);
}