Источник веб-камеры в приемник EVR - PullRequest
1 голос
/ 06 января 2020

Я могу отображать видеопоток из видео в формате mp4, записывая сэмплы байтов непосредственно в приемник Enhanced Video Renderer (EVR) (благодаря ответу на Media Foundation EVR без отображения видео ).

Я бы хотел сделать то же самое, но для источника с веб-камеры. Текущая проблема, с которой я столкнулся, заключается в том, что моя веб-камера поддерживает только форматы RGB24 и I420, и, насколько я могу судить, EVR поддерживает только RGB32. В некоторых сценариях Media Foundation ios Я полагаю, что преобразование произойдет автоматически, если в процессе зарегистрирован класс CColorConvertDMO. Я сделал это, но я подозреваю, что из-за того, как я записываю сэмплы в EVR, преобразование цвета не вызывается.

Мой вопрос заключается в том, какой подход я должен использовать, чтобы разрешить чтение сэмплов RGB24 из моя веб-камера IMFSourceReader, чтобы разрешить запись в EVR IMFStreamSink?

Моя полная программа примера здесь и, к сожалению, довольно длинная из-за необходимости установки сантехнического фундамента Media Foundation. Ниже приведен блок, в котором я пытаюсь сопоставить тип носителя EVR-приемника с типом носителя веб-камеры.

Проблема заключается в установке атрибута MF_MT_SUBTYPE. Из того, что я могу сказать, tt должно быть MFVideoFormat_RGB32 для EVR, но моя веб-камера будет принимать только MFVideoFormat_RGB24.

IMFMediaSource* pVideoSource = NULL;
IMFSourceReader* pVideoReader = NULL;
IMFMediaType* videoSourceOutputType = NULL, * pvideoSourceModType = NULL;
IMFMediaType* pVideoOutType = NULL;
IMFMediaType* pHintMediaType = NULL;
IMFMediaSink* pVideoSink = NULL;
IMFStreamSink* pStreamSink = NULL;
IMFSinkWriter* pSinkWriter = NULL;
IMFMediaTypeHandler* pSinkMediaTypeHandler = NULL, * pSourceMediaTypeHandler = NULL;
IMFPresentationDescriptor* pSourcePresentationDescriptor = NULL;
IMFStreamDescriptor* pSourceStreamDescriptor = NULL;
IMFVideoRenderer* pVideoRenderer = NULL;
IMFVideoDisplayControl* pVideoDisplayControl = NULL;
IMFGetService* pService = NULL;
IMFActivate* pActive = NULL;
IMFPresentationClock* pClock = NULL;
IMFPresentationTimeSource* pTimeSource = NULL;
IDirect3DDeviceManager9* pD3DManager = NULL;
IMFVideoSampleAllocator* pVideoSampleAllocator = NULL;
IMFSample* pD3DVideoSample = NULL;
RECT rc = { 0, 0, VIDEO_WIDTH, VIDEO_HEIGHT };
BOOL fSelected = false;

CHECK_HR(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE),
"COM initialisation failed.");

CHECK_HR(MFStartup(MF_VERSION),
"Media Foundation initialisation failed.");

//CHECK_HR(ListCaptureDevices(DeviceType::Video), 
//  "Error listing video capture devices.");

// Need the color converter DSP for conversions between YUV, RGB etc.
CHECK_HR(MFTRegisterLocalByCLSID(
__uuidof(CColorConvertDMO),
MFT_CATEGORY_VIDEO_PROCESSOR,
L"",
MFT_ENUM_FLAG_SYNCMFT,
0,
NULL,
0,
NULL),
"Error registering colour converter DSP.");

// Create a separate Window and thread to host the Video player.
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)InitializeWindow, NULL, 0, NULL);
Sleep(1000);
if (_hwnd == nullptr)
{
printf("Failed to initialise video window.\n");
goto done;
}

if (_hwnd == nullptr)
{
printf("Failed to initialise video window.\n");
goto done;
}

// ----- Set up Video sink (Enhanced Video Renderer). -----

CHECK_HR(MFCreateVideoRendererActivate(_hwnd, &pActive),
"Failed to created video rendered activation context.");

CHECK_HR(pActive->ActivateObject(IID_IMFMediaSink, (void**)&pVideoSink),
"Failed to activate IMFMediaSink interface on video sink.");

// Initialize the renderer before doing anything else including querying for other interfaces,
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms704667(v=vs.85).aspx.
CHECK_HR(pVideoSink->QueryInterface(__uuidof(IMFVideoRenderer), (void**)&pVideoRenderer),
"Failed to get video Renderer interface from EVR media sink.");

CHECK_HR(pVideoRenderer->InitializeRenderer(NULL, NULL),
"Failed to initialise the video renderer.");

CHECK_HR(pVideoSink->QueryInterface(__uuidof(IMFGetService), (void**)&pService),
"Failed to get service interface from EVR media sink.");

CHECK_HR(pService->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (void**)&pVideoDisplayControl),
"Failed to get video display control interface from service interface.");

CHECK_HR(pVideoDisplayControl->SetVideoWindow(_hwnd),
"Failed to SetVideoWindow.");

CHECK_HR(pVideoDisplayControl->SetVideoPosition(NULL, &rc),
"Failed to SetVideoPosition.");

