MFCreateFMPEG4MediaSink 不生成 MSE 兼容的 MP4
MFCreateFMPEG4MediaSink does not generate MSE-compatible MP4
我正在尝试将 H.264 视频源流式传输到网络浏览器。 Media Foundation 用于编码分段的 MPEG4 流(MFCreateFMPEG4MediaSink
启用 MFTranscodeContainerType_FMPEG4
、MF_LOW_LATENCY
和 MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS
)。然后流通过 IMFByteStream
.
连接到 Web 服务器
H.264 视频流在被 <video src=".."/>
标签使用时工作正常。但是,由此产生的延迟约为 2 秒,这对于相关应用程序来说太长了。我怀疑客户端缓冲会导致大部分延迟。因此,我正在尝试使用媒体源扩展 (MSE) 对浏览器内流进行编程控制。然而,Chrome 在通过 MSE 使用相同的 MPEG4 流时确实失败并出现以下错误:
Failure parsing MP4: TFHD base-data-offset not allowed by MSE. See
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
我在 Win10 版本 1709 (16299.309) 上使用 Chrome 65.0.3325.181(官方构建)(32 位),运行。
是否有任何方法可以使用 Media Foundation 生成与 MSE 兼容的 H.264/MPEG4 视频流?
状态更新:
根据roman-r的建议,我设法通过拦截生成的 MPEG4 流并执行以下修改自行解决了问题:
- Modify Track Fragment Header Box (tfhd):
- remove
base_data_offset
parameter (reduces stream size by 8bytes)
- set
default-base-is-moof
flag
- Add missing Track Fragment Decode Time (tfdt) (increases stream size by 20bytes)
- set
baseMediaDecodeTime
parameter
- Modify Track fragment Run box (trun):
- adjust
data_offset
parameter
字段说明记录在 https://www.iso.org/standard/68960.html(免费下载)中。
切换到基于 MSE 的视频流将延迟从约 2.0 秒减少到 0.7 秒。通过在每次 IMFSinkWriter::WriteSample 调用后调用 IMFSinkWriter::NotifyEndOfSegment
,延迟进一步减少到 0-1 帧。
上有一个示例实现
按照 roman-r 的建议并修改生成的 MPEG4 流,问题已解决。请参阅上面的答案。
另一种方法是再次使用@Fredrik 提到的相同代码,但我编写了自己的 IMFByteStream 并检查了写入 IMFByteStream 的块。
FFMpeg 几乎一次写入原子。所以你可以检查原子名称并进行修改。这是一回事。我希望有一个符合 MSE 标准的 windows 坠子。
有没有可以为 HLS 生成 .ts 文件的软件?
提到的 0.7 秒延迟(在您的 状态更新 中)是由媒体基金会的 MFTranscodeContainerType_FMPEG4
containterizer 造成的,它大约每 1/3 秒收集并输出一次(来自未知原因)在一个 MP4 moof
/mdat
框对中的帧数。这意味着您需要等待 19 帧才能以 60 FPS 从 MFTranscodeContainerType_FMPEG4
获得任何输出。
要每帧输出单个 MP4 moof
/mdat
,只需说 MF_MT_FRAME_RATE
是 1 FPS(或高于 1/3 秒的任何值)。要以正确的速度播放视频,请使用 Media Source Extensions 的 <video>.playbackRate
或更新 MP4 中 mvhd
和 mdhd
框的 timescale
(即乘以实际 FPS)流拦截器以获取正确定时的 MP4 流。
这样做,延迟可以压缩到 20 毫秒以下。当您在 Unity(研究)-> NvEnc -> MFTranscodeContainerType_FMPEG4
-> WebSocket -> Chrome 媒体源扩展显示等链中并排看到 localhost
上的输出时,这几乎无法识别.
请注意,MFTranscodeContainerType_FMPEG4
仍会引入 1 帧延迟(第 1 帧输入,无输出,第 2 帧输入,第 1 帧输出,...),因此在 60 FPS 时有 20 毫秒的延迟。唯一的解决方案似乎是编写自己的 FMPEG4 容器化程序。但这比拦截 Media Foundation 的 MP4 流要复杂得多。
尝试通过 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
基于这个问题,我发现要让 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
我能够使用媒体源扩展成功播放视频。
这篇 Mozilla 文章有助于找出丢失的标志:
https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE
我正在尝试将 H.264 视频源流式传输到网络浏览器。 Media Foundation 用于编码分段的 MPEG4 流(MFCreateFMPEG4MediaSink
启用 MFTranscodeContainerType_FMPEG4
、MF_LOW_LATENCY
和 MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS
)。然后流通过 IMFByteStream
.
H.264 视频流在被 <video src=".."/>
标签使用时工作正常。但是,由此产生的延迟约为 2 秒,这对于相关应用程序来说太长了。我怀疑客户端缓冲会导致大部分延迟。因此,我正在尝试使用媒体源扩展 (MSE) 对浏览器内流进行编程控制。然而,Chrome 在通过 MSE 使用相同的 MPEG4 流时确实失败并出现以下错误:
Failure parsing MP4: TFHD base-data-offset not allowed by MSE. See 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
我在 Win10 版本 1709 (16299.309) 上使用 Chrome 65.0.3325.181(官方构建)(32 位),运行。
是否有任何方法可以使用 Media Foundation 生成与 MSE 兼容的 H.264/MPEG4 视频流?
状态更新:
根据roman-r的建议,我设法通过拦截生成的 MPEG4 流并执行以下修改自行解决了问题:
- Modify Track Fragment Header Box (tfhd):
- remove
base_data_offset
parameter (reduces stream size by 8bytes)- set
default-base-is-moof
flag- Add missing Track Fragment Decode Time (tfdt) (increases stream size by 20bytes)
- set
baseMediaDecodeTime
parameter- Modify Track fragment Run box (trun):
- adjust
data_offset
parameter
字段说明记录在 https://www.iso.org/standard/68960.html(免费下载)中。
切换到基于 MSE 的视频流将延迟从约 2.0 秒减少到 0.7 秒。通过在每次 IMFSinkWriter::WriteSample 调用后调用 IMFSinkWriter::NotifyEndOfSegment
,延迟进一步减少到 0-1 帧。
按照 roman-r 的建议并修改生成的 MPEG4 流,问题已解决。请参阅上面的答案。
另一种方法是再次使用@Fredrik 提到的相同代码,但我编写了自己的 IMFByteStream 并检查了写入 IMFByteStream 的块。 FFMpeg 几乎一次写入原子。所以你可以检查原子名称并进行修改。这是一回事。我希望有一个符合 MSE 标准的 windows 坠子。
有没有可以为 HLS 生成 .ts 文件的软件?
提到的 0.7 秒延迟(在您的 状态更新 中)是由媒体基金会的 MFTranscodeContainerType_FMPEG4
containterizer 造成的,它大约每 1/3 秒收集并输出一次(来自未知原因)在一个 MP4 moof
/mdat
框对中的帧数。这意味着您需要等待 19 帧才能以 60 FPS 从 MFTranscodeContainerType_FMPEG4
获得任何输出。
要每帧输出单个 MP4 moof
/mdat
,只需说 MF_MT_FRAME_RATE
是 1 FPS(或高于 1/3 秒的任何值)。要以正确的速度播放视频,请使用 Media Source Extensions 的 <video>.playbackRate
或更新 MP4 中 mvhd
和 mdhd
框的 timescale
(即乘以实际 FPS)流拦截器以获取正确定时的 MP4 流。
这样做,延迟可以压缩到 20 毫秒以下。当您在 Unity(研究)-> NvEnc -> MFTranscodeContainerType_FMPEG4
-> WebSocket -> Chrome 媒体源扩展显示等链中并排看到 localhost
上的输出时,这几乎无法识别.
请注意,MFTranscodeContainerType_FMPEG4
仍会引入 1 帧延迟(第 1 帧输入,无输出,第 2 帧输入,第 1 帧输出,...),因此在 60 FPS 时有 20 毫秒的延迟。唯一的解决方案似乎是编写自己的 FMPEG4 容器化程序。但这比拦截 Media Foundation 的 MP4 流要复杂得多。
尝试通过 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
基于这个问题,我发现要让 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
我能够使用媒体源扩展成功播放视频。
这篇 Mozilla 文章有助于找出丢失的标志: https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE