【问题标题】:Media Foundation onReadSample wrong size of returned sampleMedia Foundation onReadSample 返回样本的大小错误
【发布时间】:2013-12-29 19:15:59
【问题描述】:

我正在将捕获库从 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 中,我应该收到一个缓冲区大小为的样本:

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 正确加载并正确注册。如果您自己回答问题并接受您自己的回答,总体而言可能会更好,因为我真的不回答这个问题,除非以非常模糊的方式回答。
  • 谢谢 Mgetz,我听从了你的建议并发布了一个新答案

标签: c++ image capture ms-media-foundation


【解决方案1】:

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

下一个最可能的原因是interlacing,在这种情况下,每一帧都是完整的,但不是您假设的全分辨率。无论如何,您都应该在接受之前验证 ENTIRE 媒体类型描述符。

【讨论】:

    【解决方案2】:

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

    感谢您的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多