IltmmWMProfile::AddStream Example for C++

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;
}