使用 Media Foundation 源阅读器阅读 3D(左右)视频

Posted

技术标签:

【中文标题】使用 Media Foundation 源阅读器阅读 3D(左右)视频【英文标题】:Using Media Foundation source reader to read 3D (left-right) video 【发布时间】:2018-12-24 16:32:07 【问题描述】:

当尝试读取标记为 3D 左右的 4K 视频时,IMFSourceReader 返回大小为 1920x2160 的图像(图像的一半)。如果可能的话,我想获得完整的图像,或者至少可以访问下半场。

我知道 MF_ENABLE_3DVIDEO_OUTPUT,但我不确定如何将它应用到 IMFSourceReader。我尝试在媒体类型上设置它,但这并没有改变任何东西。

源阅读器告诉我流的宽度是帧大小的一半(4K 电影为 1920x2160),但是当我在示例上使用 GetBufferCount 时,结果为 1。所以我不知道如何获取所有帧的数据。

我查看了 DX11VideoRenderer 示例,这似乎假设 GetBufferCount 返回 2。但是它不使用 IMFSourceReader,所以我不确定如何将它应用于该场景。

理想情况下,我想要的是使用 MF3DVideoOutputType_BaseView 并获得完整的 4K 源图像。

编辑:

这与 Facebook 180 数据有关。 (设置“Half Equirectangular”和“Side-bySide”。它会在 MP4 中生成 YouTube V1 球形元数据,Facebook 可以识别 180 度立体视频的特定设置。)

这里有一个示例视频:https://drive.google.com/open?id=154dl33y9RKZcvTqdBZkLQ5Y5ckG2mZtf(它会在将来的某个时候被删除;如果有人对上传位置有更好的建议,请随时提出建议)。

【问题讨论】:

如果你有一个示例文件,也许值得将它链接到 Q。另外,为了记录,这是 How do I read a 3D left-right movie's full frame using a source reader? 的交叉帖子。 阅读器可能有 2 个视频流。当你调用 IMFSourceReader::ReadSample 时传递 dwStreamIndex=1 看看你得到了什么。 罗马,是的。那里没有回应,所以在这里尝试。 很快,只有一个视频流。我正在枚举所有流,我得到一个流,它设置了 MF_MT_VIDEO_3D。 更新了一段视频和进一步调查的结果。 【参考方案1】:

这可能不是一个完全正确的答案,因为我可以通过简单的阅读来做你想做的事情。但是,下面的步骤可能会提示您在哪里进行故障排除。

IMFSourceReader 返回大小为 1920x2160 的图像(图像的一半)。如果可能的话,我想获得完整的图像,或者至少可以访问下半场。

我使用一个应用程序处理了您的示例视频,该应用程序使用 MF Source Reader 来读取视频、解压缩并保存为单个帧。我看到视频的两半都可以访问。

这里是详细信息。

视频媒体类型表示3D视频:

