目前,我正在开发基于DirectShow的应用程序来配置电视采集卡。它应该与大多数捕获卡一起使用,所以它必须尽可能通用。
由于大多数采集卡制造商似乎提出了不同的配置方式,我的应用程序将尝试分析相关的滤波器及其引脚。一个常见的是检查某个引脚是否可以直接连接到渲染器,或者它首先需要编码器/多路复用器。
注意:我正在使用带有VB.NET的DirectShow .NET库,但如果您愿意,可以使用C#或C ++进行回答。
我尝试使用以下函数检查输出引脚是否接受某个AMMediaType
:
Private Function Check1(filter As IBaseFilter, type As AMMediaType) As Boolean
Dim enumPins As IEnumPins = Nothing
If filter.EnumPins(enumPins) = 0 Then
Dim pin(0) As IPin
While (enumPins.Next(1, pin, Nothing) = 0)
Dim accepted As Boolean = (pin(0).QueryAccept(type) = 0)
Marshal.ReleaseComObject(pin(0))
If accepted Then Return True
End While
End If
Return False
End Function
此函数始终返回False
。经过一些调试后,我发现QueryAccept
总是返回-2147467259
。 The documentation未提及此类返回值。经过一番调查,我发现QueryAccept
用于提出一个新的MediaType,所以我假设QueryAccept仅在调用引脚已连接时才有效。 Read more here
我可以使用以下函数检查输出引脚是否优先选择某个AMMediaType
:
Private Function Check2(filter As IBaseFilter, type As AMMediaType) As Boolean
Dim enumPins As IEnumPins = Nothing
If filter.EnumPins(enumPins) = 0 Then
Dim pin(0) As IPin
While (enumPins.Next(1, pin, Nothing) = 0)
Dim enumMediaTypes As IEnumMediaTypes = Nothing
If pin(0).EnumMediaTypes(enumMediaTypes) = 0 Then
Dim mediaType(0) As AMMediaType
While (enumMediaTypes.Next(1, mediaType, Nothing) = 0)
Dim equals As Boolean = (type Is Nothing OrElse
(type.majorType = Nothing OrElse mediaType(0).majorType = type.majorType) AndAlso
(type.subType = Nothing OrElse mediaType(0).subType = type.subType) AndAlso
(type.formatType = Nothing OrElse mediaType(0).formatType = type.formatType))
DsUtils.FreeAMMediaType(mediaType(0))
If equals Then
Return True
End If
End While
End If
End While
End If
Return False
End Function
通过枚举EnumMediaTypes
,我可以确定某个AMMediaType
是否列为首选。但是,这并不能保证我可以建立连接。通常有一些类型不包含在此枚举中,但仍可用于连接。有时这个枚举是空的。
我正在搜索的是确定过滤器是否可以直接连接到另一个过滤器,或者它应该首先连接到编码器/多路复用器的方法。有人知道我怎么能做到这一点吗?
注意:只是连接过滤器并使用返回值来确定它是否成功,不是一个选项。根据我的经验,ICaptureGraphBuilder::RenderStream经常返回S_OK
而没有建立连接。例如,尝试使用MediaType.AnalogVideo
,而没有模拟视频引脚。
答案 0 :(得分:1)
要检查引脚是否可以连接,您需要尝试连接它们。但是,“通常”连接方法IGraphBuilder::Connect
包括所谓的智能连接,它开始尝试在中间插入其他过滤器。如果您不想这样,则使用IGraphBuilder::ConnectDirect
方法。不要直接调用IPin::Connect
:虽然它可能运行正常,但不应该直接调用,ConnectDirect会为你调用它。
请注意,对于ConnectDirect,您还要提供媒体类型。空媒体类型可能会运行,或者您可能想尝试在输出引脚上枚举的那些。基本上,这是默认行为:输出引脚将尝试作为参数提供的媒体类型(如果不为空),然后尝试自己的,然后尝试通过对等输入引脚枚举的那些,然后智能连接开始工作(除非它是ConnectDirect呼叫)。
所有RenderStream
和朋友都是上面提到的包装。
此外,-2147467259
为0x80004005
E_FAIL
"Unspecified error"。
答案 1 :(得分:0)
而不是ICaptureGraphBuilder::RenderStream,我最终使用IGraphBuilder::Connect,但仅用于检查连接是否可行。连接过滤器后,以下函数会立即断开过滤器的连接,并使用HRESULT确定连接是否成功:
Private Function Check3(graph As IGraphBuilder, filterOut As IBaseFilter, filterIn As IBaseFilter, type As AMMediaType) As Boolean
Dim result As Boolean
' Enumerate output pins
Dim enumPinsOut As IEnumPins = Nothing
If filterOut.EnumPins(enumPinsOut) = 0 Then
Dim pinOut(0) As IPin
While enumPinsOut.Next(1, pinOut, Nothing) = 0
' Enumerate output media types
Dim enumMediaTypes As IEnumMediaTypes = Nothing
If pinOut(0).EnumMediaTypes(enumMediaTypes) = 0 Then
Dim mediaType(0) As AMMediaType
While enumMediaTypes.Next(1, mediaType, Nothing) = 0
' Compare media types
If type Is Nothing OrElse
(type.majorType = Nothing OrElse type.majorType = mediaType(0).majorType) AndAlso
(type.subType = Nothing OrElse type.subType = mediaType(0).subType) AndAlso
(type.formatType = Nothing OrElse type.formatType = mediaType(0).formatType) Then
' Enumerate input pins
Dim enumPinsIn As IEnumPins = Nothing
If filterIn.EnumPins(enumPinsIn) = 0 Then
Dim pinIn(0) As IPin
While enumPinsIn.Next(1, pinIn, Nothing) = 0
' Evaluate connection return value
Dim hr As Integer = graph.Connect(pinOut(0), pinIn(0))
graph.Disconnect(pinOut(0))
result = (hr = 0)
If result = False Then Console.WriteLine(DsError.GetErrorText(hr))
Marshal.ReleaseComObject(pinIn(0))
If result = True Then Exit While
End While
End If
End If
DsUtils.FreeAMMediaType(mediaType(0))
If result = True Then Exit While
End While
End If
Marshal.ReleaseComObject(pinOut(0))
If result = True Then Exit While
End While
End If
Return result
End Function