基于事件动态录制RTSP视频流的FFmpeg实现方案问询
解决方案
针对你需要录制RTSP流中事件PTS前后10秒视频的需求,FFmpeg有几种低成本的适配方案,无需全量帧缓冲:
方案1:固定时长片段切割+事后拼接
预启动FFmpeg持续拉流,将视频按短时长(比如2秒)切割成小片段,同时记录每个片段对应的全局PTS范围,收到事件后匹配并拼接目标片段:
- 启动缓存FFmpeg进程(后台持续运行):
ffmpeg -i rtsp://your_rtsp_url -c copy -f segment -segment_time 2 -reset_timestamps 1 -strftime 1 "stream_cache/%Y%m%d_%H%M%S.mp4"
-segment_time 2:每2秒生成一个片段-reset_timestamps 1:每个片段内部时间戳从0开始,方便后续拼接-strftime 1:用时间戳命名片段,便于对应全局PTS
- 事件触发时,计算需要的时间范围(事件PTS-10到PTS+10),找出对应的缓存片段,用FFmpeg拼接并裁剪到精确时间:
ffmpeg -f concat -safe 0 -i <(printf "file '%s'\n" ./stream_cache/匹配的片段文件列表) -ss [片段内起始偏移] -to [片段内结束偏移] -c copy output.mp4
- 可通过脚本自动匹配片段:比如利用片段命名包含的时间戳对应全局PTS,筛选出覆盖目标时间范围的所有片段
- 优势:磁盘缓存成本低,可自动清理过期片段(比如只保留最近30秒的片段),实现简单
方案2:循环覆盖式MPEG-TS缓存流
利用MPEG-TS格式支持随机读取的特性,预启动FFmpeg将流输出到循环覆盖的TS文件,事件触发时直接截取:
- 启动循环缓存进程:
ffmpeg -i rtsp://your_rtsp_url -c copy -f mpegts -segment_wrap 30 -segment_time 1 "stream_cache/current_stream_%03d.ts"
-segment_wrap 30:最多保留30个1秒的TS片段,新片段会覆盖最旧的,自动控制缓存大小(这里是30秒)
- 事件触发时,根据全局PTS计算出在缓存流中的相对时间偏移,直接截取:
ffmpeg -i "concat:stream_cache/current_stream_*.ts" -ss [相对缓存起始的偏移秒数] -t 20 -c copy output.mp4
- 缓存30秒完全覆盖事件前后10秒的需求,无需担心视频流走
- 优势:TS格式截取无需重新编码,速度极快,循环覆盖无需手动清理
方案3:轻量级内存缓冲(适合小内存服务器)
如果不想用磁盘缓存,可利用FFmpeg的buffer滤镜在内存中缓存最近30秒的帧,不过需要结合外部控制触发录制:
预启动FFmpeg时,将流导入内存缓冲区,同时监听事件,事件触发时从缓冲区提取对应时间范围的帧进行封装。这种方式需要编写简单的控制逻辑,比如通过管道向FFmpeg发送指令,或者使用FFmpeg的zmq滤镜实现远程控制,复杂度稍高,但内存占用可控(缓存30秒1080P视频约几十MB)。
针对你的模拟代码调整建议
不要在事件触发时才启动FFmpeg,而是提前启动上述缓存进程;事件处理函数改为:
- 计算目标时间范围(
event.pts-10到event.pts+10) - 匹配缓存的片段/流
- 调用FFmpeg完成截取/拼接生成目标文件
内容的提问来源于stack exchange,提问作者ganjim
相关产品推荐
相关产品推荐

