Обратный вызов Microsoft Media Foundation / UVC ReadSample () - PullRequest
5 голосов
/ 18 марта 2019

Я пишу приложение Media Foundation для получения и отображения изображений 1920x1080 YUV2 с UVC-камеры с частотой 60 Гц.

Моя проблема заключается в том, что обратный вызов ReadSample () вызывается беспорядочно только с очень очень низкой скоростью(1 кадр / с или около того), в пачке нескольких кадров.

Это происходит на двух ноутбуках, но ни одного рабочего стола я не пробовал до сих пор.Я использую Windows 10, и все машины, на которых я выполнял тесты, являются современными.

Но я заметил, что, если я буду загружать процессор приложением, то обратный вызов будет вызываться с частотой 60 Гц, как и ожидалось.,

РЕДАКТИРОВАТЬ

Примечание. Частота обратного вызова также увеличивается, когда ЦП занят из-за включения антивируса.Хотя и не до 60 Гц.

Итак, если я изменю цикл обработки сообщений с:

while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

на:

   while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {
      TranslateMessage(&Msg);
      DispatchMessage(&Msg);
   }

, тогда FPS вернется к 60 Гц;но, конечно, загрузка процессора составляет почти 100% ...

Так же, перемещение мыши по окну с 1-м циклом сообщений приводит к увеличению FPS (~ 10FPS).

Снижение частоты кадров камеры до 30 Гц приводит к возникновению обратных вызовов ReadSample () на частоте 30 Гц.

Я воспроизвел ту же проблему с примером MFCaptureD3D из примеров, предоставленных Microsoft ('Windows-classic-samples ').

Обратите внимание, я немного изменил пример, чтобы измерить частоту кадров в обратном вызове ReadSample ().

На моем ноутбуке пример измеряет около 25FPS (так многоиз кадров упал).Это связано с тем, что преобразование цветового пространства основано на процессоре и очень неэффективно (75% одного ядра).Но он по-прежнему управляет 25PFS!

Закомментируя преобразование (без других изменений кода), частота кадров падает почти до нуля! .. при использовании ЦП 0%.Поэтому обратные вызовы не выполняются.

В обоих приложениях библиотека COM инициализируется в главном потоке приложения (запускает цикл сообщений окна) следующим образом:

hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

Я для удобства копирую обратный вызов ReadSample () из примера Microsoft:

HRESULT CPreview::OnReadSample(HRESULT hrStatus, DWORD /* dwStreamIndex */, DWORD /* dwStreamFlags */, LONGLONG /* llTimestamp */, IMFSample *pSample)
{
HRESULT hr = S_OK;
IMFMediaBuffer *pBuffer = NULL;

EnterCriticalSection(&m_critsec);

if (FAILED(hrStatus))
    hr = hrStatus;

if (SUCCEEDED(hr)) {
    if (pSample) {
        // Get the video frame buffer from the sample.
        hr = pSample->GetBufferByIndex(0, &pBuffer);
        // Draw the frame.
        if (SUCCEEDED(hr))
            hr = m_draw.DrawFrame(pBuffer);
    }

    rate.Inc();
}

// Request the next frame.
if (SUCCEEDED(hr))
    hr = m_pReader->ReadSample(
        (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
        0,
        NULL,   // actual
        NULL,   // flags
        NULL,   // timestamp
        NULL    // sample
        );

if (FAILED(hr))
    NotifyError(hr);

SafeRelease(&pBuffer);

LeaveCriticalSection(&m_critsec);
return hr;
}

EDIT

Оконная процедура, показанная ниже (максимально упрощена);объекты MF создаются в OnCreate ():

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
        HANDLE_MSG(hwnd, WM_CREATE, OnCreate);
    }    
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Интересно, связано ли это с COM-моделью потоков ;Я не понимаю примечание внизу страницы.

Многопоточная квартира предназначена для использования не потоками GUI.Потоки в многопоточных квартирах не должны выполнять действия пользовательского интерфейса.Это связано с тем, что потоки пользовательского интерфейса требуют прокачки сообщений, а COM не перекачивает сообщения для потоков в многопоточной квартире.

Означает ли это, что я не должен создавать объекты COM в своем потоке пользовательского интерфейса?

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

EDIT Запущены тесты с VLC, который основан нана DirectShow и не видел ни одной из этих проблем.Он отлично работает под Win7 и FPS составляет 60 Гц, как и ожидалось.Заметили, что VLC сбрасывает прерывание таймера до 1 мс ( timeBeginPeriod ()).Попытка сделать то же самое в моем, но безрезультатно.

Не хватает идей здесь ... похоже, мне, возможно, придется отказаться от MF и написать приложение DirectShow, если только дважды проверить, что оно работает должным образом.

...