我正在将捕获库从DirectShow转换为MediaFoundation。捕获库似乎运行得很好,但是运行Windows 8 32位平板电脑上的集成网络摄像头遇到了问题。

枚举捕获格式时(如Media Foundation documentation中所述),我得到了相机以下受支持的格式:

  • 0:MFVideoFormat_NV12,分辨率:448x252,帧速率:30000x1001
  • 1:MFVideoFormat_YUY2,分辨率:448x252,帧速率:30000x1001
  • 2:MFVideoFormat_NV12,分辨率:640x360,帧速率:30000x1001
  • 3:MFVideoFormat_YUY2,分辨率:640x360,帧速率:30000x1001
  • 4:MFVideoFormat_NV12,分辨率:640x480,帧速率:30000x1001
  • 5:MFVideoFormat_YUY2,分辨率:640x480,帧频:30000x1001

  • 然后,使用以下函数设置捕获格式,在本例中为索引5的捕获格式,如示例中所述:

    hr = pHandler->SetCurrentMediaType(pType);
    

    该函数执行无错误。因此,应该将相机配置为以YUY2分辨率640 * 480进行拍摄。

    onReadSample callback中,我应该收到一个带有size缓冲区的样本:
    640 * 480 * sizeof(unsigned char) * 2 =  614400 //YUY2 is encoded on 2 bytes
    

    但是,我得到了一个缓冲区大小为169344的示例。以下是回调函数的一部分。

    HRESULT SourceReader::OnReadSample(
        HRESULT hrStatus,
        DWORD dwStreamIndex,
        DWORD dwStreamFlags,
        LONGLONG llTimeStamp,
        IMFSample *pSample      // Can be NULL
        )
    {
        EnterCriticalSection(&m_critsec);
    
        if (pSample)
        {
            DWORD expectedBufferSize = 640*480*1*2; // = 614400 (hard code for the example)
    
            IMFMediaBuffer* buffer = NULL;
            hr = pSample->ConvertToContiguousBuffer(&buffer);
            if (FAILED(hr))
            {
                //...
                goto done;
            }
    
            DWORD byteLength = 0;
            BYTE* pixels = NULL;
            hr = buffer->Lock(&pixels, NULL, &byteLength);
    
            //byteLength is 169344 instead of 614400
            if (byteLength > 0 && byteLength == expectedBufferSize)
            {
                //do someting with the image, but never comes here because byteLength is wrong
            }
            //...
    

    任何建议为什么我会得到169344的样​​本?

    提前致谢

    感谢Mgetz的回答。

    我检查了媒体类型的MF_MT_INTERLACE_MODE的值,似乎视频流包含渐进帧。 MF_MT_INTERLACE_MODE的值返回MFVideoInterlace_Progressive。
    hr = pHandler->SetCurrentMediaType(m_pType);
    if(FAILED(hr)){
        //
    }
    else
    {
        //get info about interlacing
        UINT32 interlaceFormat = MFVideoInterlace_Unknown;
        m_pType->GetUINT32(MF_MT_INTERLACE_MODE, &interlaceFormat);
    
        //...
    

    因此视频流不是隔行的。我再次在onReadSample中检查了MFSampleExtension_Interlaced的值,以查看样本是否是隔行的,并且看起来样本是隔行的。
    if (pSample && m_bCapture)
    {
        //check if interlaced
        UINT32 isSampleInterlaced = 0;
        pSample->GetUINT32(MFSampleExtension_Interlaced, &isSampleInterlaced);
        if(isSampleInterlaced)
        {
            //enters here
        }
    

    流是渐进的并且样本是隔行扫描的,怎么可能?我也在onReadSample回调中再次检查了MF_MT_INTERLACE_MODE的值,它仍然为我提供了MFT_INPUT_STREAM_WHOLE_SAMPLES的值。

    关于您的第一个建议,我没有办法在输入流上强制使用标志MFT_INPUT_STREAM_WHOLE_SAMPLES。

    提前致谢

    我仍然面临这个问题,现在我正在研究可用的不同流。

    根据文档,每个媒体源都提供一个演示描述符,我们可以从中获取可用的流。要获取演示文稿描述符,我们必须调用:

    HRESULT hr = pSource->CreatePresentationDescriptor(&pPD);
    

    然后,我使用IMFPresentationDescriptor::GetStreamDescriptorCount函数请求可用的流:

    DWORD nbrStream;
    pPD->GetStreamDescriptorCount(&nbrStream);
    

    当在运行Windows 8的ACER平板电脑的前置摄像头上请求此信息时,我得到了三个流。我遍历了这些流,请求了它们的MediaTypeHandler并检查了MajorType。这三个流具有主要类型:MFMediaType_Video,因此所有流都是视频流。当列出不同流上可用的媒体类型时,我得到所有流都支持640x480的捕获。 (某些流具有更多可用的媒体类型)。

    我测试过选择每个不同的流和适当的格式类型(框架没有返回任何错误),但是我仍然没有在回调函数中收到正确的示例...

    有什么建议可以解决这个问题?

    终于找到了问题:我必须使用SourceReader-> SetCurrentMediaType(..)直接在源阅读器上设置媒体类型。做到了!

    谢谢你的帮助!

    最佳答案

    在不知道输入媒体类型描述符是什么的情况下,我们基本上只能推测,但是最有可能的答案是,即使没有在输入流上设置 MFT_INPUT_STREAM_WHOLE_SAMPLES ,您也可以处理该流。

    下一个最可能的原因是interlacing,在这种情况下,每帧将是完整的,但不是您假设的完整分辨率。无论如何,您都应先接受 ENTIRE 媒体类型描述符,然后再接受它。

    08-15 23:24