locked
Order of streams in source created using MFCreateAggregateSource RRS feed

  • Question

  • If I combine multiple media sources using MFCreateAggregateSource, is it safe to assume that the streams in the aggregate source will be ordered according to the collection I pass to MFCreateAggregateSource?

    Eg are the stream indices in the aggregate source (guaranteed to be) located at 0, # streams in source 1, # of streams in source 1 + # of streams in source 2, etc?

    If not, what would be the way to find out the source of a stream given that I only have the aggregate source? The application scenario would be multiple audio sources played simultaneously, but I want to direct them to different sinks and need to know which sink receives samples from which source?

    Thanks in advance,
    Christoph


    Tuesday, May 17, 2016 6:42 PM

Answers

  • Hi Christoph

    Yes streams are ordered according to the collection. The stream indices in an Aggregate Source are in the same order you added sources to the collection ( starting from 0 ). Streams are added by index from a source. Streams are always added even if they are not selected/active. To find out if a stream is selected on an Aggregate Source call CreatePresentationDescriptor and then GetStreamDescriptorByIndex.

    -

    Example 1 :

    You have 3 Media Sources, A, B and C. Each source has only one stream. If you add them in alphabetical order to a collection, you will get 3 streams on the Aggregate Source.

    ->

    Stream 0 is Source A ( Stream 0 )

    Stream 1 is Source B ( Stream 0 )

    Stream 2 is Source C ( Stream 0 )

    Example 2 :

    Same Media Sources, but this time B has 2 streams. If you add the sources in alphabetical order to a collection, you will get 4 streams on the Aggregate Source.

    ->

    Stream 0 is Source A ( Stream 0 )

    Stream 1 is Source B ( Stream 0 )

    Stream 2 is Source B ( Stream 1 )

    Stream 3 is Source C ( Stream 0 )

    .

    Its straightforward and guaranteed.

    Regards

    Francis


















    Thursday, May 19, 2016 1:54 PM

