Combine Video and Audio from Separate Sources - Windows C++

This tutorial shows how to use the LEADTOOLS Multimedia SDK to create a Windows C++ application that uses the ltmmConvert control and other LEADTOOLS objects to combine video and audio from separate files into one output file.

Overview  
Summary This tutorial shows how to use the LEADTOOLS Multimedia SDK to combine audio and video into one file.
Completion Time 30 minutes
Visual Studio Project Download tutorial project (19 KB)
Platform Windows API C++ Application
IDE Visual Studio 2019
Development License Download LEADTOOLS
Try it in another language

Required Knowledge

Before working on the Combine Video and Audio from Separate Sources - Windows C++ tutorial, complete the Add References and Set a License tutorial.

Create the Project and Add the Multimedia Headers and LIB Files

Start with a copy of the 64-bit Windows API project created in the Add References and Set a License tutorial. If the project is not available, create it by following the steps in that tutorial.

In order to use the ltmmConvert Object, LEADTOOLS requires additional references. Add the required Multimedia library reference by opening the pre-compiled header file, either pch.h or stdafx.h depending on the Visual Studio version used, and add the following lines:

// Add LEADTOOLS Multimedia reference 
#include "C:\LEADTOOLS23\Include\ltmm.h" 
#include "C:\LEADTOOLS23\Include\ltmm_Errors.h" 
 
//x64 libs 
#pragma comment (lib, "C:\\LEADTOOLS23\\Lib\\CDLL\\x64\\Ltmmx.lib") 
#pragma comment (lib, "C:\\LEADTOOLS23\\Lib\\CDLL\\x64\\ltmmuuidx.lib") 

Add the Code to Combine the Media Files

With the project created, the references added, and the license set, coding can begin.

