For complete code, refer to the CNVWM demo.
#include "amvideo.h" #include "Mmreg.h" HRESULT AddAudioStream(IltmmWMProfileManager* mgr, IltmmWMProfile* profile, UINT nStreamNum, UINT nFormatTag, ULONG nBitRate, ULONG nSamplesPerSec, UINT nChannels, BOOL bVideo) { long cCodecs; VARIANT varSave; VariantInit(&varSave); // get MEDIATYPE_Audio codec count BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); HRESULT hr = mgr->GetCodecInfoCount(bstr, &cCodecs); ::SysFreeString(bstr); if (FAILED(hr)) return hr; // search for matching codec for (long i = 0; i < cCodecs; i++) { long cFormats; // get MEDIATYPE_Audio codec format count BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); HRESULT hr = mgr->GetCodecFormatCount(bstr, i, &cFormats); ::SysFreeString(bstr); if(FAILED(hr)) break; for (long j = 0; j < cFormats; j++) { // get MEDIATYPE_Audio stream config interface IltmmWMStreamConfig* format; bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); hr = mgr->GetCodecFormat(bstr, i, j, &format); ::SysFreeString(bstr); if (SUCCEEDED(hr)) { // get this format's media type IltmmMediaTypeDisp* pmt; hr = format->GetMediaType(&pmt); if (SUCCEEDED(hr)) { hr = pmt->get_FormatType(&bstr); if (SUCCEEDED(hr)) { // only check FORMAT_WaveFormatEx formats if (!_wcsicmp(bstr, ltmmFORMAT_WaveFormatEx)) { VARIANT var; VariantInit(&var); pmt->get_Format(&var); WAVEFORMATEX *pWfx; SafeArrayAccessData(V_ARRAY(&var), (void**) &pWfx); // does this format look like a good candidate long nDiff = (long) (pWfx->nAvgBytesPerSec * 8 - nBitRate); if (nDiff < 250 && nDiff > -250 && pWfx->nSamplesPerSec == nSamplesPerSec && pWfx->nChannels == nChannels && pWfx->wFormatTag == nFormatTag) { if (V_VT(&varSave) != VT_EMPTY) { WAVEFORMATEX *pSaveWFX; SafeArrayAccessData(V_ARRAY(&varSave), (void**) &pSaveWFX); if (bVideo) { // For audio/video configurations, we want to // find the smaller nBlockAlign. In this case, // the nBlockAlign is larger, so we want to // use the old format. if (pWfx->nBlockAlign <= pSaveWFX->nBlockAlign) { SafeArrayUnaccessData(V_ARRAY(&varSave)); VariantClear(&varSave); VariantCopy(&varSave, &var); } } else { // otherwise, we want the larger nBlockAlign if (pWfx->nBlockAlign >= pSaveWFX->nBlockAlign) { SafeArrayUnaccessData(V_ARRAY(&varSave)); VariantClear(&varSave); VariantCopy(&varSave, &var); } } } else { VariantClear(&varSave); VariantCopy(&varSave, &var); } } SafeArrayUnaccessData(V_ARRAY(&var)); VariantClear(&var); } ::SysFreeString(bstr); } pmt->Release(); } format->Release(); } } } // return an error, if we didn't find a good candidate if (V_VT(&varSave) == VT_EMPTY) return E_FAIL; WAVEFORMATEX *pSaveWFX; SafeArrayAccessData(V_ARRAY(&varSave), (void**) &pSaveWFX); IltmmMediaTypeDisp* pmt; hr = CoCreateInstance(CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMediaTypeDisp, (void**) &pmt); if (FAILED(hr)) { SafeArrayUnaccessData(V_ARRAY(&varSave)); VariantClear(&varSave); return hr; } // setup the new stream's media type bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); pmt->put_Type(bstr); ::SysFreeString(bstr); CString s; s.Format(_T("{%.8X-0000-0010-8000-00AA00389B71}"), (UINT) pSaveWFX->wFormatTag); bstr = s.AllocSysString(); pmt->put_Subtype(bstr); ::SysFreeString(bstr); pmt->put_FixedSizeSamples(VARIANT_TRUE); pmt->put_TemporalCompression(VARIANT_FALSE); pmt->put_SampleSize(pSaveWFX->nBlockAlign); bstr = ::SysAllocString(ltmmFORMAT_WaveFormatEx); pmt->put_FormatType(bstr); ::SysFreeString(bstr); pmt->SetFormatData(-1L, varSave); IltmmWMStreamConfig* stream; bstr = ::SysAllocString(ltmmMEDIATYPE_Audio); hr = profile->CreateNewStream(bstr, &stream); ::SysFreeString(bstr); if (FAILED(hr)) { SafeArrayUnaccessData(V_ARRAY(&varSave)); VariantClear(&varSave); pmt->Release(); return hr; } stream->put_StreamNumber(nStreamNum); bstr = ::SysAllocString(L"Audio Stream"); stream->put_StreamName(bstr); ::SysFreeString(bstr); bstr = ::SysAllocString(L"Audio"); stream->put_ConnectionName(bstr); ::SysFreeString(bstr); stream->put_Bitrate(pSaveWFX->nAvgBytesPerSec * 8); stream->SetMediaType(pmt); profile->AddStream(stream); stream->Release(); pmt->Release(); SafeArrayUnaccessData(V_ARRAY(&varSave)); VariantClear(&varSave); return S_OK; } HRESULT AddVideoStream(IltmmWMProfileManager* mgr, IltmmWMProfile* profile, UINT nStreamNum, DWORD dwFourCC, ULONG nBitRate, ULONG nWidth, ULONG nHeight, ULONG nFPS, ULONG nQuality, ULONG nSecPerKey) { long cCodecs; IltmmWMStreamConfig* stream = NULL; IltmmMediaTypeDisp* pmt = NULL; VIDEOINFOHEADER *pVIH = NULL; VARIANT varFormat; VariantInit(&varFormat); // get MEDIATYPE_Video codec count BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Video); HRESULT hr = mgr->GetCodecInfoCount(bstr, &cCodecs); ::SysFreeString(bstr); if (FAILED(hr)) return hr; // search for matching codec for (long i = 0; !stream && i < cCodecs; i++) { long cFormats; // get MEDIATYPE_Video codec format count BSTR bstr = ::SysAllocString(ltmmMEDIATYPE_Video); HRESULT hr = mgr->GetCodecFormatCount(bstr, i, &cFormats); ::SysFreeString(bstr); if (FAILED(hr)) break; for (long j = 0; j < cFormats; j++) { // get MEDIATYPE_Video stream config interface bstr = ::SysAllocString(ltmmMEDIATYPE_Video); hr = mgr->GetCodecFormat(bstr, i, j, &stream); ::SysFreeString(bstr); if (SUCCEEDED(hr)) { // get this format's media type hr = stream->GetMediaType(&pmt); if (SUCCEEDED(hr)) { hr = pmt->get_FormatType(&bstr); if (SUCCEEDED(hr)) { // only check FORMAT_VideoInfo formats if (!_wcsicmp(bstr, ltmmFORMAT_VideoInfo)) { pmt->GetFormatData(-1, &varFormat); SafeArrayAccessData(V_ARRAY(&varFormat), (void**) &pVIH); if (pVIH->bmiHeader.biCompression == dwFourCC) { ::SysFreeString(bstr); break; } SafeArrayUnaccessData(V_ARRAY(&varFormat)); VariantClear(&varFormat); } ::SysFreeString(bstr); } pmt->Release(); pmt = NULL; } stream->Release(); stream = NULL; } } } // return an error, if we didn't find a good candidate if (!stream) return E_FAIL; pVIH->dwBitRate = nBitRate; pVIH->rcSource.right = nWidth; pVIH->rcSource.bottom = nHeight; pVIH->rcTarget.right = nWidth; pVIH->rcTarget.bottom = nHeight; pVIH->bmiHeader.biWidth = nWidth; pVIH->bmiHeader.biHeight = nHeight; pVIH->AvgTimePerFrame = ((LONGLONG) 10000000 ) / ((LONGLONG) nFPS ); pmt->SetFormatData(-1, varFormat); hr = stream->put_Quality( nQuality ); hr = stream->put_MaxKeyFrameSpacing((double) nSecPerKey); stream->put_StreamNumber(nStreamNum); bstr = ::SysAllocString(L"Video Stream"); stream->put_StreamName(bstr); ::SysFreeString(bstr); bstr = ::SysAllocString(L"Video"); stream->put_ConnectionName(bstr); ::SysFreeString(bstr); stream->put_Bitrate(nBitRate); stream->SetMediaType(pmt); profile->AddStream(stream); stream->Release(); pmt->Release(); SafeArrayUnaccessData(V_ARRAY(&varFormat)); VariantClear(&varFormat); return S_OK; } HRESULT AddMutexObject(IltmmWMProfile *profile, UINT nBaseStream, UINT nStreamCount) { IltmmWMMutualExclusion *excl = NULL; // create an exclusion object HRESULT hr = profile->CreateNewMutualExclusion(&excl); if (FAILED(hr)) return hr; // indicate that the streams differ by bit rate // see CLSID_WMMUTEX_Bitrate in the WMSDK BSTR bstr = ::SysAllocString(L"{D6E22A01-35DA-11D1-9034-00A0C90349BE}"); hr = excl->put_Type(bstr); ::SysFreeString(bstr); if (FAILED(hr)) { excl->Release(); return hr; } // mark all the streams for mutual exclusion for (UINT i = 0; i < nStreamCount; i++) { hr = excl->AddStream(nBaseStream + i); if (FAILED(hr)) { excl->Release(); return hr; } } // assign the exclusion object to the profile hr = profile->AddMutualExclusion(excl); excl->Release(); return hr; }