合并来自不同来源的视频和音频 - Windows C++

本教程介绍如何使用LEADTOOLS 多媒体 SDK创建 Windows C++ 应用程序,该应用程序使用ltmmConvert控件和其他 LEADTOOLS 对象将来自不同文件的视频和音频合并为一个输出文件。

概述  
概括 本教程介绍如何使用 LEADTOOLS 多媒体 SDK 将音频和视频合并为一个文件。
完成时间 30分钟
Visual Studio 项目 下载教程项目 (19 KB)
平台 Windows API C++ 应用程序
集成开发环境 Visual Studio 2019
开发许可证 下载 LEADTOOLS
尝试使用其他语言

所需知识

在开始“从不同来源合并视频和音频 - Windows C++”教程之前,请先完成“添加引用”和“设置许可证”教程。

创建项目并添加多媒体头文件和 LIB 文件

从“添加引用”和“设置许可证”教程中创建的 64 位 Windows API 项目的副本开始。 Start with a copy of the 64-bit Windows API project created in the Add References and Set a License tutorial. 如果该项目不可用,请按照该教程中的步骤创建它。

为了使用该ltmmConvert对象,LEADTOOLS 需要额外的引用。通过打开预编译头文件(取决于所使用的 Visual Studio 版本)添加所需的多媒体库引用pch.hstdafx.h并添加以下几行:

// 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") 

添加代码以合并媒体文件

创建项目、添加参考并设置许可证后,就可以开始编码了。

在项目的主 CPP 文件中,找到该InitInstance()函数并在开头添加以下代码行,以初始化 Windows COM 库。

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

以下步骤适用于 Visual Studio 2019;对于其他版本的 Visual Studio,它们可能有所不同。

前往解决方案资源管理器,双击资源文件 (.rc)。展开资源树中的菜单选项卡,然后双击菜单资源以在设计器界面中打开它。在“Exit ”项下方的空白处,单击并输入“&Merge Audio and Video”。将新项拖到“Exit”上方。确保该项的 ID 为ID_FILE_MERGEAUDIOANDVIDEO

前往项目的主 CPP 文件,其中包含WndProc()主窗口函数。找到switch (wmId)该 case 下方的语句WM_COMMAND,并添加如下所示的新 case。

// 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 

下面是代码中使用的SelectCompressor()CombineFiles()和函数的代码。CombineAudioandVideo()

要测试,请使用以下示例文件:

选择压缩机(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); 
} 

合并文件(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; 
} 

合并音频和视频()

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

运行项目

按F5或选择“调试”->“开始调试”来运行项目。

如果正确遵循这些步骤,应用程序将运行并将音频和视频源文件转换为一个媒体文件。如果使用了上面的示例文件,这将是预期的输出媒体文件

本教程展示了如何使用ltmmConvertObject 将两个媒体文件(一个视频和一个音频)合并为一个文件。

参见

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