强制Mpeg2Demultiplexer使用ffdshow来渲染H264数字电视视频

22
我花费了很多时间尝试使DirectShow的DTVViewer示例工作,但不幸的是没有成功。DVBT网络的视频格式是H264,我发现IFilterGraph的IntelliConnect行为更喜欢使用Mpeg2视频格式。
这是想要查看代码的人的代码。如果你不知道任何关于DirectShow的东西,我会分享我的经验。最可能的问题在教程的第5步和第6步中描述。
连接过滤器的辅助函数的代码:
public static void UnsafeConnectFilters(IFilterGraph2 graph, IBaseFilter source, IBaseFilter dest, Func<AMMediaType, bool> sourceMediaPredicate=null, Func<AMMediaType, bool> destMediaPredicate=null) {
    foreach(IPin spin in IteratePinsByDirection(source, PinDirection.Output)) {
        if(IsConnected(spin))
            continue;
        int fetched;
        AMMediaType[] sourceTypes=GetMajorType(spin, out fetched);
        if(fetched>0) {
            Guid sourceType=sourceTypes[0].majorType;
            try {
                if(sourceMediaPredicate!=null&&!sourceMediaPredicate(sourceTypes[0]))
                    continue;
                foreach(IPin pin in IteratePinsByDirection(dest, PinDirection.Input)) {
                    if(IsConnected(pin))
                        continue;
                    var types=GetMajorType(pin, out fetched);
                    try {
                        if(fetched>0) {
                            Guid destType=types[0].majorType;
                            if(destMediaPredicate!=null&&!destMediaPredicate(types[0]))
                                continue;
                            if(sourceType==destType) {
                                spin.Connect(pin, types[0]);
                                return;
                            }
                        }
                        else {
                            spin.Connect(pin, sourceTypes[0]);
                            return;
                        }
                    }
                    finally {
                    }
                }
            }
            finally {
            }

        }
    }
}

