/* - 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 #include // for setting NetMeeting to manual codec selection #include // 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; }