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