首页 > 解决方案 > 使用 Media Foundation 源阅读器阅读 3D(左右)视频

问题描述

尝试读取标记为 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 (它将在将来的某个时候删除;如果有人对上传位置有更好的建议,请随时提出建议它)。

标签: c++windowsvideoms-media-foundationstereo-3d

解决方案


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

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 视频解码器,以防您想直接在内部源读取器管道之外对其进行管理。

首次读取的视频样本具有以下属性:

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 版本 1803 支持使用现有 MediaCapture API 进行 360 度全景预览、捕获和录制。[…]

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

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


推荐阅读