Search code examples
c++ms-media-foundationtopology

Determine resolved input type of IMFSampleGrabberSinkCallback


I have an IMFSampleGrabberSinkCallback in my Media Foundation application, which I create an activator for using MFCreateSampleGrabberSinkActivate. The function receives only a partially filled media type. Within the sample grabber callback, an NVENC encoder is running (I know that there are out-of-the-box transforms for NVENC, but the software is not running on Windows 10). In order to use the encoder, I need to have the full media type that after topology resolution (mainly the size of the frames, which is not known when the sample grabber is created).

There seems to be no obvious way to obtain this information in the IMFSampleGrabberSinkCallback, so the idea would be getting the full topology from the session once I receive MF_TOPOSTATUS_READY.

First question: Is this the only way to get the full type the grabber will receive or did I miss something?

After getting the full topology, the idea is iterating all nodes, searching the one with the sample grabber and retrieving its input type.

Second question: What would be the best way of doing that? For me, there seems to be no way to retrieve my IMFSampleGabberSinkCallback from the topology node.

I would solve that using the topo node ID, but I am not sure whether this would work in any case. The documentation of IMFTopologyNode::GetTopoNodeID states that

When a node is first created, it is assigned an identifier. Node identifiers are unique within a topology, but can be reused across several topologies. The topology loader uses the identifier to look up nodes in the previous topology, so that it can reuse objects from the previous topology.

To me, it is not clear whether the ID will be reused or whether it can be reused.

Third question: Is it guaranteed that, if I obtain the topo node ID of the node I insert my IMFActivate obtained from MFCreateSampleGrabberSinkActivate (and as long as I do not change the ID manually using IMFTopologyNode::SetTopoNodeID, the very same ID will be used for any subsequent topology created during the topology resolution process?

Thanks in advance, Christoph

Edit: The question is not on how to get NVENC working and resolve its input type, but the key questions are (1) whether the topo IDs are guaranteed to be preserved during the resolution process and (2) whether there is a better way to do that than the following (which is susceptible to users actively changing the topo ID): First, I create an activator for my grabber callback. Once I have added the node containing the activator as object to the topology, I retrieve its ID. When the session reports that the topology is ready, I retrieve the node with the ID saved before, obtain its object, query its IMFStreamSink interface, retrieve its IMFMediaTypeHandler, get the current media type and obtain the actual frame size and frame rate for NVENC. But: This only works if the ID cannot change and is not actively changed.

I have extracted the topology resolution stages from my test code:

Topology resolution stages

The topology resolver finds out that a colour conversion is required and adds the blue transform to account for this. Coming back to the questions: In this case, they would be (1) whether it is guaranteed that the ID of the red node cannot change during resolution and (2) whether there is an alternative way to implement this which is not susceptible to someone using IMFTopologyNode::SetTopoNodeID on the red node.


Solution

  • From my experience ID of Topology Node looks like result of hash function. I think that generator of ID has complex algorithm and it cannot guaranty constant from one session to other, but ID is stable during current session. Maybe you can try another way - your wrote - "have added the node containing the activator as object to the topology," but what do you do with original pointer on "an activator for my grabber callback"? IMFTopologyNode::SetObject increments reference of IUnknown. I think you release original pointer an activate, but you
    can keep pointer on on "an activator for my grabber callback". In that case there is not need - "I retrieve the node with the ID saved before, obtain its object,". After resolving of topology you ALREADY can have pointer on activator with full resolved MediaType and query its IMFStreamSink interface, retrieve its IMFMediaTypeHandler without saving ID of topology node. Activator is proxy, but for IMFMediaSink object, which is gotten by calling of IMFActivate::ActivateObject with IID_IMFMediaSink. While it is called first time by topology resolving it creates object with IMFMediaSink interface (which creates the IMFStreamSink with IMFSampleGabberSinkCallback inner itself) in activator, but the next calling will return reference - Activator KEEPS reference on resolved IMFMediaSink - according to MSDN MFActivate::ActivateObject - "After the first call to ActivateObject, subsequent calls return a pointer to the same instance, until the client calls either ShutdownObject or IMFActivate::DetachObject." It means that after resolving of topology Microsoft's code DOES NOT detach object or shutdown it - only close session execute ShutdownObject or IMFActivate::DetachObject.

    Regards