How to set framerate for IMFSourceReader for webcam capture on Windows 10 laptop

539 views Asked by At

I have seen the other questions but somehow its not working out for me. Environment: Windows 10 MediaFoundation/SourceReader in async mode., Logitech C922 webcam 1080p pro.

Issue:

  1. I am trying to read webcam using media foundation in async mode using sourcereader. I am getting ::OnReadSample() called at 60-65msecs frequency instead of expected 33.33msecs for 30fps.

  2. Verified by

hr = m_pReader->GetCurrentMediaType(
            (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
            &pType
            );

and printing attributes for pType that MF_MT_FRAME_RATE is 30 x 1. Both MIN and MAX RANGE are also 30 x 1.

  1. Verified in ::OnReadSample() callback as well that Mediatype is same. The streamflags are not set for MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED bit. So currentmediatype hasn't changed internally.
hr = m_pReader->GetCurrentMediaType(
                (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
                &pt
                );
  1. I had set the fps even using https://learn.microsoft.com/en-us/windows/win32/medfound/how-to-set-the-video-capture-frame-rate the exact function on above page but still its getting called every 64msecs or so. Below is snapshot of the pType that is being used.
MF_MT_FRAME_SIZE    640 x 480
MF_MT_AVG_BITRATE   147456000
MF_MT_YUV_MATRIX    2
MF_MT_MAJOR_TYPE    MFMediaType_Video
MF_MT_VIDEO_LIGHTING    3
MF_MT_DEFAULT_STRIDE    1280
MF_MT_VIDEO_CHROMA_SITING   6
MF_MT_AM_FORMAT_TYPE    {F72A76A0-EB0A-11D0-ACE4-0000C0CC16BA}
MF_MT_FIXED_SIZE_SAMPLES    1
MF_MT_VIDEO_NOMINAL_RANGE   2
MF_MT_FRAME_RATE    30 x 1
MF_MT_PIXEL_ASPECT_RATIO    1 x 1
MF_MT_ALL_SAMPLES_INDEPENDENT   1
MF_MT_FRAME_RATE_RANGE_MIN  30 x 1
MF_MT_SAMPLE_SIZE   614400
MF_MT_VIDEO_PRIMARIES   2
MF_MT_INTERLACE_MODE    2
MF_MT_FRAME_RATE_RANGE_MAX  30 x 1
MF_MT_SUBTYPE   MFVideoFormat_YUY2

Please suggest what might be missing in such case. I am sort of getting 15fps instead of 30fps that is being requested. I have enumerated media types of the device and it supports 30fps.

Thanks in advance.

1

There are 1 answers

1
sipsorcery On

It's likely to be because you are setting the adjusted media type on the IMFSourceReader instead of the handler for the IMFMediaSource.

A snippet from a full working example is shown below. Note the tailored media type is being set on pSourceMediaTypeHandler and not pVideoReader. See the example source code for the variable declarations etc.

// ----- Set up webcam video source. -----

CHECK_HR(GetVideoSourceFromDevice(WEBCAM_DEVICE_INDEX, &pVideoSource, &pVideoReader),
"Failed to get webcam video source.");

CHECK_HR(pVideoReader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, TRUE),
"Failed to set the first video stream on the source reader.");

CHECK_HR(pVideoSource->CreatePresentationDescriptor(&pSourcePresentationDescriptor),
"Failed to create the presentation descriptor from the media source.");

CHECK_HR(pSourcePresentationDescriptor->GetStreamDescriptorByIndex(0, &fSelected, &pSourceStreamDescriptor),
"Failed to get source stream descriptor from presentation descriptor.");

CHECK_HR(pSourceStreamDescriptor->GetMediaTypeHandler(&pSourceMediaTypeHandler),
"Failed to get source media type handler.");

DWORD srcMediaTypeCount = 0;
CHECK_HR(pSourceMediaTypeHandler->GetMediaTypeCount(&srcMediaTypeCount),
"Failed to get source media type count.");

// ----- Attempt to set the desired media type on the webcam source. -----

CHECK_HR(MFCreateMediaType(&pWebcamSourceType), "Failed to create webcam output media type.");

CHECK_HR(FindMatchingVideoType(pSourceMediaTypeHandler, WEBCAM_PIXEL_FORMAT, VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_FRAME_RATE, pWebcamSourceType),
"No matching webcam media type was found.");

// This check is not necessary if the media type was from the list of supported types.
// It is useful if the media type is constructed manually. It is left here for demonstration purposes. 
CHECK_HR(pSourceMediaTypeHandler->IsMediaTypeSupported(pWebcamSourceType, &pWebCamMatchingType), "Webcam does not support requested options.");

if (pWebCamMatchingType != NULL) {
// If IsMediaTypeSupported supplied us with the closest matching media type use that.
CHECK_HR(pSourceMediaTypeHandler->SetCurrentMediaType(pWebCamMatchingType), "Failed to set media type on source.");
}
else {
// If IsMediaTypeSupported did not supply us a new type the typ checked must have been good enough use that.
CHECK_HR(pSourceMediaTypeHandler->SetCurrentMediaType(pWebcamSourceType), "Failed to set media type on source.");
}

CHECK_HR(pSourceMediaTypeHandler->GetCurrentMediaType(&pVideoSourceOutputType),
"Error retrieving current media type from first video stream.");

std::cout << "Webcam media type:" << std::endl;
std::cout << GetMediaTypeDescription(pVideoSourceOutputType) << std::endl << std::endl;

I used that example to confirm I was able to set the frame rate on my Logitech C920 to 5fps and the get the correct sampling rate in the source reader loop.

Attempting to convert sample, sample duration 2000000, sample time 863168227222, evr timestamp 0.
Attempting to convert sample, sample duration 2000000, sample time 863170145312, evr timestamp 2000000.
Attempting to convert sample, sample duration 2000000, sample time 863172227244, evr timestamp 4000000.
Attempting to convert sample, sample duration 2000000, sample time 863174144901, evr timestamp 6000000.
Attempting to convert sample, sample duration 2000000, sample time 863176225938, evr timestamp 8000000.
Attempting to convert sample, sample duration 2000000, sample time 863178147388, evr timestamp 10000000.
Attempting to convert sample, sample duration 2000000, sample time 863180225543, evr timestamp 12000000.