Я пишу приложение 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, если только дважды проверить, что оно работает должным образом.