All replies

  • Hi Christoph

    Yes streams are ordered according to the collection. The stream indices in an Aggregate Source are in the same order you added sources to the collection ( starting from 0 ). Streams are added by index from a source. Streams are always added even if they are not selected/active. To find out if a stream is selected on an Aggregate Source call CreatePresentationDescriptor and then GetStreamDescriptorByIndex.

    -

    Example 1 :

    You have 3 Media Sources, A, B and C. Each source has only one stream. If you add them in alphabetical order to a collection, you will get 3 streams on the Aggregate Source.

    ->

    Stream 0 is Source A ( Stream 0 )

    Stream 1 is Source B ( Stream 0 )

    Stream 2 is Source C ( Stream 0 )

    Example 2 :

    Same Media Sources, but this time B has 2 streams. If you add the sources in alphabetical order to a collection, you will get 4 streams on the Aggregate Source.

    ->

    Stream 0 is Source A ( Stream 0 )

    Stream 1 is Source B ( Stream 0 )

    Stream 2 is Source B ( Stream 1 )

    Stream 3 is Source C ( Stream 0 )

    .

    Its straightforward and guaranteed.

    Regards

    Francis


















    Thursday, May 19, 2016 1:54 PM
  • I forgot to add that you should always keep indices or identifiers of streams, because it makes life easier when calling all the different stream and presentation descriptor functions. If you have a project/topology with fixed stream count its good to have defines or constants.

    And in case you dont know how to add the source and output nodes :

    For each active/selected stream on an Aggregate source you need to create one source node and one output node. In the example from my first post with the 3 sources A, B , C where B has 2 streams you need to create 4 source and 4 output nodes.

    First call CreatePresentationDescriptor on the Aggregate Source and then for each stream GetStreamDescriptorByIndex. Set the Aggregate Source, the Presentation Descriptor and the Stream Descriptor on each Source node like this.

    ->

    pSourceNode->SetUnknown(MF_TOPONODE_SOURCE, pAggregateSource)

    pSourceNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPresentationDescriptor)

    pSourceNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor)

    <-

    Create an output node for each source ( branch ) node in the topology. Call GetStreamSinkById on a Media Sink and then set the Sink Pointer on the node like this

    ->

    pMediaSink->GetStreamSinkById(streamIdOnTheSink, &pStreamSink)

    pOutputNode->SetObject(pStreamSink)

    <-

    And to connect the nodes always use

    ->

    pSourceNode->ConnectOutput(0, pMFTorSinkNode, 0)

    .

    Example :

    We have 3 Media Sources and 2 Media Sinks ( Archive Sinks ).

    The sources are A, B , C where B has 2 active/selected streams.

    ->

    Source A is Video Source with one stream  ( stream 0 )

    Source B is Audio Source with two streams ( stream 0 and 1 )

    Source C is Audio Source with one stream  ( stream 0 )

    ->

    Stream 0 of Source A is connected to Media Sink 1 ( stream sink 0 )

    Stream 0 of Source B is connected to Media Sink 1 ( stream sink 1 )

    Stream 1 of Source B is connected to Media Sink 2 ( stream sink 1 )

    Stream 0 of Source C is connected to Media Sink 2 ( stream sink 0 )

    ->

    Before we create the nodes we call CreatePresentationDescriptor on the Aggregate Source.

    Now that we have the Presentation Descriptor we create the source and output nodes and set this

    ->

    Source Node 1:

    pPresentationDescriptor->GetStreamDescriptorByIndex(0, &bSelected, &pStreamDescriptor)

    pSourceNode1->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor)

    Output Node 1:

    pMediaSink1->GetStreamSinkById(0, &pStreamSink)

    pOutputNode1->SetObject(pStreamSink)

    Source Node 2:

    pPresentationDescriptor->GetStreamDescriptorByIndex(1, &bSelected, &pStreamDescriptor)

    pSourceNode2->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor)

    Output Node 2:

    pMediaSink1->GetStreamSinkById(1, &pStreamSink)

    pOutputNode2->SetObject(pStreamSink)

    Source Node 3:

    pPresentationDescriptor->GetStreamDescriptorByIndex(2, &bSelected, &pStreamDescriptor)

    pSourceNode3->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor)

    Output Node 3:

    pMediaSink2->GetStreamSinkById(0, &pStreamSink)

    pOutputNode3->SetObject(pStreamSink)

    Source Node 4:

    pPresentationDescriptor->GetStreamDescriptorByIndex(3, &bSelected, &pStreamDescriptor)

    pSourceNode4->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pStreamDescriptor)

    Output Node 4:

    pMediaSink2->GetStreamSinkById(1, &pStreamSink)

    pOutputNode4->SetObject(pStreamSink)

    .

    All code lines in this post are just pseudo code to illustrate the relations between source and output nodes. I would normaly not attach numbers to variables, more likely use a function which takes ID's or numbers as input.

    I hope this helps you to set up your pipeline.

    Regards

    Francis




















    Thursday, May 19, 2016 4:38 PM
  • Thanks. I already have some test code based on this ordering assumption and it is working as you said.

    May I ask whether you know of some MSDN documentation on the ordering or did also you just experience that behaviour? I could not find any note on that in the API docs.

    Also, thanks for your hint on the IDs. I still need to fix that, because I always connected to pin 0 on the source node. I wonder why this is working. Could it be that, given my aggregate source node has one video and one audio stream (there will be more in the future), that the topology can and does resolve the wrong ping automatically?

    Best regards,
    Christoph

    Thursday, May 19, 2016 6:47 PM
  • Sorry, i made a crucial mistake in my second post.

    Its updated now with the correct source node and output node connections. I was just flying over it yesterday without looking closer into my working codes.

    Every stream in an Aggregate Source is one branch ( source to output node connection ). And you always connect nodes with 0

    ->ConnectOutput(0, pSinkorMFTNode, 0)

    There was a side node somehwere in the MSDN documentary about the Aggregate Source and the stream ordering. But its realy hidden as i cant seem to find it right now. Most things came from experience though.

    Regards

    Francis






    Friday, May 20, 2016 7:13 AM
  • Something i also forgot to meantion was why i am using a Stream Sink pointer in my pseudo code rather than a Media Sink.

    pMediaSink->GetStreamSinkById(dwID, &pStreamSink)

    This is of course for when you are building a "Full Topology". When you build a "Partial Topology" you would set the Media Sink pointer instead of the Stream Sink, and then set

    pOutputNode->SetUINT32(MF_TOPONODE_STREAMID, streamID)

    I am mostly building Full Topologies as i am implementing IMFMediaSourceEx a lot and there are design flaws in the Media Session and Topology Resolver API's when you are using a Device Manager.

    The node connections with 0 are still the same though.

    Regards,

    Francis


    Sunday, May 22, 2016 1:11 PM
  • Thanks for adding that hint. I got my stuff running, also using the stream sinks - actually, because I did not know about the MF_TOPONODE_STREAMID thing ...

    Best regards,
    Christoph

    Sunday, May 22, 2016 1:18 PM
  • I am glad i could help.

    From your last post though it seems you might have misunderstood the MF_TOPONODE_STREAMID thing. I would say that 90 % of all developers are building partial topologies so i am wondering how you could fix your code by learning about the MF_TOPONODE_STREAMID attribute. Its actualy an attribute that you would use in 90 % of all developing cases anyway.

    I just added the hint with my last post as i am building rare case full topologies and so i have to "Bind Output Nodes to Media Sinks" myself. To clarify again the 2 ways of binding a sink to an ouput node :

    "Partial Topology":

    pOutputNode->SetObject(pMediaSink)

    pOutputNode->SetUINT32(MF_TOPONODE_STREAMID, streamID)

    "Full Topology": 

    pMediaSink->GetStreamSinkById(streamID, &pStreamSink)

    pOutputNode->SetObject(pStreamSink)

    .

    As said in 90 % of all cases a developer is building a partial topology. Are you sure that you are building a full topology ? The Topology Resolver might take your Stream Sink anyway even if you build a Partial Topology, but its actualy not the correct way. Thats why i want to make it absolutely clear again with this post.

    Regards

    Francis




    Monday, May 23, 2016 7:26 PM
  • Actually, I am not sure about anything I am doing here :-D But I know that I manually connect all the stream sinks, not the media sink - just because the MSDN sample (https://msdn.microsoft.com/de-de/library/windows/desktop/bb250377(v=vs.85).aspx) did it this way. Actually, I was already wondering what the media sink is good for if I need to connect the stream sinks anyway ... Same for the sources:

        hr = ::MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &retval);
        VV3_CHECK_COM_LOG_AND_THROW(hr, _T("Failed to create topology node with ")
            _T("error code 0x%x."), hr);
    
        hr = retval->SetUnknown(MF_TOPONODE_SOURCE, source);
        VV3_CHECK_COM_LOG_AND_THROW(hr, _T("Failed to set media source in ")
            _T("topology node with error code 0x%x."), hr);
    
        hr = retval->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, presDesc);
        VV3_CHECK_COM_LOG_AND_THROW(hr, _T("Failed to set presentation descriptor ")
            _T("in topology node with error code 0x%x."), hr);
    
        hr = retval->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, streamDesc);
        VV3_CHECK_COM_LOG_AND_THROW(hr, _T("Failed to set stream descriptor in ")
            _T("topology node with error code 0x%x."), hr);
    

    It is working somehow ...

    Best regards,
    Christoph

    Tuesday, May 24, 2016 6:31 PM