强制 Mpeg2Demultiplexer 使用 ffdshow 呈现 H264 数字电视视频

Forcing Mpeg2Demultiplexer to use ffdshow to render H264 Digital TV Video

提问人:Bakhshi 提问时间:6/26/2012 最后编辑:Ken KinBakhshi 更新时间:3/19/2013 访问量:2588

问:

不幸的是,我花了很多时间尝试使DirectShow的DTVViewer示例工作,但没有成功。DVBT网络的视频格式是H264,我发现IntelliConnect的行为更喜欢使用Mpeg2视频格式。IFilterGraph

对于那些想要查看代码的人来说,这里是。如果您对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();
      
    2. 我们正在使用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");
      
    3. 创建一个 mpeg2 多路复用器,从单个电视流中获取单独的 EPG/Vidoe/音频/文本流

      _mpeg2Demultiplexer = (IBaseFilter) new MPEG2Demultiplexer();
      _graph.AddFilter(_mpeg2Demultiplexer, "MPEG-2 Demultiplexer");
      

      现在我们在本地过滤器中搜索 BDA 源过滤器,在我的情况下是IT9135 BDA Fitler

      DsDevice[] devicesOfCat = 
          DsDevice.GetDevicesOfCat(FilterCategory.BDASourceFiltersCategory);
      
      IBaseFilter iteDeviceFilter;
      
      _graph.AddSourceFilterForMoniker(
          devicesOfCat[0].Mon, null, devicesOfCat[0].Name, out iteDeviceFilter);
      
    4. 现在连接过滤器:[DVBT Net. Provider]->[BDA Src Filter]->[MPEG2Demux]-> ...

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

      必须将两个过滤器连接到解复用器,以提供 epg(节目指南数据)。对不起,我不知道它们具体是什么 doig .它们位于类别下。我们尝试按名称找到它们并将它们连接到解复用器:PBDATransportInformationRenderersCategory

      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

    5. 现在创建 h264 视频类型,并将输出输出引脚添加到此类型的解复用器

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

      下面,我尝试搜索能够处理 H264 视频的 ffdshow 视频解码器,它位于类别下(如 )。DirectShow FiltersGraphStudio

      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;
          }
      }
      
    6. 为视频输出创建视频渲染器...

      _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);
      

      在这里,我尝试将解复用器的 h264 输出引脚连接到 ffdshow。此方法调用失败,并出现 AccessViolationException。我不确定如何将这两者连接在一起.:(

      注释此行将导致一个开始运行的图形,尽管图形中有一个断开连接的 ffdshowVideoDecoder 过滤器,但不会显示任何内容。IntelliConnect 将 Mpeg2 视频输出连接到本地可用的视频解码器,正如我所说,它不会显示任何内容。

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

      ConnectFilters();
      

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

      tuner.put_TuningSpace(tuningspace);
      tuner.put_TuneRequest(request);
      
    8. 启动图形并希望显示一些声音或视频

      int hr = (_graph as IMediaControl).Run();
      DsError.ThrowExceptionForHR(hr);
      
    9. 检查图形是否正在运行...

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

      它说图形正在运行。

C# Direct显示 H.264 DVB

评论

0赞 Bakhshi 6/27/2012
...我最好说我正在使用 Windows XP :)
0赞 Odys 12/18/2012
您可以使用 GraphEdit 手动创建图表吗?如果是这样,请将手动图表作为屏幕截图包含在内。
0赞 Bakhshi 2/11/2013
@odyodyodys我不再从事该项目。但我无法仅使用 GraphEdit 创建图表。它需要大量的端口配置,这在GE中是不可能的。我最终使用了TeamMediaPortal组件,该组件是从源代码中提取的。
0赞 Simon 9/23/2013
你有没有让它工作过?

答:

1赞 odavid 3/19/2013 #1

您是否检查过您的 ffdshow 是否启用了 H264/AVC?打开过滤器属性,在“编解码器”部分,应启用 H264/AVC 格式(您也可以禁用 Mpeg2 解码器,以确保它不会喜欢这种格式)。

另一件事,您可以尝试使用另一个 Mpeg2 多路复用器。默认的“MPEG-2 解复用器”在不同环境中的行为并不相同。还有许多其他过滤器可以解复用 TS,如果您可以投入一些资金,我建议使用 MainConcept 或 Elecard。

评论

0赞 Bakhshi 3/25/2013
感谢您的路过。是的,H262 已在 ffdshow 属性中启用。关于使用其他解复用器,我不确定我是否测试过它们。 已经有一段时间了。无论如何,如果你正在运行任何东西,你能在这里分享你的经验,以便其他人可以从中学到一些东西吗?谢谢