For complete code, refer to the CNVWM demo.
#include "amvideo.h"
void CopyWaveFormatEx (WAVEFORMATEX *wfex, BYTE *pArrayData)
{
memcpy ( wfex, pArrayData, sizeof ( WAVEFORMATEX ) ) ;
}
void CopyVideoInfoHeader (VIDEOINFOHEADER *vih, BYTE *pArrayData)
{
memcpy ( vih, pArrayData, sizeof ( VIDEOINFOHEADER ) ) ;
}
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 = {0};
IltmmMediaTypeDisp *pCandidatemt = NULL;
IltmmMediaTypeDisp *pMt = NULL;
IltmmWMStreamConfig *pStream = NULL;
long codecs;
long formats;
long lSize;
BYTE *pArrayData = NULL;
HRESULT hr;
int codecindex;
int formatindex;
BSTR bstrData;
long diff;
BSTR stringData;
BSTR stringData2;
bCandidate = FALSE;
// get the number of audio codecs
IltmmWMProfileManager_GetCodecInfoCount(pManager, /*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", &codecs);
// search for matching codec
for(codecindex = 0; codecindex < codecs; codecindex++)
{
IltmmWMProfileManager_GetCodecFormatCount(pManager, /*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", codecindex, &formats);
for(formatindex = 0; formatindex < formats; formatindex++)
{
if(pCodecFormat)
{
IltmmWMStreamConfig_Release(pCodecFormat);
pCodecFormat = NULL;
}
hr = IltmmWMProfileManager_GetCodecFormat(pManager, /*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", codecindex, formatindex, &pCodecFormat);
if(pMediaType)
{
IltmmMediaTypeDisp_Release(pMediaType);
pMediaType = NULL;
}
hr = IltmmWMStreamConfig_GetMediaType(pCodecFormat, &pMediaType);
IltmmMediaTypeDisp_get_FormatType(pMediaType, &bstrData);
if (!wcscmp(_wcsupr(bstrData), /*FORMAT_WaveFormatEx*/L"{05589F81-C356-11CE-BF01-00AA0055595A}"))
{
VARIANT var;
IltmmMediaTypeDisp_get_Format (pMediaType, &var);
SafeArrayAccessData(V_ARRAY(&var), (void**) &pArrayData);
lSize = var.parray->cbElements * var.parray->rgsabound->cElements;
CopyWaveFormatEx(&wfex, pArrayData);
SafeArrayUnaccessData(V_ARRAY(&var));
VariantClear(&var);
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 blockalign.
// In this case,
// the blockalign 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);
IltmmMediaTypeDisp_put_Type(pMt, /*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}");
stringData = SysAllocStringLen(L"00000000", 150);
stringData2 = SysAllocStringLen(L"{", 150);
swprintf(stringData, 353, L"%0 8X");
wcscat(stringData2, stringData);
wcscat(stringData2, L"-0000-0010-8000-00AA00389B71}");
IltmmMediaTypeDisp_put_Subtype(pMt, stringData2);
IltmmMediaTypeDisp_put_FixedSizeSamples(pMt, TRUE);
IltmmMediaTypeDisp_put_TemporalCompression(pMt, FALSE);
IltmmMediaTypeDisp_put_SampleSize(pMt, candidatewfex.nBlockAlign);
IltmmMediaTypeDisp_put_FormatType(pMt, /*FORMAT_WaveFormatEx*/L"{05589F81-C356-11CE-BF01-00AA0055595A}");
IltmmMediaTypeDisp_get_Format (pCandidatemt, &var);
IltmmMediaTypeDisp_SetFormatData(pMt, -1, var);
IltmmWMProfile_CreateNewStream(pProfile, /*MEDIATYPE_Audio*/L"{73647561-0000-0010-8000-00AA00389B71}", &pStream);
IltmmWMStreamConfig_put_StreamNumber (pStream, nStreamNum);
IltmmWMStreamConfig_put_StreamName(pStream, L"Audio Stream");
IltmmWMStreamConfig_put_ConnectionName (pStream, L"Audio");
IltmmWMStreamConfig_put_Bitrate(pStream, candidatewfex.nAvgBytesPerSec * 8);
IltmmWMStreamConfig_SetMediaType (pStream, pMt);
IltmmWMProfile_AddStream(pProfile, pStream);
IltmmMediaTypeDisp_Release(pMt);
IltmmWMStreamConfig_Release(pStream);
IltmmMediaTypeDisp_Release(pCandidatemt);
}
if(pCodecFormat)
{
IltmmWMStreamConfig_Release(pCodecFormat);
pCodecFormat = NULL;
}
if(pMediaType)
{
IltmmMediaTypeDisp_Release(pMediaType);
pMediaType = NULL;
}
}
void AddVideoStream
(
IltmmWMProfileManager *pManager ,
IltmmWMProfile *pProfile,
int nStreamNum,
long lFourCC,
long lBitrate,
long lWidth,
long lHeight,
long lFps,
long lQuality,
long lSecperKey
)
{
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;
int codecindex;
int formatindex;
VARIANT var;
SAFEARRAY sa;
struct
{
LONG lowpart;
LONG highpart;
} Num64;
bCandidate = FALSE;
// get the number of video codecs
IltmmWMProfileManager_GetCodecInfoCount(pManager, /*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", &codecs);
// search for matching codec
for(codecindex = 0; codecindex < codecs; codecindex++)
{
IltmmWMProfileManager_GetCodecFormatCount (pManager, /*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, &formats);
#ifdef DEBUG
IltmmWMProfileManager_GetCodecName(pManager, /*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, &bstrData);
OutputDebugString(OLE2A(bstrData));
SysFreeString(bstrData);
#endif
for(formatindex = 0; formatindex < formats; formatindex++)
{
if(pCodecFormat)
{
IltmmWMStreamConfig_Release(pCodecFormat);
pCodecFormat = NULL;
}
IltmmWMProfileManager_GetCodecFormat (pManager, /*MEDIATYPE_Video*/ L"{73646976-0000-0010-8000-00AA00389B71}", codecindex, formatindex, &pCodecFormat);
if(pMediaType)
{
IltmmMediaTypeDisp_Release(pMediaType);
pMediaType = NULL;
}
IltmmWMStreamConfig_GetMediaType (pCodecFormat, &pMediaType);
IltmmMediaTypeDisp_get_FormatType (pMediaType, &bstrData);
if (!wcscmp(_wcsupr(bstrData), /*FORMAT_VideoInfo*/ L"{05589F80-C356-11CE-BF01-00AA0055595A}"))
{
VARIANT var;
IltmmMediaTypeDisp_get_Format(pMediaType, &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;
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
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;
IltmmMediaTypeDisp_SetFormatData(pCandidateMt, -1, var);
IltmmWMStreamConfig_put_Quality(pCandidateStream, lQuality);
IltmmWMStreamConfig_put_MaxKeyFrameSpacing(pCandidateStream, lSecperKey);
IltmmWMStreamConfig_put_StreamNumber(pCandidateStream, nStreamNum);
IltmmWMStreamConfig_put_StreamName(pCandidateStream, L"Video Stream");
IltmmWMStreamConfig_put_ConnectionName(pCandidateStream, L"Video");
IltmmWMStreamConfig_put_Bitrate (pCandidateStream, lBitrate);
IltmmWMStreamConfig_put_BufferWindow(pCandidateStream, -1);
IltmmWMStreamConfig_SetMediaType(pCandidateStream, pCandidateMt);
IltmmWMProfile_AddStream (pProfile, pCandidateStream);
IltmmWMProfile_ReconfigStream(pProfile, pCandidateStream);
IltmmMediaTypeDisp_Release(pCandidateMt);
IltmmWMStreamConfig_Release(pCandidateStream);
}
if(pCodecFormat)
{
IltmmWMStreamConfig_Release(pCodecFormat);
pCodecFormat = NULL;
}
if(pMediaType)
{
IltmmMediaTypeDisp_Release(pMediaType);
pMediaType = NULL;
}
}
void AddMutexObject(IltmmWMProfile *pProfile, int nBaseStream, int nStreamCount)
{
IltmmWMMutualExclusion *pExcl = NULL;
HRESULT hr;
int i;
// create an exclusion object
IltmmWMProfile_CreateNewMutualExclusion(pProfile, &pExcl);
// indicate that the streams differ by bit rate
// see CLSID_WMMUTEX_Bitrate in the WMSDK
IltmmWMMutualExclusion_put_Type(pExcl, L"{D6E22A01-35DA-11D1-9034-00A0C90349BE}");
// mark all the streams for mutual exclusion
for(i = 0; i < nStreamCount; i++)
{
hr = IltmmWMMutualExclusion_AddStream(pExcl, nBaseStream + i );
}
// assign the exclusion object to the profile
hr = IltmmWMProfile_AddMutualExclusion(pProfile, pExcl);
IltmmWMMutualExclusion_Release(pExcl);
}
void IltmmWMProfile_AddStream_Example (IltmmConvert *pConvert)
{
IltmmWMProfileManager *pManager = NULL;
IltmmWMProfile *pProfile = NULL;
int i;
// create an empty profile
CoCreateInstance(&CLSID_ltmmWMProfileManager, NULL, CLSCTX_INPROC_SERVER, &IID_IltmmWMProfileManager, (void**) &pManager);
IltmmWMProfileManager_put_SystemProfileVersion(pManager, ltmmWMT_VER_8_0);
IltmmWMProfileManager_CreateEmptyProfile(pManager, ltmmWMT_VER_7_0, &pProfile);
IltmmWMProfile_put_Name(pProfile, L"Custom Profile");
IltmmWMProfile_put_Description(pProfile, 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(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
IltmmConvert_put_WMProfile(pConvert, pProfile);
// Free…
IltmmWMProfileManager_Release(pManager);
}