如何确定引脚是否可以连接?

时间:2012-11-29 10:44:43

标签: .net vb.net directshow directshow.net media-type

目前,我正在开发基于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总是返回-2147467259The 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,而没有模拟视频引脚。

2 个答案:

答案 0 :(得分:1)

要检查引脚是否可以连接,您需要尝试连接它们。但是,“通常”连接方法IGraphBuilder::Connect包括所谓的智能连接,它开始尝试在中间插入其他过滤器。如果您不想这样,则使用IGraphBuilder::ConnectDirect方法。不要直接调用IPin::Connect:虽然它可能运行正常,但不应该直接调用,ConnectDirect会为你调用它。

请注意,对于ConnectDirect,您还要提供媒体类型。空媒体类型可能会运行,或者您可能想尝试在输出引脚上枚举的那些。基本上,这是默认行为:输出引脚将尝试作为参数提供的媒体类型(如果不为空),然后尝试自己的,然后尝试通过对等输入引脚枚举的那些,然后智能连接开始工作(除非它是ConnectDirect呼叫)。

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

此外,-21474672590x80004005 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