MF_MT_MAJOR_TYPE, vValue 73646976-0000-0010-8000-00AA00389B71 (Type VT_CLSID, MFMediaType_Video, FourCC vids)
MF_MT_SUBTYPE, vValue 34363248-0000-0010-8000-00AA00389B71 (Type VT_CLSID, MFVideoFormat_H264, FourCC H264)
MF_MT_AM_FORMAT_TYPE, vValue E06D80E3-DB46-11CF-B4D1-00805F6CBBEA (Type VT_CLSID, WMFORMAT_MPEG2Video)
MF_MT_VIDEO_PROFILE, vValue 100 (Type VT_UI4)
MF_MT_VIDEO_LEVEL, vValue 51 (Type VT_UI4)
MF_MT_FRAME_SIZE, vValue 16492674418800 (Type VT_UI8, 3840x2160)
MF_MT_PIXEL_ASPECT_RATIO, vValue 4294967297 (Type VT_UI8, 1:1)
MF_MT_INTERLACE_MODE, vValue 7 (Type VT_UI4)
MF_MT_FRAME_RATE, vValue 128849018881001 (Type VT_UI8, 30000/1001, 29.970)
MF_MT_SAMPLE_SIZE, vValue 1 (Type VT_UI4)
MF_MT_AVG_BITRATE, vValue 82101870 (Type VT_UI4)
MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY, vValue 0 (Type VT_UI4)
MF_MT_MPEG4_SAMPLE_DESCRIPTION, vValue 00 00 59 2A 73 74 73 64 00 00 00 00 00 00 00 01 00 00 59 1A 61 76 63 31 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F 00 08 70 00 48 00 00 00 48 00 00 00 00 00 00 00 01 15 41 6D 62 61 72 65 6C 6C 61 20 41 56 43 20 65 6E 63 6F 64 65 72 00 00 00 00 00 00 00 00 00 00 00 18 FF FF 00 00 00 4B 61 76 63 43 01 64 00 33 FF E1 00 34 27 64 00 33 AC 34 C8 03 C0 04... (Type VT_VECTOR | VT_UI1)
MF_MT_MPEG_SEQUENCE_HEADER, vValue 00 00 01 27 64 00 33 AC 34 C8 03 C0 04 3E 84 00 00 0F A4 00 03 A9 83 A1 80 00 4C 4B 40 00 03 93 87 0B BC B8 D0 C0 00 26 25 A0 00 01 C9 C3 85 DE 5C 3E 11 08 D4 00 00 00 00 01 28 EE 38 B0 (Type VT_VECTOR | VT_UI1)
MF_MT_VIDEO_3D, vValue 1 (Type VT_UI4)
MF_MT_VIDEO_3D_FORMAT, vValue 2 (Type VT_UI4)
MF_MT_VIDEO_ROTATION, vValue 0 (Type VT_UI4)
MF_NALU_LENGTH_SET, vValue 1 (Type VT_UI4)
MF_PROGRESSIVE_CODING_CONTENT, vValue 1 (Type VT_UI4)
11D25A49-BB62-467F-9DB1-C17165716C49, vValue 00 00 00 00 00 00 00 00 00 00 00 00 (Type VT_VECTOR | VT_UI1)
4A8FC407-6EA1-46C8-B567-6971D4A139C3, vValue 0 (Type VT_UI4)
A51DA449-3FDC-478C-BCB5-30BE76595F55, vValue 1 (Type VT_UI4)

注意 3840x2160 分辨率和 MF_MT_VIDEO_3D_FORMATMFVideo3DSampleFormat_Packed_LeftRight

每个媒体样本包含一个缓冲区,两个视图并排打包到一个帧中。

这似乎是对您文件的正确读取。我让我的应用程序设置 Source Reader 并使用以下媒体类型调用 SetCurrentMediaType

MF_MT_MAJOR_TYPE, vValue 73646976-0000-0010-8000-00AA00389B71 (Type VT_CLSID, MFMediaType_Video, FourCC vids)
MF_MT_SUBTYPE, vValue 00000016-0000-0010-8000-00AA00389B71 (Type VT_CLSID, MFVideoFormat_RGB32, FourCC 0x00000016)
MF_MT_FRAME_SIZE, vValue 16492674418800 (Type VT_UI8, 3840x2160)
MF_MT_PIXEL_ASPECT_RATIO, vValue 4294967297 (Type VT_UI8, 1:1)
MF_MT_INTERLACE_MODE, vValue 2 (Type VT_UI4)
MF_MT_FRAME_RATE, vValue 128849018881001 (Type VT_UI8, 30000/1001, 29.970)

即要求将视频解压为全分辨率RGB格式。

Source Reader 可以接受这样的请求,并提供视频解码器来满足格式转换:

Category MFT_CATEGORY_VIDEO_DECODER, Direct3D 11 Aware, Input MFVideoFormat_H264, 3840 x 2160, Output MFVideoFormat_NV12, 3840 x 2160

显然解码器是H.264 Video Decoder,以防您想直接在内部源读取器管道之外对其进行管理。

第一个读取的视频样本具有以下属性:

MF_NALU_LENGTH_INFORMATION, vValue  (Type VT_VECTOR | VT_UI1)
MFSampleExtension_ForwardedDecodeUnits, vValue ??? (Type VT_UNKNOWN)
MFSampleExtension_AccumulatedNonRefPicPercent, vValue 0 (Type VT_UI4)
MFSampleExtension_Token, vValue ??? (Type VT_UNKNOWN, 0x00000282397B1020)
MFSampleExtension_CleanPoint, vValue 1 (Type VT_UI4)
MFSampleExtension_Discontinuity, vValue 1 (Type VT_UI4)
MFSampleExtension_FrameCorruption, vValue 0 (Type VT_UI4)
nSampleTime 0, nSampleDuration 33 3666, nBufferCount 1, nTotalLength 33177600
nBufferIndex 0, nCurrentLength 33177600, nMaxLength 33177600