In the main CPP file of the project, locate the InitInstance() function and add the following line of code at the beginning, to initialize the Windows COM library.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 
{ 
   CoInitialize(NULL); 
   // Keep the rest of the function unchanged 

The steps below are for Visual Studio 2019; they could be different for other versions of Visual Studio.

Go to the Solution Explorer and double-click the resources file (.rc). Expand the menu tab in the resources tree and double-click the menu resource to open it in the designer interface. In the empty item below the Exit item, click and type &Merge Audio and Video. Drag the new item above Exit. Ensure the item's ID is ID_FILE_MERGEAUDIOANDVIDEO.

Go to the main CPP file of the project, which contains the WndProc() function for the main window. Navigate to the switch (wmId) statement that is below the WM_COMMAND case and add the new case shown below.

// In WndProc(), under "case WM_COMMAND:" 
switch (wmId) 
{ 
case ID_FILE_MERGEAUDIOANDVIDEO: 
   if(FAILED(CombineAudioandVideo())) 
      MessageBox(hWnd, TEXT("Combining failed"), TEXT("LEADTOOLS Demo"), MB_ICONERROR); 
   else 
      MessageBox(NULL, TEXT("Combining successful"), TEXT("LEADTOOLS Demo"), MB_ICONINFORMATION); 
   break; 
     // Keep rest of the code as is 

Below is the code for the SelectCompressor() , CombineFiles() and CombineAudioandVideo() functions used in the code.

To test use these sample files:

SelectCompressor(IltmmCompressors *pCompressors, const TCHAR *pszCompressorName)

void SelectCompressor(IltmmCompressors *pCompressors, const TCHAR *pszCompressorName) 
{ 
   long index; 
   BSTR bstrCompressorName = SysAllocString(pszCompressorName); 
   pCompressors->Find(bstrCompressorName, &index); 
   pCompressors->put_Selection(index); 
   SysFreeString(bstrCompressorName); 
} 

CombineFiles(IltmmSampleTarget* pVideoTarget, IltmmSampleTarget* pAudioTarget, const TCHAR* _targetFile)

HRESULT CombineFiles(IltmmSampleTarget* pVideoTarget, IltmmSampleTarget* pAudioTarget, const TCHAR* _targetFile) 
{ 
   IltmmMultiStreamSource* pMSSource = NULL; 
   HRESULT hr = CoCreateInstance(CLSID_ltmmMultiStreamSource, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMultiStreamSource, (void**)&pMSSource); 
   if (FAILED(hr)) 
      return hr; 
   pMSSource->put_StreamCount(2); 
   IltmmMediaTypeDisp* pmt = NULL; 
 
   hr = pVideoTarget->GetConnectedMediaType(&pmt); 
   if (FAILED(hr)) 
      return hr; 
   hr = pMSSource->SetMediaType(0, pmt); 
   if (FAILED(hr)) 
      return hr; 
   pmt->Release(); 
   pmt = NULL; 
 
   hr = pAudioTarget->GetConnectedMediaType(&pmt); 
   if (FAILED(hr)) 
      return hr; 
   hr = pMSSource->SetMediaType(1, pmt); 
   if (FAILED(hr)) 
      return hr; 
   pmt->Release(); 
   pmt = NULL; 
 
   IltmmConvert* pCombineConvert = NULL; 
   hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**)&pCombineConvert); 
   if (FAILED(hr)) 
      return hr; 
   pCombineConvert->put_SourceObject(pMSSource); 
   BSTR bstrTargetFile = SysAllocString(_targetFile); 
   pCombineConvert->put_TargetFile(bstrTargetFile); 
   SysFreeString(bstrTargetFile); 
 
   //Select the desired compressor based on the name 
#define LEAD_H264_ENCODER L"@device:sw:{33D9A760-90C8-11D0-BD43-00A0C911CE86}\\LEAD H264 Encoder (4.0)" 
#define LEAD_AAC_AUDIO_ENCODER L"@device:sw:{33D9A761-90C8-11D0-BD43-00A0C911CE86}\\{E2B7DD70-38C5-11D5-91F6-00104BDB8FF9}" 
 
   //Set the Video Compressor 
   IltmmCompressors* pCompressors; 
   pCombineConvert->get_VideoCompressors(&pCompressors); 
   SelectCompressor(pCompressors, LEAD_H264_ENCODER); 
   pCompressors->Release(); 
 
   //Set the Audio Compressor 
   pCombineConvert->get_AudioCompressors(&pCompressors); 
   SelectCompressor(pCompressors, LEAD_AAC_AUDIO_ENCODER); 
   pCompressors->Release(); 
 
   pCombineConvert->put_TargetFormat(ltmmConvert_TargetFormat_MPEG2_TRANSPORT); 
 
   IltmmMediaSampleDisp* pmsSrc = NULL; 
   IltmmMediaSampleDisp* pmsDst = NULL; 
   long              lStartTimeHi; 
   long              lStartTimeLo; 
   long              lStopTimeHi; 
   long              lStopTimeLo; 
   VARIANT           vBuffer; 
   VARIANT_BOOL      vBool; 
   long              lActualDataLength; 
 
   //Begin the running the Combine ConvertCtrl 
   pCombineConvert->StartConvert(); 
 
   //Video Write 
   while (true) 
   { 
      pVideoTarget->GetSample(10000, &pmsSrc); 
      if (!pmsSrc) 
         break; 
      // get a source sample 
      hr = pMSSource->GetSampleBuffer(0, 10000, &pmsDst); 
      if (FAILED(hr)) 
         break; 
 
      // copy the data to the source sample 
      hr = pmsSrc->get_Buffer(&vBuffer); 
      if (FAILED(hr)) 
         break; 
      hr = pmsSrc->get_ActualDataLength(&lActualDataLength); 
      if (FAILED(hr)) 
         break; 
 
      hr = pmsDst->SetData(lActualDataLength, vBuffer); 
      if (FAILED(hr)) 
         break; 
 
      // copy the sample time 
      hr = pmsSrc->GetTime(&lStartTimeHi, &lStartTimeLo, &lStopTimeHi, &lStopTimeLo); 
      if (FAILED(hr)) 
         pmsDst->ResetTime(); 
      else 
      { 
         hr = pmsDst->SetTime(lStartTimeHi, lStartTimeLo, lStopTimeHi, lStopTimeLo); 
         if (FAILED(hr)) 
            break; 
      } 
 
      // copy the other flags 
      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 source sample 
      hr = pMSSource->DeliverSample(0, 2000, pmsDst); 
      if (FAILED(hr)) 
         break; 
 
      // release the source sample 
      pmsDst->Release(); 
      pmsDst = NULL; 
   } 
   //Audio Write 
   while (true) 
   { 
      pAudioTarget->GetSample(10000, &pmsSrc); 
      if (!pmsSrc) 
         break; 
      // get a source sample 
      hr = pMSSource->GetSampleBuffer(1, 10000, &pmsDst); 
      if (FAILED(hr)) 
         break; 
 
      // copy the data to the source sample 
      hr = pmsSrc->get_Buffer(&vBuffer); 
      if (FAILED(hr)) 
         break; 
      hr = pmsSrc->get_ActualDataLength(&lActualDataLength); 
      if (FAILED(hr)) 
         break; 
 
      hr = pmsDst->SetData(lActualDataLength, vBuffer); 
      if (FAILED(hr)) 
         break; 
 
 
      // copy the sample time 
      hr = pmsSrc->GetTime(&lStartTimeHi, &lStartTimeLo, &lStopTimeHi, &lStopTimeLo); 
      if (FAILED(hr)) 
         pmsDst->ResetTime(); 
      else 
      { 
         hr = pmsDst->SetTime(lStartTimeHi, lStartTimeLo, lStopTimeHi, lStopTimeLo); 
         if (FAILED(hr)) 
            break; 
      } 
 
      // copy the other flags 
      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 source sample 
      hr = pMSSource->DeliverSample(1, 2000, pmsDst); 
      if (FAILED(hr)) 
         break; 
 
      // release the source sample 
      pmsDst->Release(); 
      pmsDst = NULL; 
   } 
   pCombineConvert->StopConvert(); 
   pMSSource->DeliverEndOfStream(0, 1000); 
   pMSSource->DeliverEndOfStream(1, 1000); 
   pCombineConvert->ResetSource(); 
 
   pMSSource->Release(); 
   pCombineConvert->Release(); 
   return hr; 
} 

