如何结合GDCL MPEG-4通过DirectShow播放MP4文件
DirectShow结合GDCL MPEG-4解码器播放MP4文件
问题描述
DirectShow默认无法播放MP4文件,我找到了GDCL MPEG-4解码器,但未找到相关使用示例。现有一段基础DirectShow示例代码,希望了解如何结合该代码使用GDCL解码器实现MP4文件的播放。
现有基础代码
#include <iostream> #include <dshow.h> int main() { IGraphBuilder* pGraph = NULL; IMediaControl* pControl = NULL; IMediaEvent* pEvent = NULL; // 初始化COM库 HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { printf("ERROR - 无法初始化COM库"); return 1; } // 创建滤镜图管理器并获取接口 hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); if (FAILED(hr)) { printf("ERROR - 无法创建滤镜图管理器"); return 1; } hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); hr = pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent); // 构建滤镜图:替换为你系统中的文件路径 hr = pGraph->RenderFile(L"..\\BigBuckBunny360.wmv", NULL); if (SUCCEEDED(hr)) { // 运行滤镜图 hr = pControl->Run(); if (SUCCEEDED(hr)) { // 等待播放完成 long evCode; pEvent->WaitForCompletion(INFINITE, &evCode); // 注意:实际应用中不要使用INFINITE,会导致无限阻塞 } else { std::cout << std::system_category().message(hr) << std::endl; } } else { std::cout << std::system_category().message(hr) << std::endl; } pControl->Release(); pEvent->Release(); pGraph->Release(); CoUninitialize(); return 0; }
实现步骤与修改后的代码
前置准备
- 编译并注册GDCL解码器:获取解码器代码编译生成滤镜组件(通常为
gdclmpeg4dec.dll),通过命令行执行regsvr32 gdclmpeg4dec.dll完成注册,让DirectShow能识别该解码器。
修改代码手动构建滤镜图
默认RenderFile可能无法自动匹配GDCL解码器,需手动添加并连接各个滤镜:
#include <iostream> #include <dshow.h> // 辅助函数:查找滤镜的指定方向引脚 HRESULT FindPin(IBaseFilter* pFilter, PIN_DIRECTION dir, IPin** ppPin) { IEnumPins* pEnum = NULL; IPin* pPin = NULL; HRESULT hr = pFilter->EnumPins(&pEnum); if (FAILED(hr)) return hr; while (pEnum->Next(1, &pPin, NULL) == S_OK) { PIN_DIRECTION pinDir; pPin->QueryDirection(&pinDir); if (pinDir == dir) { *ppPin = pPin; pEnum->Release(); return S_OK; } pPin->Release(); } pEnum->Release(); return E_FAIL; } int main() { IGraphBuilder* pGraph = NULL; IMediaControl* pControl = NULL; IMediaEvent* pEvent = NULL; IBaseFilter* pSource = NULL; IBaseFilter* pDecoder = NULL; IBaseFilter* pVideoRenderer = NULL; IPin* pSourceOut = NULL; IPin* pDecoderIn = NULL; IPin* pDecoderOut = NULL; IPin* pVideoRenderIn = NULL; // 初始化COM库 HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { printf("ERROR - 无法初始化COM库"); goto Cleanup; } // 创建滤镜图管理器 hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); if (FAILED(hr)) { printf("ERROR - 无法创建滤镜图管理器"); goto Cleanup; } // 获取控制和事件接口 hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); hr = pGraph->QueryInterface(IID_IMediaEvent, (void**)&pEvent); // 1. 创建MP4源滤镜(使用Async Reader) hr = CoCreateInstance(CLSID_AsyncReader, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pSource); if (FAILED(hr)) { printf("ERROR - 无法创建源滤镜"); goto Cleanup; } // 设置源文件路径 IFileSourceFilter* pFileSource = NULL; hr = pSource->QueryInterface(IID_IFileSourceFilter, (void**)&pFileSource); if (SUCCEEDED(hr)) { hr = pFileSource->Load(L"你的MP4文件路径.mp4", NULL); pFileSource->Release(); } if (FAILED(hr)) { printf("ERROR - 无法加载MP4文件"); goto Cleanup; } hr = pGraph->AddFilter(pSource, L"MP4 Source"); // 2. 创建GDCL MPEG-4解码器滤镜(CLSID从解码器源码中获取) const CLSID CLSID_GdclMpeg4Dec = {0x1B544C20, 0xFD0B, 0x11D1, {0x90, 0x38, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x98}}; hr = CoCreateInstance(CLSID_GdclMpeg4Dec, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pDecoder); if (FAILED(hr)) { printf("ERROR - 无法创建GDCL解码器"); goto Cleanup; } hr = pGraph->AddFilter(pDecoder, L"GDCL MPEG-4 Decoder"); // 3. 创建视频渲染器 hr = CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pVideoRenderer); if (FAILED(hr)) { printf("ERROR - 无法创建视频渲染器"); goto Cleanup; } hr = pGraph->AddFilter(pVideoRenderer, L"Video Renderer"); // 连接滤镜引脚 // 源滤镜 -> 解码器 hr = FindPin(pSource, PINDIR_OUTPUT, &pSourceOut); hr = FindPin(pDecoder, PINDIR_INPUT, &pDecoderIn); hr = pGraph->Connect(pSourceOut, pDecoderIn); // 解码器 -> 视频渲染器 hr = FindPin(pDecoder, PINDIR_OUTPUT, &pDecoderOut); hr = FindPin(pVideoRenderer, PINDIR_INPUT, &pVideoRenderIn); hr = pGraph->Connect(pDecoderOut, pVideoRenderIn); // 运行滤镜图 hr = pControl->Run(); if (SUCCEEDED(hr)) { long evCode; pEvent->WaitForCompletion(INFINITE, &evCode); } else { std::cout << std::system_category().message(hr) << std::endl; } Cleanup: // 释放所有资源 if (pSourceOut) pSourceOut->Release(); if (pDecoderIn) pDecoderIn->Release(); if (pDecoderOut) pDecoderOut->Release(); if (pVideoRenderIn) pVideoRenderIn->Release(); if (pSource) pSource->Release(); if (pDecoder) pDecoder->Release(); if (pVideoRenderer) pVideoRenderer->Release(); if (pControl) pControl->Release(); if (pEvent) pEvent->Release(); if (pGraph) pGraph->Release(); CoUninitialize(); return 0; }
注意事项
- 确保GDCL解码器的CLSID正确,可从其源代码的头文件中查找定义。
- 若MP4包含音频,需额外添加音频解码器和音频渲染器的连接逻辑,可参考视频部分的实现逻辑。
- 实际应用中避免使用
INFINITE等待播放完成,可通过定时查询事件状态实现非阻塞等待。
内容的提问来源于stack exchange,提问作者BigRiver
相关产品推荐
相关产品推荐

