Create a File with 2 Audio Streams that are Mutually Exclusive
The following code can be used to create a file with two audio streams that are mutually exclusive:
BSTR bstr;
CString fname;
HRESULT hr;
USES_CONVERSION;
if( m_pConvert == NULL )
return;
// Create the profile manager object:
hr = CoCreateInstance(CLSID_ltmmWMProfileManager, NULL, CLSCTX_INPROC_SERVER, IID_IltmmWMProfileManager, (void**) &m_pProfMan);
// create an empty profile:
hr = m_pProfMan->CreateEmptyProfile (ltmmWMT_VER_7_0, &m_pProf);
// Set the profile name and description
hr = m_pProf->put_Name (L"Mutex Stream_test");
hr = m_pProf->put_Description (L"Example code");
// add 2 audio streams with different bitrates
hr = AddAudioStream(mgr, profile, 1, CODEC_AUDIO_MSAUDIO, 8000, 8000, 1, FALSE);
hr = AddAudioStream(mgr, profile, 2, CODEC_AUDIO_MSAUDIO, 16000, 16000, 1, FALSE);
// make them mutually exclusive
hr = AddMutexObject(profile, 1, 2);
// add the profile to the convert object
hr = m_pConvert->put_WMProfile (m_pProf);
m_pProf->Release();
m_pProfMan->Release();
//set the target format
hr = m_pConvert->put_TargetFormat ( ltmmConvert_TargetFormat_Asf_Compressor_Mux );
// set the source file name; the source file contains multiple audio streams:
hr = m_pConvert->put_SourceFile (L"London.avi");
// set the output file name:
hr = m_pConvert->put_TargetFile ("London.asf");
// do the conversion
hr = m_pConvert->StartConvert ();
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);
// 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);
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 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);
// 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);
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);
// 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);
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);
hr = stream->SetMediaType (pmt);
hr = profile->AddStream (stream);
stream->Release();
pmt->Release();
SafeArrayUnaccessData(V_ARRAY(&varSave));
VariantClear(&varSave);
return S_OK;
}
HRESULT AddMutexObject(IltmmWMProfile *profile, UINT nBaseStream, UINT nStreamCount)
{
IltmmWMMutualExclusion *excl = NULL;
// create an exclusion object
HRESULT hr = profile->CreateNewMutualExclusion (&excl);
// mark all the streams for mutual exclusion
for(UINT i = 0; i < nStreamCount; i++)
{
hr = excl->AddStream (nBaseStream + i);
}
// indicate that the streams differ by Bitrate
// see CLSID_WMMUTEX_Bitrate in the WMSDK
BSTR bstr = ::SysAllocString(L"{D6E22A01-35DA-11D1-9034-00A0C90349BE}");
hr = excl->put_Type(bstr);
::SysFreeString(bstr);
// assign the exclusion object to the profile
hr = profile->AddMutualExclusion (excl);
excl->Release();
return hr;
}