ffmpeg命令行可直接截取rtmp流,-ss必须置于-i前实现输入侧seek,否则因rtmp无随机访问能力会导致花屏或时长不准;配合-c copy、-avoid_negative_ts make_zero及正确pts处理,即可稳定完成定时录制与裁切。

ffmpeg命令行直接截取RTMP流最简单
不用写C++也能完成需求:FFmpeg本身支持从RTMP拉流并按时间窗口保存为本地文件,90%的剪辑场景用命令就行。关键不是“能不能用C++”,而是“有没有必要用C++”。如果只是定时录几段、按秒裁切、转封装,ffmpeg命令足够稳定且调试快。
常见错误是直接用-ss + -t在RTMP源上硬切,结果首帧花屏或时长不准——因为RTMP没有随机访问能力,-ss必须放在输入参数前(即“输入侧seek”),否则会先解码再丢帧,延迟大还不准。
-
ffmpeg -i "rtmp://example.com/live/stream" -ss 00:01:20 -t 30 -c copy -f mp4 output.mp4→ 错误:-ss放后面,实际从连接开始解码后才截,不准 -
ffmpeg -ss 00:01:20 -i "rtmp://example.com/live/stream" -t 30 -c copy -f mp4 output.mp4→ 正确:-ss在-i前,FFmpeg尝试在协议层跳转(依赖服务器支持) - 若服务器不支持seek(如多数Nginx-rtmp),则必须用
-c:v copy -c:a copy配合-avoid_negative_ts make_zero防止时间戳错乱
用libavcodec/libavformat写C++要绕开RTMP协议栈
FFmpeg的C API本身不处理RTMP;它靠librtmp(或libswscale等)作为第三方协议后端。你调avformat_open_input()打开"rtmp://..." URL时,背后其实是librtmp在干活。这意味着:不能假设RTMP连接行为和本地文件一致,尤其超时、重连、断流恢复都得自己管。
容易踩的坑是忽略AVFormatContext->interrupt_callback——RTMP流可能卡住不动,av_read_frame()会无限阻塞。必须设回调函数+超时逻辑,否则程序假死。
- 初始化时务必调
avformat_network_init(),否则RTMP/HTTP等网络协议不可用 -
avformat_find_stream_info()对RTMP可能耗时长甚至失败,可设fmt_ctx->probesize = 1024*1024和fmt_ctx->max_analyze_duration = 5000000限制分析深度 - 音频/视频流时间基(
time_base)来自服务器,不一定等于AV_TIME_BASE_Q,计算PTS时别硬除,要用av_rescale_q()
保存剪辑的关键是PTS控制而非单纯计数帧
RTMP流没有全局时间线,每帧的PTS是相对于流启动时刻的。想截取“从第80秒开始的30秒”,不能靠frame_count * frame_duration估算,必须用PTS做判断。而且不同流的时间基不同,比如H.264流常用{1, 1000},AAC音频可能是{1, 44100}。
典型做法是记录第一个视频包的pkt.dts(或pts),然后把目标起始时间(如80秒)换算成该流的时间基单位,再逐包比较。注意:AVPacket.dts可能为AV_NOPTS_VALUE,此时需回退到pts或用前序包推算。
- 起始时间换算:
target_dts = av_rescale_q(80 * AV_TIME_BASE, AV_TIME_BASE_Q, stream->time_base) - 保存条件:当
pkt.dts != AV_NOPTS_VALUE && pkt.dts >= target_dts && pkt.dts - 务必用
av_interleaved_write_frame()写入,否则音视频包顺序错乱,播放器无法同步
输出MP4必须处理moov位置和B帧依赖
RTMP流里H.264通常带B帧,而MP4容器要求关键帧(IDR)开头。直接把截下来的包喂给avformat_write_header()再写帧,大概率生成无法播放的文件——要么没moov box,要么第一帧不是IDR。
解决方案只有两个:一是用-c copy模式(命令行)或C++中复用原始packet(不做解码/重编码),但要求起始点恰好是IDR帧;二是解码+重新编码,确保输出第一帧是IDR。后者更可靠但CPU贵。
- 判断IDR帧:
if (pkt->flags & AV_PKT_FLAG_KEY && codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) - 写MP4前必须调
avformat_write_header(),且AVFormatContext.oformat->flags含AVFMT_GLOBALHEADER时,需手动设置codec_ctx->extradata - 用
av_write_trailer()关闭输出——漏掉这步,文件末尾moov缺失,几乎所有播放器打不开
真正麻烦的不是代码量,而是RTMP流的不可控性:服务器时间戳漂移、关键帧间隔不定、网络抖动导致包乱序。哪怕逻辑写对,实测时仍要反复调av_packet_rescale_ts()和丢弃非单调DTS包。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











