使用Sink Writer录制WMV时内存过高及文件合并问题咨询
关于Sink Writer录制WMV内存泄漏与分段录制合并的解决方案
问题1:录制过程中刷新Sink Writer释放内存
内存飙升的核心原因多为未及时释放媒体样本/缓冲区,或Sink Writer缓存未被强制写入磁盘。以下是针对性解决步骤:
- 强制写入磁盘并清空缓存:每写入若干帧(例如每5帧,对应1秒时长)后,调用
IMFSinkWriter::Flush方法,指定目标流索引(通常视频流为0,或用MF_SINK_WRITER_ALL_STREAMS处理所有流)。该操作会强制将缓存数据写入文件并释放内存,示例代码:HRESULT hr = pSinkWriter->Flush(MF_SINK_WRITER_ALL_STREAMS); if (FAILED(hr)) { // 处理错误逻辑 } - 确保媒体样本及时释放:每次调用
IMFSinkWriter::WriteSample完成帧写入后,必须调用IMFSample::Release()释放样本对象,同时确保关联的IMFMediaBuffer也被正确释放——这是多数内存泄漏案例的根源。 - 限制缓存时长:通过设置
MF_SINK_WRITER_MAX_BUFFER_DURATION属性,限制Sink Writer的最大缓存时长(例如设为1秒,单位为100纳秒),让系统自动触发写入,避免缓存无限增长:PROPVARIANT var; PropVariantInit(&var); var.vt = VT_I8; var.hVal.QuadPart = 10000000; // 1秒 HRESULT hr = pSinkWriter->SetProperty(MF_SINK_WRITER_MAX_BUFFER_DURATION, var); PropVariantClear(&var);
问题2:分段录制与WMV文件合并
分段录制实现
完全支持每10分钟生成一个独立WMV文件,实现步骤如下:
- 计算分段触发条件:按5FPS计算,10分钟对应3000帧;或通过系统时间戳判断录制时长。
- 达到分段条件时:
- 调用
IMFSinkWriter::Finalize完成当前文件写入,随后调用Release()释放当前Sink Writer实例。 - 复用之前的媒体类型参数(分辨率、帧率、码率、编码格式必须完全一致),重新创建Sink Writer并指定新的输出文件名,继续录制流程。
- 调用
WMV文件合并
WMV基于ASF容器,直接拼接文件会导致播放异常,需保证所有分段编码参数完全一致后,通过以下方式合并:
方式1:命令行工具(推荐)
使用FFmpeg工具完成合并,无需编写代码:
- 直接拼接命令:
ffmpeg -i "concat:segment1.wmv|segment2.wmv|segment3.wmv" -c copy merged.wmv - 若遇到格式检测问题,先创建文件列表
filelist.txt:
再执行:file 'segment1.wmv' file 'segment2.wmv' file 'segment3.wmv'ffmpeg -f concat -safe 0 -i filelist.txt -c copy merged.wmv
方式2:Media Foundation编程实现
通过Media Foundation读取分段流并写入合并文件:
- 为每个分段创建
IMFSourceReader,验证所有分段的媒体类型参数一致。 - 创建新的
IMFSinkWriter,设置与分段相同的输出媒体类型。 - 依次读取每个分段的媒体样本,调用
IMFSinkWriter::WriteSample写入合并文件。 - 所有分段读取完成后,调用
Finalize完成写入。
内容的提问来源于stack exchange,提问作者Drewski7280
相关产品推荐
相关产品推荐

