Concatenate two AVI files using IltmmMultiStreamSource and IltmmMultiStreamTarget Example for C++

#define SOURCE_FILE1  "C:\\Src1.avi"
#define SOURCE_FILE2  "C:\\Src2.wav"
#define DEST_FILE  "C:\\Dst.avi"

void Concatenate()
{
   IltmmConvert* pConvert1 = NULL;
   IltmmConvert* pConvert2 = NULL;
   IltmmMultiStreamTarget* pSampleTarget = NULL;
   IltmmMultiStreamSource* pSampleSource = NULL;
   long lStartLo, lStartHi;
   IltmmMediaTypeDisp* pmt = NULL;
   IltmmMediaTypeDisp* pInsertedMediaType;
   BSTR  bstr;

   CoInitialize(NULL);
   HRESULT hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**) &pConvert1);
   if(FAILED(hr))
   {
      AfxMessageBox(_T("Can't instantiate convert library"));
      return -1;
   }

   hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**) &pConvert2);
   if(FAILED(hr))
   {
      AfxMessageBox(_T("Can't instantiate convert library"));
      return -1;
   }

   hr = CoCreateInstance(CLSID_ltmmMultiStreamTarget, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMultiStreamTarget, (void**) &pSampleTarget);
   if(FAILED(hr))
   {
      AfxMessageBox(_T("Can't instantiate convert library"));
      return -1;
   }

   hr = CoCreateInstance(CLSID_ltmmMultiStreamSource, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMultiStreamSource, (void**) &pSampleSource);
   if(FAILED(hr))
   {
      AfxMessageBox(_T("Can't instantiate convert library"));
      return -1;
   }

   // set the start time to be 0
   lStartHi = 0;
   lStartLo = 0;

   // set the input filename
   bstr = A2BSTR(SOURCE_FILE1);
   pConvert1->put_SourceFile(bstr);
   SysFreeString(bstr);
   // set the output sample to a target object
   pSampleTarget->put_StreamCount(2);

   hr = CoCreateInstance(CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMediaTypeDisp, (void**) &pmt);
   if(FAILED(hr))
   {
      AfxMessageBox(_T("Can't instantiate convert library"));
      return -1;
   }

   pmt->put_Type(ltmmMEDIATYPE_Video);
   pSampleTarget->SetAcceptedMediaType(0, pmt);
   pmt->put_Type(ltmmMEDIATYPE_Audio);
   pSampleTarget->SetAcceptedMediaType(1, pmt);
   pmt->Release();
   pmt = NULL;

   // get the inserted media type for the first stream
   pSampleTarget->GetAcceptedMediaType(0, &pInsertedMediaType);
   pInsertedMediaType->Release();
   pInsertedMediaType = NULL;

   hr = pConvert1->put_TargetObject(pSampleTarget);

   // START the source conversion, so we can get the media sample format
   hr = pConvert1->StartConvert();

    //INITIALIZE pConvert2
   // get the output media sample format and put it into the source object
   pSampleSource->put_StreamCount(2);
   hr = pSampleTarget->GetConnectedMediaType(0, &pmt);
   pSampleSource->SetMediaType(0, pmt);
   pmt->Release();
   pmt = NULL;
   pSampleTarget->GetConnectedMediaType(1, &pmt);
   pSampleSource->SetMediaType(1, pmt);
   pmt->Release();
   pmt = NULL;

   // get the inserted media type for the first stream
   pSampleSource->GetMediaType(0, &pInsertedMediaType);
   pInsertedMediaType->Release();
   pInsertedMediaType = NULL;

   // set the output filename
   bstr = A2BSTR(DEST_FILE);
   pConvert2->put_TargetFile(bstr);
   SysFreeString(bstr);
   pConvert2->put_SourceObject(pSampleSource);
   // start the dest conversion
   pConvert2->StartConvert();

   SetWindowText("Converting file1...");
   // convert first file
   ConvertFile(pConvert1, pSampleTarget, pSampleSource, &lStartHi, &lStartLo);

   /*
      Restrict the output format to the media type of the source for the first file
      That is because the two files must have the same media type for both video and audio
      With video, you have to make sure the files have the same frame rate! Minor changes in
      the frame rate might make the connection fail!
      The control will tolerate differences in frame rate if you comment the next line
   */
   pSampleTarget->GetConnectedMediaType(0, &pmt);
   pSampleTarget->SetAcceptedMediaType(0, pmt);
   pmt->Release();
   pmt = NULL;
   pSampleTarget->GetConnectedMediaType(1, &pmt);
   pSampleTarget->SetAcceptedMediaType(1, pmt);
   pmt->Release();
   pmt = NULL;

   // change the source file to second file
   bstr = A2BSTR(SOURCE_FILE2);
   pConvert1->put_SourceFile(bstr);
   SysFreeString(bstr);
   // start converting again
   pConvert1->StartConvert();

   SetWindowText("Converting file2...");
   // convert second file
   ConvertFile(pConvert1, pSampleTarget, pSampleSource, &lStartHi, &lStartLo);

   // deliver end of sample to stop the conversion
   pSampleSource->DeliverEndOfStream(0, 1000);
   pSampleSource->DeliverEndOfStream(1, 1000);

   long lState;
   pConvert2->get_State(&lState);
   if (lState = ltmmConvert_State_Running)
        pConvert2->StopConvert();

   SetWindowText("Done");
   // free the source and target objects
   pConvert1->ResetTarget();
   pConvert2->ResetSource();

   if (pConvert1)
   {
      pConvert1->Release();
      pConvert1 = NULL;
   }

   if (pConvert2)
   {
      pConvert2->Release();
      pConvert2 = NULL;
   }

   if (pSampleSource)
   {
      pSampleSource->Release();
      pSampleSource = NULL;
   }

   if (pSampleTarget)
   {
      pSampleTarget->Release();
      pSampleTarget = NULL;
   }

   CoUninitialize();
   return TRUE;  // return TRUE  unless you set the focus to a control
}

