Question

Currently I'm working on a DirectShow based application for configuring TV capture cards. It's supposed to work with most of the capture cards out there, so it has to be as generic as possible.

Since most capture card manufacturers seem to come up with different ways of configuration, my application will try to analyse the related filters and their pins. One common is checking if a certain pin can be connected to a renderer directly, or it needs an encoder/mux first.

Note: I am using the DirectShow .NET library with VB.NET, but you can answer in C# or C++ if you like.

I tried checking if the output pin accepts a certain AMMediaType with the following function:

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

This function always returns False. After some debugging I found out that QueryAccept always returns -2147467259. The documentation does not mention such return value. After some more investigation, I found out QueryAccept is used for proposing a new MediaType, so I assume QueryAccept only works when the calling pin is already connected. Read more here.

I can check if a certain AMMediaType is preferred by the output pin using the function below:

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

By enumerating EnumMediaTypes, I can determine if a certain AMMediaType is listed as preferred. This, however, does not assure me that a connection is possible. Often there are types that are not contained by this enumeration, but can still be used to connect. Sometimes this enumeration is empty.

What I'm searching for is a way to determine if a filter can be connected to another filter directly, or it should connect to an encoder/mux first. Does someone know how I can achieve this?

Note: Simply connecting the filters and using the return value to determine if it was succesful, is not an option. In my experience, ICaptureGraphBuilder::RenderStream often returns S_OK while no connection was made. For example, try using MediaType.AnalogVideo while there is no analog video pin.

Was it helpful?

Solution 2

Instead of ICaptureGraphBuilder::RenderStream, I ended up using IGraphBuilder::Connect, but only for checking if a connection is possible. After connecting the filters, the following function immediately disconnects the filters, and uses the HRESULT to determine if the connection was succesful:

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

OTHER TIPS

To check if pins can be connected you need to try to connect them. However, the "usual" connection method IGraphBuilder::Connect includes so called Intelligent Connect, which starts trying to insert additional filters in the middle. If you don't want this, you have IGraphBuilder::ConnectDirect method. Don't call IPin::Connect directly: though it might work out fine, it is not supposed to be called directly, ConnectDirect calls it for you instead.

Note that for ConnectDirect you are also to provide a media type. Null media type might work out, or you might want to try those from enumerated on output pin. Basically, this is the default behavior in first place: output pin would try media type provided as argument (if not null), then try its own, then it tries those enumerated by peer input pin, then Intelligent Connect starts working (unless it is ConnectDirect call).

All RenderStream and friends are wrappers on top of mentioned.

Also, -2147467259 is 0x80004005 E_FAIL "Unspecified error".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top