能否Flush Sink Writer进度到文件以避免全量样本加载至内存?
关于Media Foundation Sink Writer增量刷写MP4文件的解答
原生IMFSinkWriter在默认标准MP4输出模式下,不支持类似IMFSinkWriter::Finalize的增量刷入且刷入后仍可继续写入样本的能力,原因如下:
- MP4容器的标准文件结构要求最终的
moov元数据块(包含所有帧的索引、时长等关键信息)必须在所有媒体帧写入完成后才能生成,默认配置下Sink Writer会缓存所有帧的相关元数据,直到调用Finalize时才会将完整的元数据和所有缓存内容一次性写入输出流,这也是你调用IMFByteStream::Flush无效的核心原因:此时要写入的内容根本没有被Sink Writer提交到绑定的字节流对象,刷字节流不会产生任何效果。
可行的解决方案
方案1:使用碎片化MP4(fMP4)输出模式(最适配你的场景)
你可以通过配置Sink Writer的属性开启MP4碎片化写入能力,完全满足你增量刷入、无需提前加载所有样本到内存、刷入后仍可继续写入的需求:
- 创建Sink Writer前先初始化属性存储对象,设置
MF_MPEG4SINK_SINK_OPTION_FRAGMENTED属性为TRUE - 将配置好的属性存储作为参数传入
MFCreateSinkWriterFromURL的最后一个入参 - 开启该模式后,Sink Writer会按固定间隔生成独立可播放的
moof+mdat片段,每个片段写完后会自动推送到绑定的字节流,已经刷入的内容无需调用Finalize即可正常播放,同时你可以持续写入后续的H264样本。
该模式输出的fMP4格式兼容性极强,目前几乎所有主流播放器、流媒体服务都支持该格式。
方案2:调整样本加载逻辑
如果必须输出标准非碎片化MP4,你不需要将所有样本提前加载到内存,只需要边生成/读取H264压缩帧边调用IMFSinkWriter::WriteSample喂给Sink Writer即可,Sink Writer内部的缓存为固定大小,不会随着视频总时长线性增长内存占用,最后调用Finalize一次性写入元数据即可。
方案3:拆分多段标准MP4
如果必须输出标准非碎片化MP4且要求已写入的部分随时可独立播放,可以按时间维度拆分输出任务,每写完一段就调用Finalize生成一个独立的MP4文件,后续要写入新内容时创建新的Sink Writer输出新文件即可,需要完整文件时可做后处理合并。
内容的提问来源于stack exchange,提问作者user16850544
相关产品推荐
相关产品推荐