CHECK_HR(pVideoSink->GetStreamSinkByIndex(0, &pStreamSink),
"Failed to get video renderer stream by index.");

CHECK_HR(pStreamSink->GetMediaTypeHandler(&pSinkMediaTypeHandler),
"Failed to get media type handler for stream sink.");

DWORD sinkMediaTypeCount = 0;
CHECK_HR(pSinkMediaTypeHandler->GetMediaTypeCount(&sinkMediaTypeCount),
"Failed to get sink media type count.");

std::cout << "Sink media type count: " << sinkMediaTypeCount << "." << std::endl;

// ----- Set up Video source (is either a file or webcam capture device). -----

#if USE_WEBCAM_SOURCE
CHECK_HR(GetVideoSourceFromDevice(WEBCAM_DEVICE_INDEX, &pVideoSource, &pVideoReader),
"Failed to get webcam video source.");
#else
CHECK_HR(GetVideoSourceFromFile(MEDIA_FILE_PATH, &pVideoSource, &pVideoReader),
"Failed to get file video source.");
#endif

CHECK_HR(pVideoReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &videoSourceOutputType),
"Error retrieving current media type from first video stream.");

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.");

std::cout << "Source media type count: " << srcMediaTypeCount << ", is first stream selected " << fSelected << "." << std::endl;
std::cout << "Default output media type for source reader:" << std::endl;
std::cout << GetMediaTypeDescription(videoSourceOutputType) << std::endl << std::endl;

// ----- Create a compatible media type and set on the source and sink. -----

// Set the video input type on the EVR sink.
CHECK_HR(MFCreateMediaType(&pVideoOutType), "Failed to create video output media type.");
CHECK_HR(pVideoOutType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), "Failed to set video output media major type.");
CHECK_HR(pVideoOutType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), "Failed to set video sub-type attribute on media type.");
CHECK_HR(pVideoOutType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive), "Failed to set interlace mode attribute on media type.");
CHECK_HR(pVideoOutType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE), "Failed to set independent samples attribute on media type.");
CHECK_HR(MFSetAttributeRatio(pVideoOutType, MF_MT_PIXEL_ASPECT_RATIO, 1, 1), "Failed to set pixel aspect ratio attribute on media type.");
CHECK_HR(CopyAttribute(videoSourceOutputType, pVideoOutType, MF_MT_FRAME_SIZE), "Failed to copy video frame size attribute to media type.");
CHECK_HR(CopyAttribute(videoSourceOutputType, pVideoOutType, MF_MT_FRAME_RATE), "Failed to copy video frame rate attribute to media type.");

//CHECK_HR(GetSupportedMediaType(pMediaTypeHandler, &pVideoOutType),
//  "Failed to get supported media type.");

std::cout << "Custom media type defined as:" << std::endl;
std::cout << GetMediaTypeDescription(pVideoOutType) << std::endl << std::endl;

auto doesSinkSupport = pSinkMediaTypeHandler->IsMediaTypeSupported(pVideoOutType, &pHintMediaType);
if (doesSinkSupport != S_OK) {
std::cout << "Sink does not support desired media type." << std::endl;
goto done;
}
else {
CHECK_HR(pSinkMediaTypeHandler->SetCurrentMediaType(pVideoOutType),
  "Failed to set input media type on EVR sink.");
}

// The block below returnedalways failed furing testing. My guess is the source media type handler
// is not aligned with the video reader somehow.
/*auto doesSrcSupport = pSourceMediaTypeHandler->IsMediaTypeSupported(pVideoOutType, &pHintMediaType);
if (doesSrcSupport != S_OK) {
std::cout << "Source does not support desired media type." << std::endl;
goto done;
}
else {
CHECK_HR(pSourceMediaTypeHandler->SetCurrentMediaType(pVideoOutType),
  "Failed to set output media type on source reader.");
}*/

CHECK_HR(pVideoReader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pVideoOutType),
"Failed to set output media type on source reader.");

// ----- Source and sink now configured. Set up remaining infrastructure and then start sampling. -----

Ответы [ 2 ]

1 голос
/ 10 января 2020

Source Reader обычно может выполнить это преобразование: RGB24 -> RGB32.

, насколько я могу судить, EVR поддерживает только RGB32

Не совсем это зависит только от вашего видеопроцессора: mofo7777 / Stackoverflow

В рамках проекта MFVideoEVR замените все MFVideoFormat_RGB32 на MFVideoFormat_NV12, он должен работать с графической картой NVidia. Изменить сон (20); со сном (40); в Main. cpp (HRESULT DisplayVideo (...)), поскольку использование формата NV12 более оптимизировано (значение для частоты кадров видео 25 кадров в секунду).

По вашему вопросу:

Вы можно сделать это без ручки преобразования цвета MFT. От MFVideoEVR, две вещи для обновления:

  • Настройка источника захвата видео вместо источника видеофайла
  • Ручная обработка времени выборки, поскольку время выборки захвата является неточным

Исходный код здесь: mofo7777 / Stackoverflow

В рамках проекта MFVideoCaptureEVR.

0 голосов
/ 07 января 2020

Мне нужно было вручную подключить преобразование цветов MFT (я уверен, что некоторые сценарии Media Foundation ios подключить его автоматически, но, вероятно, только при использовании топологии) И отрегулировать часы, установленные в образце Direct3D IMFS, предоставленном для EVR.

Рабочая пример .

...