Microsoft Media Foundation / UVC ReadSample()回调

时间:2019-03-18 12:14:27

标签: video windows-10 video-capture ms-media-foundation uvc

我正在编写Media Foundation应用程序,以从60Hz的UVC摄像机获取并显示1920x1080 YUV2图像。

我的问题是ReadSample()回调仅以非常低的速率(大约1 FPS)被不稳定地调用,只有几帧。

这在两台笔记本电脑上发生,但到目前为止我还没有尝试过使用台式机。 我正在运行Windows 10,并且在其上运行测试的所有计算机都是最新的。

但是,我注意到,如果我让CPU忙于我的应用程序,则回调将以预期的60Hz频率被调用。

编辑

注:由于防病毒启动,当CPU繁忙时,回调率也会提高。虽然不能达到60Hz的全频率。

因此,如果我将消息循环从以下位置更改:

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

收件人:

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

然后FPS回到60Hz;但是当然CPU使用率接近100%...

同上,在第一个消息循环中将鼠标移到窗口上方会使FPS增加一点(〜10FPS)。

将摄像头的帧速率降低到30Hz会导致ReadSample()回调以应有的30Hz发生。

我已经从Microsoft提供的示例(“ Windows-classic-samples”)再现了MFCaptureD3D示例的相同问题。

注意,我对示例进行了一些修改,以测量ReadSample()回调中的帧速率。

在我的笔记本电脑上,该示例的速度约为25FPS(因此丢掉了很多帧)。这是因为色彩空间转换是基于CPU的并且效率很低(一个内核的75%)。但是,它仍然管理25PFS!

注释掉转换(没有其他代码更改),导致帧速率下降到几乎为零!.. CPU使用率为0%。因此不会发生回调。

在两个应用程序中,COM库都在应用程序的主线程中初始化(运行窗口的消息循环),如下所示:

hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);

为方便起见,我从Microsoft的示例中复制了ReadSample()回调:

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

编辑

如下所示的窗口过程(尽可能简化); 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 threading model有关;我不明白页面底部的注释。

  

多线程单元旨在供非GUI线程使用。   多线程单元中的线程不应执行UI操作。   这是因为UI线程需要消息泵,而COM则不需要   抽出多线程单元中线程的消息。

这是否意味着我不应该在UI线程中创建COM对象?

我尝试在具有自己的msg循环的另一个线程中创建它们,但得到的结果完全相同。

编辑 使用基于DirectShow的VLC进行了测试,没有发现任何问题。在Win7下工作正常,FPS预期为60Hz。 注意,VLC将计时器中断降至1ms(timeBeginPeriod())。尝试对我做同样的事情,无济于事。

在这里用尽所有想法……如果只是仔细检查它是否可以正常工作,我可能不得不放弃MF并编写DirectShow应用。

0 个答案:

没有答案