|
|
/*
- INSCODEC.CPP - * Microsoft NetMeeting * Network Access Controller (NAC) DLL * Installable codecs interfaces * * Revision History: * * When Who What * -------- ------------------ --------------------------------------- * 01.29.96 Yoram Yaacovi Created * * Functions: * CInstallCodecs * QueryInterface * AddRef * Release * Initialize * TranslateHr * CInstallAudioCodecs * QueryInterface * AddRef * Release * AddACMFormat * RemoveACMFormat * ReorderFormats * EnumFormats * FreeBuffer * CInstallVideoCodecs * QueryInterface * AddRef * Release * AddVCMFormat * RemoveVCMFormat * ReorderFormats * EnumFormats * FreeBuffer * Public: * Private: * FreeBuffer * External: * CreateInstallCodecs * * * @doc EXTERNAL * * Notes: * @topic Implementation Notes | Below are some implementation notes. * * @devnote To add an audio or video format for use with NetMeeting, first obtain the * appropriate interface by calling the COM CoCreateInstance, providing the desired * interface (IInstallAudioCodecs or IInstallVideoCodecs). Then call the Add>CMFormat * method on this interface to add a format, or Remove?CMFormat to remove one. Use * the EnumFormats method to enumerate the list of formats known to NetMeeting, or * ReorderFormats to make NetMeeting use these formats in a different priority order * (see comment in the ReorderFormats description). * * @devnote When a vendor uses our API to add a codec format for use with NetMeeting, * the information about this format is stored in the registry. Whenever we do * an upgrade install of NetMeeting, we blow away these registry entry, * together with all the standard registry entries. This is required to avoid * incompatibility problems. This means that if a user installed a 3rd party codec, * and then upgraded NetMeeting, he will have to re-add the custom codec. * */
#include <precomp.h>
#include <confreg.h> // for setting NetMeeting to manual codec selection
#include <regentry.h> // for setting NetMeeting to manual codec selection
EXTERN_C int g_cICObjects=0; EXTERN_C HANDLE g_hMutex=NULL; class CInstallCodecs *g_pIC;
/***************************************************************************
CInstallCodecs
***************************************************************************/ /***************************************************************************
IUnknown Methods
***************************************************************************/ HRESULT CInstallCodecs::QueryInterface (REFIID riid, LPVOID *lppNewObj) { HRESULT hr = NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::QueryInterface\n"));
#ifdef DEBUG
// parameter validation
if (IsBadReadPtr(&riid, (UINT) sizeof(IID))) { hr = ResultFromScode(E_INVALIDARG); goto out; }
if (IsBadWritePtr(lppNewObj, sizeof(LPVOID))) { hr = ResultFromScode(E_INVALIDARG); goto out; } #endif // DEBUG
*lppNewObj = 0;
if (riid == IID_IUnknown || riid == IID_IInstallCodecs) *lppNewObj = (IInstallCodecs *) this; else if (riid == IID_IInstallAudioCodecs) *lppNewObj = (IInstallAudioCodecs *) &ifAudio; else if (riid == IID_IInstallVideoCodecs) *lppNewObj = (IInstallVideoCodecs *) &ifVideo; else { hr = E_NOINTERFACE; goto out; } ((IUnknown *)*lppNewObj)->AddRef ();
out: DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::QueryInterface - leave, hr=0x%x\n", hr)); return hr; }
ULONG CInstallCodecs::AddRef (void) { DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::AddRef\n"));
InterlockedIncrement((long *) &m_cRef);
DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::AddRef - leave, m_cRef=%d\n", m_cRef));
return m_cRef; }
ULONG CInstallCodecs::Release (void) { DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::Release\n"));
// if the cRef is already 0 (shouldn't happen), assert, but let it through
ASSERT(m_cRef);
if (InterlockedDecrement((long *) &m_cRef) == 0) { delete this; }
DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::Release - leave, m_cRef=%d\n", m_cRef)); return m_cRef; }
/***************************************************************************
CInstallAudioCodecs
***************************************************************************/ /****************************************************************************
* @doc EXTERNAL COMPFUNC AUDIO * * @interface IInstallAudioCodecs | This interface provides methods for * adding audio codec formats for use with NetMeeting, as well as * removing these formats, enumerating them, and change their use order. * ***************************************************************************/ /***************************************************************************
IUnknown Methods
Calling the containing object respective methods
***************************************************************************/ /****************************************************************************
* * @method HRESULT | IInstallAudioCodecs | QueryInterface | QueryInterface * ***************************************************************************/ HRESULT CInstallAudioCodecs::QueryInterface (REFIID riid, LPVOID *lppNewObj) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::QueryInterface\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::QueryInterface - leave\n")); return (This->QueryInterface(riid, lppNewObj));
}
/****************************************************************************
* * @method ULONG | IInstallAudioCodecs | AddRef | AddRef * ***************************************************************************/ ULONG CInstallAudioCodecs::AddRef (void) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::AddRef\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::AddRef - leave\n")); return (This->AddRef()); }
/****************************************************************************
* * @method ULONG | IInstallAudioCodecs | Release | Release * ***************************************************************************/ ULONG CInstallAudioCodecs::Release (void) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::Release\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::Release - leave\n")); return (This->Release()); }
/****************************************************************************
* * AddACMFormat * * @method HRESULT | IInstallAudioCodecs | AddACMFormat | Adds an ACM encoding * format for use with NetMeeting * * @parm LPWAVEFORMATEX | lpwfx | Pointer to the WAVEFORMATEX structure of the * format to add * * @parm PAUDCAP_INFO | pAudCapInfo | Additional format info that is not in the * WAVEFORMATEX structure * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_NO_SUCH_FORMAT | The specified WAVEFORMATEX was not found with ACM. * The format must be installed with ACM before it can be added for use * with NetMeeting. * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * ***************************************************************************/ HRESULT CInstallAudioCodecs::AddACMFormat(LPWAVEFORMATEX lpwfx, PAUDCAP_INFO pAudCapInfo) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::AddACMFormat\n"));
/*
* Parameter validation */
// parameters
if (!lpwfx || !pAudCapInfo || IsBadReadPtr(lpwfx, (UINT) sizeof(WAVEFORMATEX)) || IsBadReadPtr(pAudCapInfo, (UINT) sizeof(AUDCAP_INFO))) { hr = E_INVALIDARG; goto out; }
// NAC doesn't like a nBlockAlign of 0
if (lpwfx->nBlockAlign == 0) { hr = E_INVALIDARG; goto out; }
// the format tags in the WAVEFORMAT and the AUDCAP_INFO should match
if (lpwfx->wFormatTag != pAudCapInfo->wFormatTag) { hr = E_INVALIDARG; goto out; }
// only supporting formats with one audio channel
if (lpwfx->nChannels != 1) { hr = E_INVALIDARG; goto out; } /*
* Add the format */
// add
hr = This->m_pAudAppCaps->AddACMFormat(lpwfx, pAudCapInfo);
out: if (FAILED(hr)) { ERRORMSG(("CInstallAudioCodecs::AddACMFormat failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::AddACMFormat - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * RemoveACMFormat * * @method HRESULT | IInstallAudioCodecs | RemoveACMFormat | Removes an ACM * format from the list of formats used by NetMeeting * * @parm LPWAVEFORMATEX | lpwfx | Pointer to the WAVEFORMATEX structure for the * format to remove * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (0x7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_NO_SUCH_FORMAT | The specified format was not found. * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * ***************************************************************************/ HRESULT CInstallAudioCodecs::RemoveACMFormat(LPWAVEFORMATEX lpwfx) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::RemoveACMFormat\n"));
/*
* Parameter validation */
if (!lpwfx || IsBadReadPtr(lpwfx, (UINT) sizeof(WAVEFORMATEX))) { hr = E_INVALIDARG; goto out; }
// NAC doesn't like a nBlockAlign of 0
if (lpwfx->nBlockAlign == 0) { hr = E_INVALIDARG; goto out; }
// only supporting formats with one audio channel
if (lpwfx->nChannels != 1) { hr = E_INVALIDARG; goto out; } hr = This->m_pAudAppCaps->RemoveACMFormat(lpwfx);
out: if (FAILED(hr)) { ERRORMSG(("CInstallAudioCodecs::RemoveACMFormat failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::RemoveACMFormat - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * ReorderFormats * * @method HRESULT | IInstallAudioCodecs | ReorderFormats | Reorders the audio * formats for use with Netmeeting * * @parm PAUDCAP_INFO_LIST | pAudCapInfoList | Pointer to a structure with a count * and a pointer to a list of the formats to reorder. The list is of the * format AUDCAP_INFO_LIST. * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * * @comm Since ReorderFormats can only reorder formats that are known to NetMeeting, * it is recommended that the caller will first call EnumFormats, to get the * of all formats known to NetMeeting, assign new sort indices (wSortIndex), * and then call ReorderFormats with the modified list. * * @comm Arranging the formats in a specific order, by using ReorderFormats, does * not guarantee that the top ranked formats will be used before lower ranked * formats are used. For example, if the sending system is not capable of * encoding a top ranked format, this format will not be used. The same * will happen if the receiving system cannot decode this format. * ***************************************************************************/ HRESULT CInstallAudioCodecs::ReorderFormats(PAUDCAP_INFO_LIST pAudCapInfoList) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER ); HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::ReorderFormats\n"));
/*
* Parameter validation */
if (!pAudCapInfoList || IsBadReadPtr(pAudCapInfoList, sizeof(DWORD)) || IsBadReadPtr(pAudCapInfoList, sizeof(AUDCAP_INFO_LIST) + ((pAudCapInfoList->cFormats-1) * sizeof(AUDCAP_INFO)))) { hr = E_INVALIDARG; goto out; }
// fill in the format buffer here
hr = This->m_pAudAppCaps->ApplyAppFormatPrefs(pAudCapInfoList->aFormats, pAudCapInfoList->cFormats);
if (FAILED(hr)) goto out;
/*
* switch NetMeeting to manual mode */
// set the registry. failing here won't fail ReorderFormats
re.SetValue(REGVAL_CODECCHOICE, CODECCHOICE_MANUAL);
out: if (FAILED(hr)) { ERRORMSG(("CInstallAudioCodecs::ReorderFormats failed, hr=0x%x\n", hr)); } DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::ReorderFormats - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * EnumFormats * * @method HRESULT | IInstallAudioCodecs | EnumFormats | Enumerates the audio * codec formats known to NetMeeting * * @parm PAUDCAP_INFO_LIST * | ppAudCapInfoList | Address where this method * will put a pointer to a AUDCAP_INFO_LIST list, where enumerated formats * are listed. * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag E_OUTOFMEMORY | Not enough memory for allocating the enumeration buffer * @flag IC_E_NO_FORMATS | No formats were available to enumerate * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * * @comm The caller is expected to free the returned list, by calling FreeBuffer * on the same interface. * ***************************************************************************/ HRESULT CInstallAudioCodecs::EnumFormats(PAUDCAP_INFO_LIST *ppAudCapInfoList) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
ULONG cFormats = 0; UINT uBufSize = 0; HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::EnumFormats\n"));
/*
* Parameter validation */
if (!ppAudCapInfoList || IsBadWritePtr(ppAudCapInfoList, sizeof(PAUDCAP_INFO_LIST))) { hr = E_INVALIDARG; goto out; }
// nothing yet....
*ppAudCapInfoList = NULL;
// are there any formats ?
if (HR_FAILED(This->m_pAudAppCaps->GetNumFormats((UINT *) &cFormats)) || (cFormats == 0)) { hr = IC_E_NO_FORMATS; goto out; }
// allocate a buffer for the call. the caller is expected to call
// FreeBuffer to free
// AUDCAP_INFO_LIST already includes one AUDCAP_INFO
uBufSize = sizeof(AUDCAP_INFO_LIST) + (cFormats-1) * sizeof(AUDCAP_INFO); *ppAudCapInfoList = (PAUDCAP_INFO_LIST) MEMALLOC (uBufSize); if (!(*ppAudCapInfoList)) { hr = E_OUTOFMEMORY; goto out; } hr = This->m_pAudAppCaps->EnumFormats((*ppAudCapInfoList)->aFormats, uBufSize, (UINT *) &((*ppAudCapInfoList)->cFormats));
out: if (FAILED(hr)) { ERRORMSG(("CInstallAudioCodecs::EnumFormats failed, hr=0x%x\n", hr)); } DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::EnumFormats - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * FreeBuffer * * @method HRESULT | IInstallAudioCodecs | FreeBuffer | Free a buffer that was * returned by the IInstallAudioCodec interface * * @parm LPVOID | lpBuffer | Address of the buffer to free. This buffer must have * been allocated by one of the IInstallAudioCodecs methods * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * None * ***************************************************************************/ HRESULT CInstallAudioCodecs::FreeBuffer(LPVOID lpBuffer) { CInstallCodecs *This=IMPL(CInstallCodecs, ifAudio, this); // the containing object
HRESULT hr = NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::FreeBuffer\n"));
hr = This->FreeBuffer(lpBuffer);
if (FAILED(hr)) { ERRORMSG(("CInstallAudioCodecs::FreeBuffer failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallAudioCodecs::FreeBuffer - leave, hr=0x%x\n", hr)); return This->TranslateHr(hr); }
/***************************************************************************
CInstallVideoCodecs
***************************************************************************/ /****************************************************************************
* @doc EXTERNAL COMPFUNC VIDEO ***************************************************************************/ /***************************************************************************
IUnknown Methods
Calling the containing object respective methods
***************************************************************************/ /****************************************************************************
* * @method HRESULT | IInstallVideoCodecs | QueryInterface | QueryInterface * ***************************************************************************/ HRESULT CInstallVideoCodecs::QueryInterface (REFIID riid, LPVOID *lppNewObj) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::QueryInterface\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::QueryInterface - leave\n")); return (This->QueryInterface(riid, lppNewObj));
}
/****************************************************************************
* * @method ULONG | IInstallVideoCodecs | AddRef | AddRef * ***************************************************************************/ ULONG CInstallVideoCodecs::AddRef (void) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddRef\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddRef - leave\n")); return (This->AddRef()); }
/****************************************************************************
* * @method ULONG | IInstallVideoCodecs | Release | Release * ***************************************************************************/ ULONG CInstallVideoCodecs::Release (void) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::Release\n"));
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::Release - leave\n")); return (This->Release()); }
/****************************************************************************
* * AddVCMFormat * * @method HRESULT | IInstallVideoCodecs | AddVCMFormat | Adds an video encoding * format for use with NetMeeting * * @parm PAUDCAP_INFO | pVidCapInfo | Information on the format to add * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_NO_SUCH_FORMAT | The specified format was not found. The format * must be installed with Video For Windows before it can be added for use * with NetMeeting. * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * ***************************************************************************/ HRESULT CInstallVideoCodecs::AddVCMFormat(PVIDCAP_INFO pVidCapInfo) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddVCMFormat\n"));
/*
* Add the format */
hr = AddRemoveVCMFormat(pVidCapInfo, TRUE);
if (FAILED(hr)) { ERRORMSG(("CInstallVideoCodecs::AddVCMFormat failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddVCMFormat - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * RemoveVCMFormat * * @method HRESULT | IInstallVideoCodecs | RemoveVCMFormat | Removes an video * format from the list of formats used by NetMeeting * * @parm PVIDCAP_INFO | pVidCapInfo | Pointer to the PVIDCAP_INFO structure * describing the format to remove * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (0x7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_NO_SUCH_FORMAT | The specified format was not found. * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * ***************************************************************************/ HRESULT CInstallVideoCodecs::RemoveVCMFormat(PVIDCAP_INFO pVidCapInfo) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::RemoveVCMFormat\n"));
/*
* Remove the format */
hr = AddRemoveVCMFormat(pVidCapInfo, FALSE);
if (FAILED(hr)) { ERRORMSG(("CInstallVideoCodecs::RemoveVCMFormat failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::RemoveVCMFormat - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * ReorderFormats * * @method HRESULT | IInstallVideoCodecs | ReorderFormats | Reorders the video * formats for use with Netmeeting * * @parm PVIDCAP_INFO_LIST | pVidCapInfoList | Pointer to a structure with a count * and a pointer to a list of the formats to reorder. The list is of the * format VIDCAP_INFO_LIST. * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * * @comm Since ReorderFormats can only reorder formats that are known to NetMeeting, * it is recommended that the caller will first call EnumFormats, to get the * of all formats known to NetMeeting, assign new sort indices (wSortIndex), * and then call ReorderFormats with the modified list. * * @comm Arranging the formats in a specific order, by using ReorderFormats, does * not guarantee that the top ranked formats will be used before lower ranked * formats are used. For example, if the sending system is not capable of * encoding a top ranked format, this format will not be used. The same * will happen if the receiving system cannot decode this format. * ***************************************************************************/ HRESULT CInstallVideoCodecs::ReorderFormats(PVIDCAP_INFO_LIST pVidCapInfoList) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::ReorderFormats\n"));
/*
* Parameter validation */
if (!pVidCapInfoList || IsBadReadPtr(pVidCapInfoList, sizeof(DWORD)) || IsBadReadPtr(pVidCapInfoList, sizeof(VIDCAP_INFO_LIST) + ((pVidCapInfoList->cFormats-1) * sizeof(VIDCAP_INFO)))) { hr = E_INVALIDARG; goto out; }
hr = This->m_pVidAppCaps->ApplyAppFormatPrefs(pVidCapInfoList->aFormats, pVidCapInfoList->cFormats);
out: if (FAILED(hr)) { ERRORMSG(("CInstallVideoCodecs::ReorderFormats failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::ReorderFormats - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * EnumFormats * * @method HRESULT | IInstallVideoCodecs | EnumFormats | Enumerates the video * codec formats known to NetMeeting * * @parm PVIDCAP_INFO_LIST * | ppVidCapInfoList | Address where this method * will put a pointer to a VIDCAP_INFO_LIST list, where enumerated formats * are listed. * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag E_OUTOFMEMORY | Not enough memory for allocating the enumeration buffer * @flag IC_E_NO_FORMATS | No formats were available to enumerate * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * * @comm The caller is expected to free the returned list, by calling FreeBuffer * on the same interface. * ***************************************************************************/ HRESULT CInstallVideoCodecs::EnumFormats(PVIDCAP_INFO_LIST *ppVidCapInfoList) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
ULONG cFormats = 0; UINT uBufSize = 0; HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::EnumFormats\n"));
/*
* Parameter validation */
if (!ppVidCapInfoList || IsBadWritePtr(ppVidCapInfoList, sizeof(PVIDCAP_INFO_LIST))) { hr = E_INVALIDARG; goto out; }
// nothing yet....
*ppVidCapInfoList = NULL;
// are there any formats ?
if (HR_FAILED(This->m_pVidAppCaps->GetNumFormats((UINT *) &cFormats)) || (cFormats == 0)) { hr = IC_E_NO_FORMATS; goto out; }
// allocate a buffer for the call. the caller is expected to call
// FreeBuffer to free
// VIDCAP_INFO_LIST already includes one VIDCAP_INFO
uBufSize = sizeof(VIDCAP_INFO_LIST) + (cFormats-1) * sizeof(VIDCAP_INFO); *ppVidCapInfoList = (PVIDCAP_INFO_LIST) MEMALLOC (uBufSize); if (!(*ppVidCapInfoList)) { hr = E_OUTOFMEMORY; goto out; } hr = This->m_pVidAppCaps->EnumFormats((*ppVidCapInfoList)->aFormats, uBufSize, (UINT *) &((*ppVidCapInfoList)->cFormats));
out: if (FAILED(hr)) { ERRORMSG(("CInstallVideoCodecs::EnumFormats failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::EnumFormats - leave\n")); return This->TranslateHr(hr); }
/****************************************************************************
* * FreeBuffer * * @method HRESULT | IInstallVideoCodecs | FreeBuffer | Free a buffer that was * returned by the IInstallVideoCodec interface * * @parm LPVOID | lpBuffer | Address of the buffer to free. This buffer must have * been allocated by one of the IInstallVideoCodecs methods * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * None * ***************************************************************************/ HRESULT CInstallVideoCodecs::FreeBuffer(LPVOID lpBuffer) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
HRESULT hr = NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::FreeBuffer\n"));
hr = This->FreeBuffer(lpBuffer);
if (FAILED(hr)) { ERRORMSG(("CInstallVideoCodecs::FreeBuffer failed, hr=0x%x\n", hr)); }
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::FreeBuffer - leave, hr=0x%x\n", hr)); return This->TranslateHr(hr); }
/****************************************************************************
* @doc INTERNAL COMPFUNC ***************************************************************************/ /****************************************************************************
* * AddRemoveVCMFormat * * @method HRESULT | IInstallVideoCodecs | AddRemoveVCMFormat | Adds or * removes a VCM format for use with NetMeeting * * @parm PAUDCAP_INFO | pVidCapInfo | Information on the format to add/remove * * @parm BOOL | bAdd | TRUE = Add the format, FALSE = Remove the format * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag IC_E_NO_SUCH_FORMAT | The specified format was not found. The format * must be installed with Video For Windows before it can be added for use * with NetMeeting. * @flag IC_E_INTERNAL_ERROR | the Network Audio/Video Controller * reported a system error * ***************************************************************************/ HRESULT CInstallVideoCodecs::AddRemoveVCMFormat(PVIDCAP_INFO pVidCapInfo, BOOL bAdd) { CInstallCodecs *This=IMPL(CInstallCodecs, ifVideo, this); // the containing object
VIDEOFORMATEX vfx; HRESULT hr=NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddVCMFormat\n"));
/*
* Parameter validation */
if (!pVidCapInfo || IsBadReadPtr(pVidCapInfo, (UINT) sizeof(VIDCAP_INFO))) { hr = E_INVALIDARG; goto out; }
// some fields should not be zero
if ((pVidCapInfo->uFrameRate == 0) || (pVidCapInfo->uAvgBitrate == 0) || ((pVidCapInfo->dwBitsPerSample == 0) && (pVidCapInfo->bih.biBitCount == 0))) { hr = E_INVALIDARG; goto out; }
// make sure dwBitsPerSample and biBitCount match
if (pVidCapInfo->dwBitsPerSample == 0) pVidCapInfo->dwBitsPerSample = pVidCapInfo->bih.biBitCount; if (pVidCapInfo->bih.biBitCount == 0) pVidCapInfo->bih.biBitCount = LOWORD(pVidCapInfo->dwBitsPerSample); if (LOWORD(pVidCapInfo->dwBitsPerSample) != pVidCapInfo->bih.biBitCount) { hr = E_INVALIDARG; goto out; }
/*
* Make a VIDEOFORMATEX structure */
RtlZeroMemory((PVOID) &vfx, sizeof(VIDEOFORMATEX));
// Make sure it's Upper Case
if (pVidCapInfo->dwFormatTag > 256) CharUpperBuff((LPTSTR)&pVidCapInfo->dwFormatTag, sizeof(DWORD));
vfx.dwFormatTag = pVidCapInfo->dwFormatTag;
vfx.nSamplesPerSec = pVidCapInfo->uFrameRate; vfx.wBitsPerSample = pVidCapInfo->dwBitsPerSample; // wBitPerSample is a DWORD
vfx.nAvgBytesPerSec = pVidCapInfo->uAvgBitrate; RtlCopyMemory(&vfx.bih, &pVidCapInfo->bih, sizeof(BITMAPINFOHEADER));
/*
* Add or remove the format */
if (bAdd) hr = This->m_pVidAppCaps->AddVCMFormat(&vfx, pVidCapInfo); else hr = This->m_pVidAppCaps->RemoveVCMFormat(&vfx);
out: DEBUGMSG(ZONE_INSTCODEC,("CInstallVideoCodecs::AddRemoveVCMFormat - leave\n")); return This->TranslateHr(hr); }
/***************************************************************************
Name : CInstallCodecs::CInstallCodecs
Purpose : The CInstallCodecs object constructor
Parameters: none
Returns : None
Comment :
***************************************************************************/ inline CInstallCodecs::CInstallCodecs (void) { m_cRef = 0; // will be bumped to 1 by the explicit QI in the create function
m_pAudAppCaps = NULL; m_pVidAppCaps = NULL;
// can't use ++ because RISC processors may translate to several instructions
InterlockedIncrement((long *) &g_cICObjects); }
/***************************************************************************
Name : CInstallCodecs::~CInstallCodecs
Purpose : The CInstallCodecs object destructor
Parameters: none
Returns : None
Comment :
***************************************************************************/ inline CInstallCodecs::~CInstallCodecs (void) { // let the caps interfaces and objects go
if (m_pAudAppCaps) m_pAudAppCaps->Release(); if (m_pVidAppCaps) m_pVidAppCaps->Release();
// can't use ++ because RISC processors may translate to several instructions
if (!InterlockedDecrement((long *) &g_cICObjects)) { if (g_hMutex) CloseHandle(g_hMutex); g_hMutex = NULL; }
g_pIC = (CInstallCodecs *)NULL;
}
/***************************************************************************
Name : CInstallCodecs::FreeBuffer
Purpose : Frees a buffer allocated by the the installable codecs interfaces.
Parameters: lpBuffer - a pointer to the buffer to free. This buffer must have been allocated by installable codecs interfaces
Returns : HRESULT
Comment :
***************************************************************************/ HRESULT CInstallCodecs::FreeBuffer(LPVOID lpBuffer) { HRESULT hr = NOERROR;
DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::FreeBuffer\n"));
if (lpBuffer) MEMFREE(lpBuffer);
DEBUGMSG(ZONE_INSTCODEC,("CInstallCodecs::FreeBuffer - leave, hr=0x%x\n", hr)); return TranslateHr(hr); }
/***************************************************************************
Name : CInstallCodecs::TranslateHr
Purpose : Translates an HRESULT to an external installable codecs value
Parameters: hr - [in] the HRESULT value to translate
Returns : HRESULT - the translated value
Comment :
***************************************************************************/ HRESULT CInstallCodecs::TranslateHr(HRESULT hr) { switch (hr) { case CAPS_E_NOMATCH: hr = IC_E_NO_SUCH_FORMAT; break;
case CAPS_E_INVALID_PARAM: hr = E_INVALIDARG; break;
case CAPS_E_SYSTEM_ERROR: hr = IC_E_INTERNAL_ERROR; break; default: break; }
return hr; }
/****************************************************************************
* * Initialize * * @func HRESULT | Initialize | Initializes the CinstallCodecs object * * @parm REFIID | riid | Reference to the identifier of the interface * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag E_OUTOFMEMORY | Not enough memory for creating the object * @flag IC_E_CAPS_INSTANTIATION_FAILURE | Could not instantiate a capability object * @flag IC_E_CAPS_INITIALIZATION_FAILURE | Could not initialize a capability object * ***************************************************************************/ HRESULT CInstallCodecs::Initialize(REFIID riid) { HRESULT hr=NOERROR; CMsiaCapability *pAudCapObj = NULL; CMsivCapability *pVidCapObj = NULL;
/*
* Instantiate */
ACQMUTEX(g_hMutex);
/*
* Audio */
if ((riid == IID_IInstallAudioCodecs) && !m_pAudAppCaps) { // instantiate the audio capability object
DBG_SAVE_FILE_LINE pAudCapObj = new CMsiaCapability;
if (!pAudCapObj) { hr = IC_E_CAPS_INSTANTIATION_FAILURE; goto out; }
// get an appcap interface on the capability objects
// this interface will be used for most calls
hr = pAudCapObj->QueryInterface(IID_IAppAudioCap, (void **)&m_pAudAppCaps); if(!HR_SUCCEEDED(hr)) { hr = IC_E_CAPS_INSTANTIATION_FAILURE; goto out; } pAudCapObj->Release(); // this balances the refcount of "new CMsiaCapability"
// initialize the capability objects
if (!(pAudCapObj->Init())) { hr = IC_E_CAPS_INITIALIZATION_FAILURE; goto out; } }
/*
* Video */
if ((riid == IID_IInstallVideoCodecs) && !m_pVidAppCaps) { // instantiate the video capability object
DBG_SAVE_FILE_LINE pVidCapObj = new CMsivCapability;
if (!pVidCapObj) { hr = IC_E_CAPS_INSTANTIATION_FAILURE; goto out; } // get an appcap interface on the capability objects
// this interface will be used for most calls
hr = pVidCapObj->QueryInterface(IID_IAppVidCap, (void **)&m_pVidAppCaps); if(!HR_SUCCEEDED(hr)) { hr = IC_E_CAPS_INSTANTIATION_FAILURE; goto out; } pVidCapObj->Release(); // this balances the refcount of "new CMsivCapability"
if (!(pVidCapObj->Init())) { hr = IC_E_CAPS_INITIALIZATION_FAILURE; goto out; } }
out: if (FAILED(hr)) { ERRORMSG(("CInstallCodecs::Initialize failed, hr=0x%x\n", hr)); }
RELMUTEX(g_hMutex); return TranslateHr(hr); }
/****************************************************************************
* @doc EXTERNAL COMPFUNC ***************************************************************************/ /****************************************************************************
* * CreateInstallCodecs * * @func HRESULT | CreateInstallCodecs | Creates an instance of the CInstallCodecs * object, and returns the requested interface. This function should only be * called indirectly through CoCreateInstance. * @parm LPUNKNOWN | punkOuter | Pointer to whether object is or isn�t part * of an aggregate * * @parm REFIID | riid | Reference to the identifier of the interface * * @parm LPVOID * | ppv | Indirect pointer to requested interface * * @rdesc Returns zero (NOERROR) if the function was successful. Otherwise, it returns * a standard HRESULT, with the WIN32 facility code (7), or the specific facility * code for installable codecs (0x301). * Possible error codes: * @flag E_INVALIDARG | Invalid argument * @flag E_OUTOFMEMORY | Not enough memory for creating the object * @flag CLASS_E_NOAGGREGATION | Aggregation is not supported for this object * @flag IC_E_CAPS_INSTANTIATION_FAILURE | Could not instantiate a capability object * @flag IC_E_CAPS_INITIALIZATION_FAILURE | Could not initialize a capability object * * @comm CreateInstallCodecs should not be called directly. Clients of installable * codecs should use the COM CoCreateInstance to instantiate the object, expecting * the same return values. * ***************************************************************************/ extern "C" HRESULT WINAPI CreateInstallCodecs ( IUnknown *pUnkOuter, REFIID riid, void **ppv) { CInstallCodecs *pIC; HRESULT hr = NOERROR;
*ppv = 0; if (pUnkOuter) { hr = CLASS_E_NOAGGREGATION; goto out; }
/*
* instantiate the object */
// create a mutex to control access to QoS object data
//
// NOTE: I'm taking some chance here: the code that creates the mutex must be
// executed by one thread at a time, so it should really be in the PROCESS_ATTACH
// for NAC.DLL. However, since this code is expected to be called rarely, and in
// order not to add code to the NAC load time, I put it here.
if (!g_hMutex) { g_hMutex = CreateMutex(NULL, FALSE, NULL); ASSERT(g_hMutex); if (!g_hMutex) { ERRORMSG(("CreateInstallCodecs: CreateMutex failed, 0x%x\n", GetLastError())); hr = E_FAIL; goto out; } }
ACQMUTEX(g_hMutex);
// only instantiate a new object if it doesn't already exist
if (!g_pIC) { DBG_SAVE_FILE_LINE if (!(pIC = new CInstallCodecs)) { hr = E_OUTOFMEMORY; RELMUTEX(g_hMutex); goto out; }
// Save pointer
g_pIC = pIC; } else { // this is the case when the object was already instantiaed in this
// process, so we only want to return the object pointer.
pIC = g_pIC; }
// always initialize the object. Initialize will only initialize what
// is not yet initialized
hr = pIC->Initialize(riid);
RELMUTEX(g_hMutex);
// get the requested interface for the caller
if (pIC) { // QueryInterface will get us the interface pointer and will AddRef
// the object
hr = pIC->QueryInterface (riid, ppv); } else hr = E_FAIL;
out: if (FAILED(hr)) { ERRORMSG(("CreateInstallCodecs failed, hr=0x%x\n", hr)); } return hr; }
|