如您所见,它有一个缓冲区,数据大小为 3840 * 2160 * 4 字节。图片本身就是我在上面附上的那张,有两半。

这是 Windows 2018 年 10 月 10 日更新(版本 1809)上的行为。我想这种行为基本上符合您的原始请求。我还看到 MP4 原子也表示全分辨率 (3840x2160),所以总体而言,我上面提到的行为和我实际看到的行为是完全可以预期的。更重要的是,即使 SDK topoedit 播放文件的两半,这意味着当立体声从两半混合时,要实现电影和电视的行为,必须以某种方式专门配置解码器。

据我了解,您看到的是不同的行为,这应该是有原因的,很可能与视频解码器或解码后的步骤有关请求它。由于视频是以左+右方式编码的,我会说管道中的某些内容不太可能被硬编码以丢弃下半部分并且无法控制这一点,也许它可能是管道配置的问题。

但也可能发生早期版本的 Windows 缺乏对球面视频的支持,并截断了视频,因为它由两半组成,但同时还没有球面功能的代码路径和实现。

Windows 10, version 1803 provides support for 360 camera preview, capture, and record with existing MediaCapture APIs. […]

2018 年 12 月 27 日更新:问题似乎仅限于或至少与启用 MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING 有关。启用后,Source Reader 应用Video Processor MFT 来满足格式转换需求,而不是内部转换器(但是 AFAIR 不是硬件加速的)。内部非硬件转换器透明地输出两个视图,甚至可能不知道一个框架中有两个视图。然而,视频处理器 MFT 声明了立体 3D 功能,并且在其默认操作模式下,它放弃了下半部分。

快速浏览一下,我无法启用它的 3D 输出选项并将其切换为保留最右半部分,无论是作为单个缓冲区的一部分、辅助缓冲区还是辅助纹理表面。但是,由于看起来后半部分在解码器后的步骤中被剥离,它应该可以很好地工作,例如 - 并且可能有许多类似的方法来实现这个技巧 - 从 Source Reader 读取 NV12 纹理,然后从样本/纹理中移除 3D 信息,像素格式的进一步转换(包括启用 GPU)会导致转换完整的 3840x2160 帧而不移除后半部分。

【讨论】:

非常感谢您的详细回复。它帮助我继续我的调查。我已将其范围缩小到使用 MFVideoFormat_ARGB32(或 MFVideoFormat_RGB32)。如果我使用 NV12,一切都很好。 (我正在使用 MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING 和 MF_SOURCE_READER_D3D_MANAGER 创建设备。) 忘了说操作系统版本是1803。 我手边没有1803,但我可以分享上面提到的工具本身。 “MediaFoundationSplitFrameBitmaps-x64 input HET_0015.MP4”将创建一个子目录并在那里写入提取的帧,这就是为我提取两者的内容。您可能想在 1803 上尝试它。那时它只执行 MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING,但如果您不带参数运行,您将打印语法并且您将能够应用 MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING 仅供参考,MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING 确实在 Windows 10 版本 1809 中丢失了后半部分。据我所知,这可能是启用 D3D11 的视频处理器 MFT 变体的默认行为。稍后我可能会再试一次,但总体思路是这样的:如果您通过IMFSourceReaderEx::GetTransformForStream 从源阅读器中提取IMFTransform,那么也许您可以更新它以在输出中启用后半部分。或者如果这不起作用,您将不得不提取 NV12(解码器输出),然后转换为 RGB(如果需要)直接与 MFT 对话。 (很抱歉造成混乱:在上面的原始评论中我提供了错误的下载链接,现在已修复)

以上是关于使用 Media Foundation 源阅读器阅读 3D(左右)视频的主要内容,如果未能解决你的问题,请参考以下文章

使用 IMFSourceReader 进行音频流式传输(Microsoft Media Foundation)

使用 Media Foundation 将音频从文件播放到扬声器

如何在没有拓扑的情况下将 Windows Media Foundation 与 UWP 结合使用

使用 Media Foundation SDK 进行直播

使用 Microsoft Media Foundation 从文件播放视频

Windows Media Foundation 枚举音频设备