IltmmWMProfile::AddStream Example for C++
For complete code, refer to the CNVWM demo.
#include "amvideo.h"
#include "Mmreg.h"
void AddAudioStream(IltmmWMProfileManager *pManager, IltmmWMProfile *pProfile,
int nStreamNum, int nFormatTag, long lPrefBitrate,
long lSamplesPerSec, int nChannels, BOOL bWithVideo)
{
IltmmWMStreamConfig *pCodecFormat = NULL;
IltmmMediaTypeDisp *pMediaType = NULL;
WAVEFORMATEX wfex ;
BOOL bCandidate;
WAVEFORMATEX candidatewfex;
IltmmMediaTypeDisp *pCandidatemt = NULL;
IltmmMediaTypeDisp *pMt = NULL;
IltmmWMStreamConfig *pStream = NULL;
long codecs;
long formats;
long lSize;
BYTE *pArrayData = NULL;
HRESULT hr;
bCandidate = FALSE;
// get the number of audio codecs
pManager->GetCodecInfoCount (/*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", &codecs);
// search for matching codec
for(int codecindex = 0; codecindex < codecs; codecindex++)
{
pManager->GetCodecFormatCount (/*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", codecindex, &formats);
for(int formatindex = 0; formatindex < formats; formatindex++)
{
if(pCodecFormat)
{
pCodecFormat->Release();
pCodecFormat = NULL;
}
hr = pManager->GetCodecFormat (/*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", codecindex, formatindex, &pCodecFormat);
if(pMediaType)
{
pMediaType->Release();
pMediaType = NULL;
}
hr = pCodecFormat->GetMediaType (&pMediaType);
BSTR bstrData;
pMediaType->get_FormatType (&bstrData);
if (!wcscmp(_wcsupr(bstrData), /*FORMAT_WaveFormatEx*/L"{05589F81-C356-11CE-BF01-00AA0055595A}"))
{
VARIANT var;
pMediaType->get_Format (&var);
SafeArrayAccessData(V_ARRAY(&var), (void**) &pArrayData);
lSize = var.parray->cbElements * var.parray->rgsabound->cElements;
CopyWaveFormatEx(&wfex, pArrayData);
SafeArrayUnaccessData(V_ARRAY(&var));
VariantClear(&var);
long diff = (wfex.nAvgBytesPerSec * 8 - lPrefBitrate);
if(diff < 250 &&
diff > -250 &&
wfex.nSamplesPerSec == (unsigned int)lSamplesPerSec &&
wfex.nChannels == nChannels &&
wfex.wFormatTag == nFormatTag)
{
if(bCandidate)
{
if(bWithVideo)
{
//
// For audio/video configurations,
// we want to
// find the smaller block alignment.
// In this case,
// the block alignment is larger, so we want to
// use the old format.
//
if (wfex.nBlockAlign <= candidatewfex.nBlockAlign)
{
memcpy(&candidatewfex, &wfex, sizeof(WAVEFORMATEX));
pCandidatemt = pMediaType;
}
}
else
{
if (wfex.nBlockAlign >= candidatewfex.nBlockAlign)
{
memcpy(&candidatewfex, &wfex, sizeof(WAVEFORMATEX));
pCandidatemt = pMediaType;
}
}
}
else
{
bCandidate = TRUE;
memcpy(&candidatewfex, &wfex, sizeof(WAVEFORMATEX));
pCandidatemt = pMediaType;
}
}
}
}
}
if(bCandidate)
{
VARIANT var;
// modify the selected codec to support this bitrate and format
CoCreateInstance(CLSID_ltmmMediaType,
NULL,
CLSCTX_INPROC_SERVER,
IID_IltmmMediaTypeDisp,
(void**) &pMt);
pMt->put_Type (/*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}");
BSTR stringData = SysAllocStringLen(L"00000000", 150);
BSTR stringData2 = SysAllocStringLen(L"{", 150);
swprintf(stringData, L"%0 8X", 353);
wcscat(stringData2, stringData);
wcscat(stringData2, L"-0000-0010-8000-00AA00389B71}");
pMt->put_Subtype (stringData2);
pMt->put_FixedSizeSamples (TRUE);
pMt->put_TemporalCompression (FALSE);
pMt->put_SampleSize (candidatewfex.nBlockAlign);
pMt->put_FormatType (/*FORMAT_WaveFormatEx*/L"{05589F81-C356-11CE-BF01-00AA0055595A}");
pCandidatemt->get_Format (&var);
pMt->SetFormatData (-1, var);
pProfile->CreateNewStream (/*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", &pStream);
pStream->put_StreamNumber (nStreamNum);
pStream->put_StreamName (L"Audio Stream");
pStream->put_ConnectionName (L"Audio");
pStream->put_Bitrate (candidatewfex.nAvgBytesPerSec * 8);
pStream->SetMediaType (pMt);
pProfile->AddStream (pStream);
pMt->Release();
pStream->Release();
pCandidatemt->Release();
}
if(pCodecFormat)
{
pCodecFormat->Release();
pCodecFormat = NULL;
}
if(pMediaType)
{
pMediaType->Release();
pMediaType = NULL;
}
}
void AddVideoStream(IltmmWMProfileManager *pManager ,
IltmmWMProfile *pProfile,
int nStreamNum,
long lFourCC,
long lBitrate,
long lWidth,
long lHeight,
long lFps,
long lQuality,
long lSecperKey)
{
USES_CONVERSION;
IltmmWMStreamConfig *pCodecFormat = NULL;
IltmmMediaTypeDisp *pMediaType = NULL;
VIDEOINFOHEADER vih;
BOOL bCandidate;
VIDEOINFOHEADER candidatevih;
IltmmMediaTypeDisp *pCandidateMt = NULL;
IltmmWMStreamConfig *pCandidateStream = NULL;
long codecs;
long formats;
BSTR bstrData;
BYTE *pArrayData = NULL;
bCandidate = FALSE;
// get the number of video codecs
pManager->GetCodecInfoCount (/*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", &codecs);
// search for matching codec
for(int codecindex = 0; codecindex < codecs; codecindex++)
{
pManager->GetCodecFormatCount (/*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, &formats);
#ifdef DEBUG
pManager->GetCodecName (/*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, &bstrData);
OutputDebugString(OLE2A(bstrData));
SysFreeString(bstrData);
#endif
for(int formatindex = 0; formatindex < formats; formatindex++)
{
if(pCodecFormat)
{
pCodecFormat->Release();
pCodecFormat = NULL;
}
pManager->GetCodecFormat (/*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, formatindex, &pCodecFormat);
if(pMediaType)
{
pMediaType->Release();
pMediaType = NULL;
}
pCodecFormat->GetMediaType (&pMediaType);
#ifdef _DEBUG
pManager->GetCodecFormatDesc (/*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, formatindex, &bstrData);
OutputDebugString(OLE2A(bstrData));
SysFreeString(bstrData);
#endif
pMediaType->get_FormatType (&bstrData);
if (!wcscmp(_wcsupr(bstrData), /*FORMAT_VideoInfo*/ L"{05589F80-C356-11CE-BF01-00AA0055595A}"))
{
VARIANT var;
pMediaType->get_Format (&var);
SafeArrayAccessData(V_ARRAY(&var), (void**) &pArrayData);
CopyVideoInfoHeader(&vih, pArrayData);
SafeArrayUnaccessData(V_ARRAY(&var));
VariantClear(&var);
if (vih.bmiHeader.biCompression == (unsigned long)lFourCC)
{
bCandidate = TRUE;
memcpy(&candidatevih, &vih, sizeof(VIDEOINFOHEADER));
pCandidateMt = pMediaType;
pCandidateStream = pCodecFormat;
}
}
}
}
if(bCandidate)
{
// modify the selected codec to support this bitrate and size
candidatevih.dwBitRate = lBitrate;
candidatevih.rcSource.right = lWidth;
candidatevih.rcSource.bottom = lHeight;
candidatevih.rcTarget.right = lWidth;
candidatevih.rcTarget.bottom = lHeight;
candidatevih.bmiHeader.biWidth = lWidth;
candidatevih.bmiHeader.biHeight = lHeight;
struct
{
LONG lowpart;
LONG highpart;
} Num64;
Num64.lowpart = (long)((long)(10000000.0 / lFps) % 0x10000);
Num64.highpart = (long)((10000000.0 / lFps) / 0x10000);
memcpy(&candidatevih.AvgTimePerFrame, &Num64, 8);
// pass the data to ltmmMediaType via SAFEARRAY
VARIANT var;
SAFEARRAY sa;
memset(&sa, 0, sizeof(sa));
sa.cbElements = sizeof(unsigned char);
sa.cDims = 1;
sa.fFeatures = (FADF_AUTO | FADF_FIXEDSIZE);
sa.pvData = (void*)&candidatevih;
sa.rgsabound[0].cElements = sizeof(VIDEOINFOHEADER);
VariantInit(&var);
V_VT(&var) = (VT_ARRAY | VT_UI1);
V_ARRAY(&var) = &sa;
pCandidateMt->SetFormatData ( -1, var);
pCandidateStream->put_Quality (lQuality);
pCandidateStream->put_MaxKeyFrameSpacing (lSecperKey);
pCandidateStream->put_StreamNumber (nStreamNum);
pCandidateStream->put_StreamName (L"Video Stream");
pCandidateStream->put_ConnectionName (L"Video");
pCandidateStream->put_Bitrate (lBitrate);
pCandidateStream->put_BufferWindow (-1);
pCandidateStream->SetMediaType (pCandidateMt);
pProfile->AddStream (pCandidateStream);
pProfile->ReconfigStream (pCandidateStream);
pCandidateMt->Release();
pCandidateStream->Release();
}
if(pCodecFormat)
{
pCodecFormat->Release();
pCodecFormat = NULL;
}
if(pMediaType)
{
pMediaType->Release();
pMediaType = NULL;
}
}
void AddMutexObject(IltmmWMProfile *pProfile,
int nBaseStream,
int nStreamCount)
{
IltmmWMMutualExclusion *pExcl = NULL;
HRESULT hr;
// create an exclusion object
pProfile->CreateNewMutualExclusion(&pExcl);
// indicate that the streams differ by bit rate
// see CLSID_WMMUTEX_Bitrate in the WMSDK
pExcl->put_Type(L"{D6E22A01-35DA-11D1-9034-00A0C90349BE}");
// mark all the streams for mutual exclusion
for(int i = 0; i < nStreamCount; i++)
{
hr = pExcl->AddStream( nBaseStream + i );
}
// assign the exclusion object to the profile
hr = pProfile->AddMutualExclusion(pExcl);
pExcl->Release();
}
void CreateCustomProfile(IltmmConvert *pConvert)
{
IltmmWMProfileManager *pManager = NULL;
IltmmWMProfile *pProfile = NULL;
// create an empty profile
CoCreateInstance(CLSID_ltmmWMProfileManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_IltmmWMProfileManager,
(void**) &pManager);
pManager->put_SystemProfileVersion (ltmmWMT_VER_8_0);
pManager->CreateEmptyProfile (ltmmWMT_VER_7_0, &pProfile);
pProfile->put_Name (L"Custom Profile");
pProfile->put_Description (L"Custom Profile Description");
// add a single audio stream
AddAudioStream( pManager, pProfile, 1, /*CODEC_AUDIO_MSAUDIO*/353, 8000, 8000, 1, TRUE);
// add 5 video streams with different bit rates
for(int i = 0 ; i < 5; i++)
{
AddVideoStream( pManager, pProfile, 2 + i, /*CODEC_VIDEO_WMV1*/0x31564D57,
(1024 * 20) + i * 1024,
320,
240,
5 * (i + 1),
0,
8);
}
// mark all the video streams for mutual exclusion
AddMutexObject(pProfile, 2, 5);
// Assign the pProfile to a convert object
pConvert->put_WMProfile (pProfile);
// Free…
pManager->Release();
}