我正在尝试将H.264视频源流式传输到网络浏览器。 Media Foundation用于编码碎片化的MPEG4流(MFCreateFMPEG4MediaSink
启用了MFTranscodeContainerType_FMPEG4
,MF_LOW_LATENCY
和MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS
)。然后通过IMFByteStream
将流连接到Web服务器。
当H.264视频被<video src=".."/>
标签使用时,它的流媒体工作正常。但是,产生的延迟约为2秒,这对于所讨论的应用来说太多了。我怀疑客户端缓冲会导致大部分延迟。因此,我正在尝试使用Media Source Extensions(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
我正在使用Chrome 65.0.3325.181(官方构建)(32位),在Win10版本1709(16299.309)上运行。
有没有办法使用Media Foundation生成兼容MSE的H.264 / MPEG4视频流?
基于roman-r建议,我设法通过拦截生成的MPEG4流并执行以下修改来解决问题:
- 修改Track Fragment Header Box(tfhd): 删除
base_data_offset
参数(将流大小减少8bytes) 设置default-base-is-moof
标志- 添加缺少的轨道片段解码时间(tfdt)(将流大小增加20字节) 设置
baseMediaDecodeTime
参数- 修改轨道片段运行框(trun): 调整
data_offset
参数
字段描述记录在https://www.iso.org/standard/68960.html(免费下载)中。
切换到基于MSE的视频流将延迟从大约2.0降低到0.7秒。不幸的是,这对我的需求来说仍然太多了。剩余延迟的主要来源似乎是由每个MP4片段中8个帧/样本的捆绑引起的。我不知道如何解决这个问题。
提到的0.7秒延迟(在您的状态更新中)是由Media Foundation的MFTranscodeContainerType_FMPEG4
封装器引起的,该封装器在一个MP4 moof
/ mdat
盒对中收集和输出每个大约1/3秒(来自未知原因)的帧。这意味着您需要等待19帧才能从MFTranscodeContainerType_FMPEG4
以60 FPS获得任何输出。
要为每帧输出单个MP4 moof
/ mdat
,只需说谎MF_MT_FRAME_RATE
为1 FPS(或高于1/3秒的任何值)。要以正确的速度播放视频,请使用Media Source Extensions的<video>.playbackRate
,或者在MP4流拦截器中更新timescale
和mvhd
框的mdhd
(即乘以实际FPS),以获得正确定时的MP4流。
这样做,延迟可以缩短到20毫秒以下。当您在localhost
上看到输出并排在Unity(研究) - > NvEnc - > MFTranscodeContainerType_FMPEG4
- > WebSocket - > Chrome Media Source Extensions显示时,几乎无法识别。
请注意,MFTranscodeContainerType_FMPEG4
仍然会引入1帧延迟(第1帧输入,无输出,第2帧输入,第1帧输出,......),因此60 FPS时的20 ms延迟。对此的唯一解决方案似乎是编写自己的FMPEG4容器。但这比拦截媒体基金会的MP4流程要复杂得多。
通过遵循roman-r的建议并修改生成的MPEG4流来解决问题。见上面的答案。
另一种方法是再次使用@Fredrik提到的相同代码但我编写自己的IMFByteStream并检查写入IMFByteStream的块。 FFMpeg几乎每次写入一次原子。所以你可以检查原子名称并进行修改。这是一回事。我希望有一个符合MSE标准的Windows沉降片。
有没有可以为HLS生成.ts文件的?