Bak*_*shi 22 .net c# directshow h.264 dvb
我花了很多时间试图让DTVViewer的DirectShow样本工作不幸,但没有成功.DVBT网络的视频格式是H264,我发现IntelliConnect行为IFilterGraph更喜欢使用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 {
}
}
}
}
Run Code Online (Sandbox Code Playgroud)有谁知道:
教程和细节
创建图表
_graph = (IFilterGraph2)new FilterGraph();
Run Code Online (Sandbox Code Playgroud)我们正在使用DVBT网络
IBaseFilter networkProvider = (IBaseFilter) new DVBTNetworkProvider();
Run Code Online (Sandbox Code Playgroud)
...必须调到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");
Run Code Online (Sandbox Code Playgroud)创建一个mpeg2 demux,从单个电视流中获取单独的EPG/Vidoe /音频/文本流
_mpeg2Demultiplexer = (IBaseFilter) new MPEG2Demultiplexer();
_graph.AddFilter(_mpeg2Demultiplexer, "MPEG-2 Demultiplexer");
Run Code Online (Sandbox Code Playgroud)
现在我们搜索BDA源过滤器的本地过滤器,在我的例子中 IT9135 BDA Fitler
DsDevice[] devicesOfCat =
DsDevice.GetDevicesOfCat(FilterCategory.BDASourceFiltersCategory);
IBaseFilter iteDeviceFilter;
_graph.AddSourceFilterForMoniker(
devicesOfCat[0].Mon, null, devicesOfCat[0].Name, out iteDeviceFilter);
Run Code Online (Sandbox Code Playgroud)现在连接过滤器: [DVBT Net. Provider]->[BDA Src Filter]->[MPEG2Demux]-> ...
UnsafeConnectFilters(_graph, networkProvider, iteDeviceFilter);
UnsafeConnectFilters(_graph, iteDeviceFilter, _mpeg2Demultiplexer);
Run Code Online (Sandbox Code Playgroud)
必须将两个过滤器连接到demux,以提供epg(节目指南数据).抱歉,我不知道他们具体是什么:P.它们属于BDATransportInformationRenderersCategory类别.我们尝试按名称找到它们并将它们连接到demux
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);
}
Run Code Online (Sandbox Code Playgroud)
现在demux连接到MPEG-2 Sections and Tables和BDA 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);
Run Code Online (Sandbox Code Playgroud)
下面,我尝试搜索能够处理H264视频的ffdshow视频解码器,它位于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;
}
}
Run Code Online (Sandbox Code Playgroud)为视频输出创建视频渲染器 ...
_videoRenderer = new VideoRendererDefault();
_graph.AddFilter((IBaseFilter)_videoRenderer, "Video Renderer");
Run Code Online (Sandbox Code Playgroud)
......和音频......
DsDevice defaultDirectSound =
DsDevice.GetDevicesOfCat(FilterCategory.AudioRendererCategory)[0];
_graph.AddSourceFilterForMoniker(
defaultDirectSound.Mon, null, defaultDirectSound.Name,
out _audioRender);
Run Code Online (Sandbox Code Playgroud)
在这里,我尝试将demux的h264输出引脚连接到ffdshow.此方法调用因AccessViolationException而失败.我不确定如何将这两者连接在一起:(.
注释这一行将导致图形开始运行,尽管图中有一个断开的ffdshowVideoDecoder过滤器,但不会显示任何内容.IntelliConnect将Mpeg2视频输出连接到本地可用的视频解码器,正如我所说,它不会显示任何内容.
// UnsafeConnectFilters(_graph, _mpeg2Demultiplexer, ffdshow, type => type.majorType == MediaType.Video && type.subType == MediaSubType.H264);
Run Code Online (Sandbox Code Playgroud)ConnectFilters 是从directshowlib的DTVViewer样本借来的
ConnectFilters();
Run Code Online (Sandbox Code Playgroud)
我在这里调动了实际调音
tuner.put_TuningSpace(tuningspace);
tuner.put_TuneRequest(request);
Run Code Online (Sandbox Code Playgroud)启动图表并希望显示某些声音或视频
int hr = (_graph as IMediaControl).Run();
DsError.ThrowExceptionForHR(hr);
Run Code Online (Sandbox Code Playgroud)检查图表是否正在运行...
FilterState pfs;
hr = (_graph as IMediaControl).GetState(1000, out pfs);
DsError.ThrowExceptionForHR(hr);
Run Code Online (Sandbox Code Playgroud)
它说图表正在运行.
您是否检查过您的 ffdshow 是否启用了 H264/AVC?打开过滤器属性,在“编解码器”部分中,应启用 H264/AVC 格式(您也可以禁用 Mpeg2 解码器以确保它不喜欢这种格式)。
另一件事,您可以尝试使用另一个 Mpeg2 解复用器。默认的“MPEG-2 解复用器”在不同环境中的行为并不相同。还有许多其他过滤器可以解复用 TS,如果您可以投入一些钱,我建议使用 MainConcept 或 Elecard。
| 归档时间: |
|
| 查看次数: |
2420 次 |
| 最近记录: |