Как установить частоту кадров для IMFSourceReader для захвата веб-камеры на ноутбуке с Windows 10

Я видел другие вопросы, но у меня почему-то не получается. Среда: Windows 10 MediaFoundation/SourceReader в асинхронном режиме, веб-камера Logitech C922 1080p pro.

Проблема:

  1. Я пытаюсь прочитать веб-камеру, используя медиа-фонд в асинхронном режиме, используя sourcereader. Я получаю вызов ::OnReadSample() с частотой 60-65 мс вместо ожидаемых 33,33 мс для 30 кадров в секунду.

  2. Проверено

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

и атрибуты печати для pType, что MF_MT_FRAME_RATE равно 30 x 1. И MIN, и MAX RANGE также имеют размер 30 x 1.

  1. В обратном вызове ::OnReadSample() также проверено, что Mediatype такой же. Флаги потока не установлены для MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED бита. Таким образом, currentmediatype не изменился внутри.
hr = m_pReader->GetCurrentMediaType(
                (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 
                &pt
                );
  1. Я установил частоту кадров даже с помощью https://docs.microsoft.com/en-us/windows/win32/medfound/how-to-set-the-video-capture-frame-rate точная функция на странице выше но все же его вызывают каждые 64 мс или около того. Ниже приведен снимок используемого pType.
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

Пожалуйста, подскажите, чего может не хватать в таком случае. Я как бы получаю 15 кадров в секунду вместо 30 кадров в секунду, которые запрашиваются. Я перечислил типы носителей устройства, и оно поддерживает 30 кадров в секунду.

Заранее спасибо.


person user3355620    schedule 13.10.2020    source источник
comment
Камера может производить меньше кадров в условиях низкой освещенности. Попробуйте навести его на какое-нибудь яркое место, чтобы исключить это для начала.   -  person Roman R.    schedule 13.10.2020
comment
@РоманР. Большое спасибо. Ты прав. Действительно, это было проблемой. Когда я тестировал в ярком солнечном месте, я действительно получал кадры каждые 32-33 мс. Это было моим ожиданием. Есть идеи, как добиться 30 кадров в секунду даже в условиях низкой освещенности?   -  person user3355620    schedule 13.10.2020
comment
Я не думаю, что вы можете заблокировать затвор / экспозицию на таком устройстве. Вам нужна специализированная камера, где есть такая возможность. То, что вы видите, — это расширенная экспозиция, которая делает невозможным полную частоту кадров. Когда вы добавляете свет и заставляете камеру сокращать время выдержки отдельных кадров, она может сделать целых 30.   -  person Roman R.    schedule 13.10.2020


Ответы (1)


Вероятно, это связано с тем, что вы устанавливаете скорректированный тип носителя для IMFSourceReader вместо обработчика для IMFMediaSource.

Фрагмент полного рабочего примера показан ниже. . Обратите внимание, что настроенный тип носителя устанавливается на pSourceMediaTypeHandler, а не на pVideoReader. См. пример исходного кода для объявлений переменных и т. д.

// ----- 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;

Я использовал этот пример, чтобы подтвердить, что мне удалось установить частоту кадров на моем Logitech C920 на 5 кадров в секунду и получить правильную частоту дискретизации в цикле чтения исходного кода.

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.
person sipsorcery    schedule 13.10.2020
comment
Спасибо за ваш ответ. пожалуйста, попробуйте более высокий fps, скажем, 30fps, и наблюдайте то же самое. Как Роман. R, мой тот же код без каких-либо изменений дает 15 кадров в секунду в условиях низкой освещенности и 30 кадров в секунду при хорошем освещении. Таким образом, кажется, что веб-камера не имеет постоянной частоты кадров, но также зависит от условий освещения. Спасибо - person user3355620; 15.10.2020