0

目前我正在开发基于 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. 文档没有提到这样的返回值。经过更多调查,我发现QueryAccept它用于提出新的 MediaType,所以我假设 QueryAccept 仅在调用引脚已连接时才有效。在这里阅读更多

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在没有模拟视频引脚时使用。

4

2 回答 2

1

要检查是否可以连接引脚,您需要尝试连接它们。但是,“通常”的连接方法IGraphBuilder::Connect包括所谓的智能连接,它开始尝试在中间插入额外的过滤器。如果你不想要这个,你有IGraphBuilder::ConnectDirect方法。不要IPin::Connect直接调用:虽然它可能工作得很好,但不应该直接调用它,而是 ConnectDirect 为您调用它。

请注意,对于 ConnectDirect,您还需要提供媒体类型。空媒体类型可能会奏效,或者您可能想尝试从输出引脚上枚举的那些。基本上,这首先是默认行为:输出 pin 将尝试作为参数提供的媒体类型(如果不是 null),然后尝试自己的,然后尝试由对等输入 pin 枚举的那些,然后 Intelligent Connect 开始工作(除非它是ConnectDirect 呼叫)。

所有RenderStream和朋友都是上面提到的包装器。

另外,-21474672590x80004005 E_FAIL“未指定的错误”

于 2012-11-30T07:41:00.430 回答
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
于 2012-11-29T13:40:03.873 回答