void CConcatFilesDlg::ConvertFile(IltmmConvert* pConvert1, IltmmMultiStreamTarget* pSampleTarget, IltmmMultiStreamSource* pSampleSource, long* plStartHi , long *plStartLo)
{
   IltmmMediaSampleDisp* pmsSrc = NULL;
   IltmmMediaSampleDisp* pmsDst = NULL;
   long LastStartHi;
   long LastStartLo;
   long LastStopHi;
   long LastStopLo;
   long lSampleStream;
   HRESULT hr;

   LastStopHi = 0;
   LastStopLo = 0;

   do
   {      
      // get the sample, allowing 10 s for the operation to complete
      hr = pSampleTarget->WaitForSample(1000, &lSampleStream);
      if (FAILED(hr))
         break;
      hr = pSampleTarget->GetSample(lSampleStream, 0, &pmsSrc);
      if (FAILED(hr))
         break;      
      hr = pSampleSource->GetSampleBuffer(lSampleStream, 2000, &pmsDst);
      if (FAILED(hr))
         break;
      // set the sample time
      pmsSrc->GetTime(&LastStartHi, &LastStartLo, &LastStopHi, &LastStopLo);
      // get the sample time
      pmsDst->SetTime(*plStartHi + LastStartHi, *plStartLo + LastStartLo, *plStartHi + LastStopHi, *plStartLo + LastStopLo);

      // copy the data
      long lActualDataLength;
      pmsSrc->get_ActualDataLength(&lActualDataLength);
      VARIANT vBuffer;
      pmsSrc->GetData(lActualDataLength, &vBuffer);
      pmsDst->SetData(lActualDataLength, vBuffer);

      // copy the other flags
      VARIANT_BOOL vBool;
      hr = pmsSrc->get_Discontinuity(&vBool);
      if (FAILED(hr))
         break;
      hr = pmsDst->put_Discontinuity(vBool);
      if (FAILED(hr))
         break;

      hr = pmsSrc->get_Preroll(&vBool);
      if (FAILED(hr))
         break;
      hr = pmsDst->put_Preroll(vBool);
      if (FAILED(hr))
         break;

      hr = pmsSrc->get_SyncPoint(&vBool);
      if (FAILED(hr))
         break;
      hr = pmsDst->put_SyncPoint(vBool);
      if (FAILED(hr))
         break;

      // release the source sample
      pmsSrc->Release();
      pmsSrc = NULL;
      // deliver the destination sample
      pSampleSource->DeliverSample(lSampleStream, 1000, pmsDst);
      // release the destination sample
      pmsDst->Release();
      pmsDst = NULL;
   }
   while (1);

   pConvert1->StopConvert();
   *plStartHi = LastStopHi;
   *plStartLo = LastStopLo;

}