You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何让FFmpeg将子秒级间隔的分段视频立即写入磁盘(树莓派录制场景)

如何让FFmpeg将子秒级间隔的分段视频立即写入磁盘(树莓派录制场景)

我之前在树莓派上做视频录制备份的时候,刚好碰到过一模一样的问题——断电后分段文件全是空的,用了-strftime又遇到子秒级命名重复覆盖的坑。给你两个亲测可行的解决方案:

方案一:不用-strftime,强制FFmpeg实时刷新分段文件到磁盘

你遇到的空文件问题,本质是MP4容器的特性:它默认会把关键元数据(比如moov atom)缓存到内存,直到文件正常关闭才写入磁盘,断电时这些缓存内容直接丢失,导致文件变成空的。我们不需要依赖-strftime来触发写入,直接给MP4分段器加参数就能强制实时刷新:

修改你的FFmpeg命令,重点调整-segment_format_options部分:

libcamera-vid --flush \
--framerate ${FRAMERATE} \
--width ${WIDTH} \
--height ${HEIGHT} \
-n \
-t ${TIMEOUT} \
--codec yuv420 \
-o - |
ffmpeg \
-fflags nobuffer \
-strict experimental \
-loglevel debug \
-flags low_delay \
-f rawvideo \
-pix_fmt yuv420p \
-s:v ${WIDTH}x${HEIGHT} \
-r ${FRAMERATE} \
-i - \
-c:v h264_v4l2m2m \
-f segment \
-segment_time 0.1 \
-segment_format mp4 \
# 新增的关键参数,强制实时刷新磁盘
-segment_format_options movflags=flush_packets+empty_moov+faststart \
-reset_timestamps 1 \
-b:v ${ENCODING_BITRATE} \
-g 1 \
"output_%04d.mp4"

参数解释:

  • movflags=flush_packets:强制FFmpeg把每个视频数据包立即刷新到磁盘,不再缓存
  • empty_moov:在文件开头生成一个空的moov元数据块,后续实时更新内容,避免依赖最终写入
  • faststart:把moov元数据移到文件头部,方便后续直接播放分段文件(可选但推荐)

另外你已经给libcamera-vid加了--flush,这个很关键,能确保摄像头的原始数据不被缓存,直接传给FFmpeg,避免上游环节的延迟。

方案二:修复-strftime的子秒级命名问题,保留实时写入特性

如果你还是想用-strftime来触发实时写入(虽然方案一更直接),可以用FFmpeg扩展的strftime格式来生成唯一的子秒级文件名:

把输出文件名从"output_%04d.mp4"改成:

"output_%s%3N.mp4"

这样每个100ms的分段会生成类似output_1700000000123.mp4的文件名:

  • %s是当前Unix时间戳(秒级)
  • %3N是毫秒部分(FFmpeg对标准strftime的扩展,%6N是微秒,%9N是纳秒)

这个格式能保证每个分段的文件名唯一,不会因为子秒级分段而被覆盖。如果你想同时保留序列数,也可以写成"output_%s%3N_%04d.mp4",兼顾时间戳和序号标识。

注意:你之前试的%f是Python等语言的格式,FFmpeg的strftime不支持,所以才会直接输出%f字符串。

备注:内容来源于stack exchange,提问作者amfast

火山引擎 最新活动