媒体基础架构设置视频隔行扫描和解码。

4

我有一个MOV文件,想要解码并将所有帧作为单独的图像。

因此,我尝试以下方式配置未压缩媒体类型:

// configure the source reader
IMFSourceReader* m_pReader;
MFCreateSourceReaderFromURL(filePath, NULL, &m_pReader);

// get the compressed media type
IMFMediaType* pFileVideoMediaType;
m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pFileVideoMediaType);

// create new media type for uncompressed type
IMFMediaType* pTypeUncomp;
MFCreateMediaType(&pTypeUncomp);

// copy all settings from compressed to uncompressed type
pFileVideoMediaType->CopyAllItems(pTypeUncomp);

// set the uncompressed video attributes
pTypeUncomp->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB8);
pTypeUncomp->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
pTypeUncomp->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);

// set the new uncompressed type to source reader
m_pReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, pTypeUncomp);

// get the full uncompressed media type
m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pTypeUncomp);

我注意到即使我明确将MF_MT_INTERLACE_MODE设置为MFVideoInterlace_Progressive,最终配置仍然配置为旧模式MFVideoInterlace_MixedInterlaceOrProgressive

之后,我循环遍历所有样本并查看它们的大小:

IMFSample* videoSample = nullptr;
IMFMediaBuffer* mbuffer = nullptr;
LONGLONG llTimeStamp;
DWORD streamIndex, flags;

m_pReader->ReadSample(
            MF_SOURCE_READER_FIRST_VIDEO_STREAM,
            0,                               // Flags.
            &streamIndex,                    // Receives the actual stream index. 
            &flags,                          // Receives status flags.
            &llTimeStamp,                    // Receives the time stamp.
            &videoSample)                    // Receives the sample or NULL.

videoSample->ConvertToContiguousBuffer(&mbuffer);

BYTE* videoData = nullptr;
DWORD sampleBufferLength = 0;

mbuffer->Lock(&videoData, nullptr, &sampleBufferLength);
cout << sampleBufferLength << endl;

我得到的样本大小相差很大:从31字节到18000字节。即使将格式更改为MFVideoFormat_RGB32也不会影响样本大小。 这个问题似乎有同样的问题,但解决方案无法修复它。
有没有帮助说明我为什么无法更改交错以及如何正确解码视频帧并从样本中获取图像数据?
非常感谢您的帮助。

1
也许你应该先尝试调用GetNativeMediaType而不是m_pReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pFileVideoMediaType)。你是否还检查了每个样本是否交错:pSample->GetUINT32(MFSampleExtension_Interlaced, &isSampleInterlaced)? - VuVirt
1
您可以在此处检查ConfigureDecoder函数:https://msdn.microsoft.com/zh-cn/library/windows/desktop/dd389281(v=vs.85).aspx#setting_output_formats。当调用ReadSample时,您还可以检查接收状态标志中的MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED,以查看类型是否已更改。 - VuVirt
@VuVirt,感谢您的评论。获取本机媒体类型并没有改变任何内容。检查交错样本时出现了错误。而且媒体类型也没有改变。您还有其他想法吗?如果您能抽出几分钟时间查看我的代码:https://github.com/mbaros100/Media-Foundation-video-decoder。非常感谢您的帮助。 - mbaros
尝试不使用pTypeUncomp->CopyAllItems。通过使用所有必要的属性手动构建未压缩视频媒体类型,如此链接所示:https://msdn.microsoft.com/en-us/library/windows/desktop/ff485865(v=vs.85).aspx - VuVirt
@VuVirt,我已经按照你发送给我的链接所说的去做了,但没有任何积极的变化。我已经更新了代码库中的代码。 - mbaros
1
你不应该将 MFVideoFormat_Base 设为子类型。请尝试使用 MFVideoFormat_RGB32。 - VuVirt
1个回答

3
为了让SourceReader将样本转换为RGB格式,您需要按以下方式创建它:

IMFAttributes* pAttr = NULL;
MFCreateAttributes(&pAttr, 1);
pAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
pAttr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE);
    
IMFSourceReader* m_pReader;
throwIfFailed(MFCreateSourceReaderFromURL(filePath, pAttr, &m_pReader), Can't create source reader from url");
pAttr->Release();

在 MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED 发生时,您不应打破循环。现在您将拥有相同大小的所有样本。 否则,您可以使用 MFVideoFormat_NV12 子类型,然后在创建读取器时无需指定 MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING 属性。


1
对我有用。非常感谢。 - mbaros
让我再问你一个问题。对于某些文件,我得到的缓冲区大小恰好匹配图像高度宽度4,并且数据是正确的。对于其他一些文件,我得到的缓冲区大小大于高度宽度4。你知道这额外的数据代表什么吗? - mbaros
1
@mbaros 是什么错误?一些示例不会暴露IMF2DBuffer。在这种情况下,您可能需要直接锁定IMFMediaBuffer或查询D3D纹理。请按照其他答案中的链接,有足够的源代码和解释可供参考。至于更大的宽度,它被称为步幅: https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa473780(v=vs.85).aspx。谢谢! - VuVirt
VuVirt看起来是这样的,样本可能没有暴露IMF2DBuffer。我使用IMFMediaBuffer。我已经测试了3个媒体文件。在所有情况下,步幅=宽度4。问题在于对于某些情况,样本缓冲区长度超过了hw4。而且取前hw4字节的数据会给出错误的输出图像。每当我的缓冲区长度为hw*4时,数据就是正确的。 - mbaros
顺带一提,“MF_TOPOLOGY_ENABLE_XVP_FOR_PLAYBACK” 似乎在任何地方都没有记录。我在这里发布此注释,以防有所帮助,因为在我翻箱倒柜寻找解决方法之前,花费了很长时间和艰辛的斗争才发现一个如此简单的修复方法。例如,Microsoft D3D11 IMFMediaSink 示例 - 通过演示显式手动连接和调用外部 XVP,会使你认为当 D3D9 EVR 模型在 D3D11 中被弃用时,IMFMediaSink 必须承担这些任务的负担。但事实并非完全如此。 - Glenn Slayden
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接