Learning (painfully) how to use the Topology and Session to present a captured video. Nothing fancy - just select a web cam, list its modes, choose a video format and hit "go". In general these are the steps I'm taking to present the video capture:
MFEnumDeviceSources()
filtered by MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
and let user select oneGetStreamDescriptorCount()
after activating the source and creating Presentation Descriptors with CreatePresentationDescriptor()
and let the user select a stream (if multiple streams are available)IMFMediaType
s available through GetMediaTypeByIndex()
and let the user choose oneOnce the exact format is selected I build the Topology this way:
MFCreateTopology()
to create a new IMFTopology
objectMFCreateVideoRendererActivate()
SetCurrentMediaType()
on the IMFMediaTypeHandler
object of the currently selected IMFStreamDescriptor
MFCreateTopologyNode()
, setting its presentation and stream descriptors with the call to SetUnknown()
and adding that node to the Topology
IMFMediaType
to the one chosen by user with SetCurrentMediaType()
SetObject()
of it providing the previously created media sink activation object (from step 5 above)ConnectOutput()
providing it with the node ID 0
When the "preview" button is clicked a session IMFMediaSession
object (created at the app's startup) is set with the new Topology
m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, pTopo);
And this is where I see something strange. I set the size of the preview video based on the frame dimensions provided by the IMFMediaType
that the user chose and the source seems to be producing the video in that format. However the renderer is handling the pixel aspect ratio incorrectly and is letterboxing/pillarboxing the video while presenting the picture as being stretched either vertically of horizontally.
For the life of me I am unable to find the way to tell the renderer to adjust for the proper pixel aspect ratio (which was set to the proper value in step 5.1 above)
The MS's SDK example only shows how to present captured video for uncompressed formats - it doesn't use the IMFMediaSession
object and works fine for the YUV2
format but not for the MJPG
. In fact it worked so well that I thought moving onto using the session would be easy :)
Using the IMFMediaSession
seems to be the least cumbersome way of supporting compressed video formats, especially the H.264
that's in the newer UVC 1.5
standard and any new (H.265
?) formats that are coming up in the future.
Further research has shown that one can access the renderer object by querying the session to get the service and then use that service to get the video display control. That IMFVideoDisplayControl
is the object that lets you control various aspects of the rendered video, including the aspect ratio of the image.
Here's how to get to that IMFVideoDisplayControl
object:
get the IMFGetService
:
hr = m_session->QueryInterface<IMFGetService>(&service);
get the IMFVideoDisplayControl
:
hr = service->GetService(MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl, (void**)&control);
Once you have the display control object you can achieve the rest. In my case (since I knew the actual true geometry of the expected video) the solution was to set the aspect ratio mode to MFVideoARMode_None