有人了解吗:

  1. 我应该如何将h264引脚连接到ffdshow?
  2. 我应该如何推荐图使用h264视频解码?

  • 教程和详细信息

    1. 创建图表

    _graph = (IFilterGraph2)new FilterGraph();
    
    我们正在使用DVBT网络。
    IBaseFilter networkProvider = (IBaseFilter) new DVBTNetworkProvider();
    

    ... 这必须调整到602000KHz@8MHz ONID=1 TSID=1 SID=6

    ITuner tuner = (ITuner) networkProvider;
    IDVBTuningSpace tuningspace = (IDVBTuningSpace) new DVBTuningSpace();
    tuningspace.put_UniqueName("DVBT TuningSpace");
    tuningspace.put_FriendlyName("DVBT TuningSpace");
    tuningspace.put__NetworkType(typeof (DVBTNetworkProvider).GUID);
    tuningspace.put_SystemType(DVBSystemType.Terrestrial);
    ITuneRequest request;
    tuningspace.CreateTuneRequest(out request);
    ILocator locator = (ILocator) new DVBTLocator();
    locator.put_CarrierFrequency(602000);
    ((IDVBTLocator) locator).put_Bandwidth(8);
    request.put_Locator(locator);
    IDVBTuneRequest dvbrequest = (IDVBTuneRequest) request;
    dvbrequest.put_TSID(1);
    dvbrequest.put_ONID(1);
    dvbrequest.put_SID(6);
    _graph.AddFilter(networkProvider, "Network Provider");
    
    创建一个mpeg2解复用器,从单个电视流中获取独立的EPG /视频/音频/文本流。
    _mpeg2Demultiplexer = (IBaseFilter) new MPEG2Demultiplexer();
    _graph.AddFilter(_mpeg2Demultiplexer, "MPEG-2 Demultiplexer");
    

    现在我们搜索本地过滤器以查找BDA源过滤器,而在我的情况下是IT9135 BDA Filter

    DsDevice[] devicesOfCat = 
        DsDevice.GetDevicesOfCat(FilterCategory.BDASourceFiltersCategory);
    
    IBaseFilter iteDeviceFilter;
    
    _graph.AddSourceFilterForMoniker(
        devicesOfCat[0].Mon, null, devicesOfCat[0].Name, out iteDeviceFilter);
    
  • 现在连接过滤器:[DVBT 网络提供商] -> [BDA Src 过滤器] -> [MPEG2Demux] -> ...

  • UnsafeConnectFilters(_graph, networkProvider, iteDeviceFilter);
    UnsafeConnectFilters(_graph, iteDeviceFilter, _mpeg2Demultiplexer);
    

    必须将两个过滤器连接到解复用器上,以提供电视节目指南数据。抱歉,我不知道它们具体是做什么的:P。它们位于BDATransportInformationRenderersCategory类别下。我们尝试按名称找到它们并将它们连接到解复用器上。

    DsDevice[] dsDevices = 
        DsDevice.GetDevicesOfCat(FilterCategory.BDATransportInformationRenderersCategory);
    
    foreach (DsDevice dsDevice in dsDevices)
    {
        IBaseFilter filter;
    
        _graph.AddSourceFilterForMoniker(
            dsDevice.Mon, null, dsDevice.Name, out filter);
    
        if(dsDevice.Name == "BDA MPEG2 Transport Information Filter")
            _bdaTIF = filter;
        else if(dsDevice.Name == "MPEG-2 Sections and Tables")
        {
            _mpeg2SectionsAndTables = filter;
        }
        UnsafeConnectFilters(_graph, _mpeg2Demultiplexer, filter);
    }
    

    现在 demux 已连接到 MPEG-2 Sections and TablesBDA MPEG2 Transport Information Filter 两个部分。

  • 现在创建 h264 视频类型并将其添加到 demux 的输出引脚中

  • AMMediaType h264 = new AMMediaType();
    h264.formatType = FormatType.VideoInfo2;
    h264.subType = MediaSubType.H264;
    h264.majorType = MediaType.Video;
    IPin h264pin;
    ((IMpeg2Demultiplexer) _mpeg2Demultiplexer).CreateOutputPin(h264, "h264", out h264pin);
    

    以下是我尝试搜索的ffdshow视频解码器,它能够处理H264视频,并位于DirectShow Filters类别下(如在GraphStudio中)。

    DsDevice[] directshowfilters = 
        DsDevice.GetDevicesOfCat(FilterCategory.LegacyAmFilterCategory);
    
    IBaseFilter ffdshow = null;
    foreach (DsDevice directshowfilter in directshowfilters)
    {
        if(directshowfilter.Name == "ffdshow Video Decoder")
        {
            _graph.AddSourceFilterForMoniker(
                directshowfilter.Mon, null, directshowfilter.Name, 
                out ffdshow);
    
            break;
        }
    }
    
  • 创建视频渲染器以用于视频输出...

    _videoRenderer = new VideoRendererDefault();
    _graph.AddFilter((IBaseFilter)_videoRenderer, "Video Renderer");
    

    ...和音频...

    DsDevice defaultDirectSound = 
        DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory)[0];
    
    _graph.AddSourceFilterForMoniker(
        defaultDirectSound.Mon, null, defaultDirectSound.Name, 
        out _audioRender);
    

    我尝试将demux的h264输出引脚连接到ffdshow。这个方法调用会失败并出现AccessViolationException异常。我不确定如何将它们连接在一起:(

    如果注释掉这行代码,虽然图形中有一个未连接的ffdshowVideoDecoder滤镜,但图形将开始运行却不会显示任何内容。IntelliConnect将Mpeg2视频输出连接到本地可用的视频解码器,正如我所说,它不会显示任何内容。

    // UnsafeConnectFilters(_graph, _mpeg2Demultiplexer, ffdshow, type => type.majorType == MediaType.Video && type.subType == MediaSubType.H264);
    
  • ConnectFilters是从directshowlib的DTVViewer示例中借用的。

  • ConnectFilters();
    

    我把实际的调整移到了这里

    tuner.put_TuningSpace(tuningspace);
    tuner.put_TuneRequest(request);
    
    开始绘制图表,并期望能够显示一些声音或视频。<\li>
    int hr = (_graph as IMediaControl).Run();
    DsError.ThrowExceptionForHR(hr);
    
  • 检查图形是否正在运行...

  • FilterState pfs;
    hr = (_graph as IMediaControl).GetState(1000, out pfs);
    DsError.ThrowExceptionForHR(hr);
    

    它表示图表正在运行。


我最好说一下,我正在使用Windows XP :) - Bakhshi
你能手动使用GraphEdit创建图形吗?如果可以,请包含手动图形的截图。 - Odys
@odyodyodys 我已经不再参与那个项目了。但是我无法仅使用GraphEdit创建图表。这需要大量的端口配置,而GE中却无法实现。最终,我使用了TeamMediaPortal组件,将其从源代码中提取出来。 - Bakhshi
你最终解决了这个问题吗? - Simon
1个回答

1

请问您检查过您的ffdshow是否启用了H264/AVC吗?打开滤镜属性,在“编解码器”部分,H264/AVC格式应该是启用的(您也可以禁用Mpeg2解码器以确保它不会优先选择此格式)。

另外,您可以尝试使用另一个Mpeg2分离器。默认的“MPEG-2 Demultiplexer”在不同的环境中表现不同。有许多其他过滤器可以分离TS,如果您愿意投资一些钱,我建议使用MainConcept或Elecard。


感谢您的光临。是的,H262在ffdshow属性中已启用。关于使用其他解复用器,我不确定是否测试过。已经有一段时间了。无论如何,如果您有任何运行情况,请在此分享您的经验,以便其他人可以从中学到一些东西。谢谢。 - Bakhshi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接