CombineAudioandVideo()

int CombineAudioandVideo() 
{ 
   // Initialize the convert control 
   IltmmConvert *pVidConvert = NULL, *pAudConvert = NULL; 
   HRESULT hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**)&pVidConvert); 
   if (FAILED(hr)) 
      return hr; 
   hr = CoCreateInstance(CLSID_ltmmConvert, NULL, CLSCTX_INPROC_SERVER, IID_IltmmConvert, (void**)&pAudConvert); 
   if (FAILED(hr)) 
      return hr; 
 
   //Init the SampleTargets. The Video and Audio data from our files will write to these. 
   IltmmSampleTarget *pVidTarget = NULL, *pAudTarget = NULL; 
   hr = CoCreateInstance(CLSID_ltmmSampleTarget, NULL, CLSCTX_INPROC_SERVER, IID_IltmmSampleTarget, (void**)&pVidTarget); 
   if (FAILED(hr)) 
      return hr; 
   hr = CoCreateInstance(CLSID_ltmmSampleTarget, NULL, CLSCTX_INPROC_SERVER, IID_IltmmSampleTarget, (void**)&pAudTarget); 
   if (FAILED(hr)) 
      return hr; 
 
   IltmmMediaTypeDisp* pmt = NULL; 
   hr = CoCreateInstance(CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMediaTypeDisp, (void**)&pmt); 
   if (FAILED(hr)) 
      return hr; 
   pmt->put_Type((BSTR)ltmmMEDIATYPE_Video); 
   // make the SampleTarget object accept connections of this media type 
   hr = pVidTarget->SetAcceptedMediaType(pmt); 
   if (FAILED(hr)) 
      return hr; 
   pVidConvert->put_TargetObject(pVidTarget); 
   pmt->Release(); 
   pmt = NULL; 
 
   hr = CoCreateInstance(CLSID_ltmmMediaType, NULL, CLSCTX_INPROC_SERVER, IID_IltmmMediaTypeDisp, (void**)&pmt); 
   if (FAILED(hr)) 
      return hr; 
   pmt->put_Type((BSTR)ltmmMEDIATYPE_Audio); 
   // make the SampleTarget object accept connections of this media type 
   hr = pAudTarget->SetAcceptedMediaType(pmt); 
   if (FAILED(hr)) 
      return hr; 
   pAudConvert->put_TargetObject(pAudTarget); 
   pmt->Release(); 
   pmt = NULL; 
   // Ensure this is the correct path 
   BSTR bstrSourceFileVid = SysAllocString(TEXT("Video-Source.mp4")); 
   hr = pVidConvert->put_SourceFile(bstrSourceFileVid); 
   if (FAILED(hr)) 
      return hr; 
   SysFreeString(bstrSourceFileVid); 
   // Ensure this is the correct path 
   BSTR bstrSourceFileAud = SysAllocString(TEXT("Audio-Source.mpg")); 
   hr = pAudConvert->put_SourceFile(bstrSourceFileAud); 
   if (FAILED(hr)) 
      return hr; 
   SysFreeString(bstrSourceFileAud); 
   pVidConvert->StartConvert(); 
   pAudConvert->StartConvert(); 
 
   // Ensure this is the correct path 
   hr = CombineFiles(pVidTarget, pAudTarget, TEXT("Combined-File.mpg")); 
   long lState = 0; 
   pVidConvert->get_State(&lState); 
   if (lState == ltmmConvert_State::ltmmConvert_State_Running) 
      pVidConvert->StopConvert(); 
   lState = 0; 
   pAudConvert->get_State(&lState); 
   if (lState == ltmmConvert_State::ltmmConvert_State_Running) 
      pAudConvert->StopConvert(); 
   pVidTarget->Release(); 
   pVidTarget = NULL; 
   pAudTarget->Release(); 
   pAudTarget = NULL; 
 
   pAudConvert->Release(); 
   pVidConvert->Release(); 
   return hr; 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps are followed correctly, the application runs and converts the audio and video source files to one media file. If the sample files above were used, this would be the expected output media file.

Wrap-up

This tutorial showed how to combine two media files, one video and one audio, to one file using the ltmmConvert Object.

See Also

Help Version 23.0.2024.3.11
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.


Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.