MFCreateFMPEG4MediaSink 不生成 MSE 兼容的 MP4

Fre*_*rud 5 mp4 mse h.264 ms-media-foundation

我正在尝试将 H.264 视频源流式传输到网络浏览器。Media Foundation 用于对分段的 MPEG4 流进行编码(MFCreateFMPEG4MediaSink使用MFTranscodeContainerType_FMPEG4MF_LOW_LATENCYMF_READWRITE_ENABLE_HARDWARE_TRANSFORMS启用)。然后,该流通过 .NET 连接到 Web 服务器IMFByteStream

当 H.264 视频被标签使用时,它的流式传输工作正常<video src=".."/>。然而,产生的延迟约为 2 秒,这对于相关应用程序来说太大了。我怀疑客户端缓冲导致了大部分延迟。因此,我正在尝试使用媒体源扩展 (MSE) 对浏览器内流进行编程控制。但是,当通过 MSE 使用相同的 MPEG4 流时,Chrome 会失败并出现以下错误:

解析 MP4 失败:MSE 不允许 TFHD 基本数据偏移。请参阅 https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing

MPEG4 流中 moof/mdat 片段的 mp4dump。这清楚地表明 TFHD 包含“非法”base data offset参数:

[moof] size=8+200
  [mfhd] size=12+4
    sequence number = 3
  [traf] size=8+176
    [tfhd] size=12+16, flags=1
      track ID = 1
      base data offset = 36690
    [trun] size=12+136, version=1, flags=f01
      sample count = 8
      data offset = 0
[mdat] size=8+1624
Run Code Online (Sandbox Code Playgroud)

我使用的是 Chrome 65.0.3325.181(官方版本)(32 位),在 Win10 版本 1709 (16299.309) 上运行。

有没有办法使用 Media Foundation 生成 MSE 兼容的 H.264/MPEG4 视频流?

状态更新:

根据roman-r建议,我设法通过拦截生成的 MPEG4 流并执行以下修改来自行解决问题:

  • 修改轨道片段标题框(tfhd):
    • 删除base_data_offset参数(将流大小减少 8 个字节)
    • 设置default-base-is-moof标志
  • 添加缺失的轨道片段解码时间(tfdt)(将流大小增加 20 字节)
    • 设置baseMediaDecodeTime参数
  • 修改Track片段运行框(trun):
    • 调整data_offset参数

字段描述记录在https://www.iso.org/standard/68960.html(免费下载)中。

切换到基于 MSE 的视频流将延迟从约 2.0 秒减少到 0.7 秒。通过在每次 IMFSinkWriter::WriteSample 调用之后调用,延迟进一步减少到 0-1 帧IMFSinkWriter::NotifyEndOfSegment

https://github.com/forderud/AppWebStream上有一个示例实现

rsc*_*rsc 6

当尝试通过 MSE 播放 fmp4 时,我遇到了相同的错误(失败解析 MP4:MSE 不允许 TFHD 基本数据偏移)。fmp4 是使用以下 ffmpeg 命令从 mp4 创建的:

ffmpeg -i myvideo.mp4 -g 52 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov myfmp4video.mp4
Run Code Online (Sandbox Code Playgroud)

基于这个问题,我发现要让 fmp4 在 Chrome 中工作,我必须添加“ default_base_moof ”标志。因此,使用以下命令创建 fmp4 后:

ffmpeg -i myvideo.mp4 -g 52 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov+default_base_moof myfmp4video.mp4
Run Code Online (Sandbox Code Playgroud)

我能够使用媒体源扩展成功播放视频。

这篇 Mozilla 文章帮助找到了丢失的标志: https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE


小智 1

提到的 0.7 秒延迟(在您的Status Update中)是由 Media Foundation 的容器器引起的,该容器器在一对 MP4 /盒子MFTranscodeContainerType_FMPEG4中收集并输出大约 1/3 秒(出于未知原因)的帧。这意味着您需要等待 19 帧才能获得60 FPS 的任何输出。moofmdatMFTranscodeContainerType_FMPEG4

要输出单个 MP4 moof/mdat每帧,只需将其设置MF_MT_FRAME_RATE为 1 FPS(或任何高于 1/3 秒的值)。要以正确的速度播放视频,请使用媒体源扩展,<video>.playbackRate或者更确切地说,更新timescale(即乘以实际 FPS) MP4 流拦截器中的mvhdmdhd框,以获得正确定时的 MP4 流。

这样做,延迟可以压缩到 20 毫秒以下。localhost当您在 Unity(研究)-> NvEnc -> MFTranscodeContainerType_FMPEG4-> WebSocket -> Chrome Media Source Extensions 显示等链中并排看到输出时,这几乎无法识别。

请注意,MFTranscodeContainerType_FMPEG4仍然会引入 1 帧延迟(第 1 帧输入,无输出,第 2 帧输入,第 1 帧输出,...),因此 60 FPS 时有 20 毫秒的延迟。唯一的解决方案似乎是编写自己的 FMPEG4 容器化器。但这比拦截 Media Foundation 的 MP4 流复杂一个数量级。