You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合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;
}

实现步骤与修改后的代码

前置准备

  1. 编译并注册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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:27:23