FFmpeg 原始视频、RTSP、转码与服务集成
FFmpeg 实战使用:原始视频、RTSP、转码与服务集成 本文按 FFmpeg 整理(原请求中的 “Ffmppe” 按常见拼写误差处理)。重点记录在摄像头、嵌入式设备和 BinBot 服务中的可复用做法。 1. 工具分工 ffmpeg :读取输入、解码、滤镜处理、编码并输出文件或流。 ffprobe :只读探测媒体元
FFmpeg 实战使用:原始视频、RTSP、转码与服务集成
本文按 FFmpeg 整理(原请求中的 “Ffmppe” 按常见拼写误差处理)。重点记录在摄像头、嵌入式设备和 BinBot 服务中的可复用做法。
1. 工具分工
ffmpeg:读取输入、解码、滤镜处理、编码并输出文件或流。ffprobe:只读探测媒体元数据,适合确认编码、分辨率、帧率、时长和流数量。ffplay:快速预览,尤其适合排查原始视频的像素格式、分辨率和帧率是否匹配。
先确认安装和编解码器:
ffmpeg -version
ffprobe -version
ffmpeg -encoders | grep -E 'libx264|aac|libopus'
容器或服务进程中不要只依赖 PATH。配置文件中显式指定绝对路径,例如:
ffmpeg_path = "/usr/bin/ffmpeg"
2. 原始 YUV 视频预览
原始 .yuv 文件没有容器元数据,播放器不知道像素格式、尺寸和帧率,三个参数必须由采集端或驱动确认。
YUYV422
ffplay -f rawvideo -pixel_format yuyv422 -video_size 640x480 -framerate 30 -i video.yuv
NV16
ffplay -f rawvideo -pixel_format nv16 -video_size 640x480 -framerate 10 -i video.yuv -vf format=yuv420p
-pixel_format 是 ffplay 的输入参数;用 ffmpeg 处理 rawvideo 时通常写成 -pix_fmt:
ffmpeg -f rawvideo -pix_fmt nv16 -video_size 640x480 -framerate 10 -i video.yuv -c:v libx264 -preset ultrafast -crf 23 -pix_fmt yuv420p output.mp4
原始视频排错规律
- 画面有明显色偏:优先检查
yuyv422、nv12、nv16是否选错。 - 画面倾斜、撕裂或滚动:检查宽高和每行 stride,确认文件是否包含 padding。
- 播放速度不对:检查
-framerate;rawvideo 不携带时间戳。 - 播放器提示输入不足:检查文件大小是否满足
帧数 × 每帧字节数,并确认采集是否被截断。 - 兼容性差:编码 H.264 后补
-pix_fmt yuv420p,多数浏览器和硬件播放器更容易解码。
可以用 ffprobe 带上同样的原始视频参数做基础检查:
ffprobe -v error -f rawvideo -pixel_format yuyv422 -video_size 640x480 -framerate 30 -show_entries frame=pkt_size -of default=noprint_wrappers=1 video.yuv
3. RTSP 摄像头流
嵌入式摄像头链路中,优先使用 TCP 传输,避免无线或交换网络丢包造成花屏:
ffprobe -v error -rtsp_transport tcp -show_entries stream=codec_name,width,height,avg_frame_rate <camera-rtsp-url>
抓取一帧作为设备或 UI 参考图:
ffmpeg -y -rtsp_transport tcp -i <camera-rtsp-url> -frames:v 1 camera-reference.jpg
排查 RTSP 时按顺序确认:
- 设备端服务是否在运行。
- TCP 端口是否可达。
ffprobe是否能拿到 codec、宽高和帧率。- 再用
ffmpeg解码少量帧,避免把网络问题误判为编码问题。
4. HLS 或转发链路验证
链路验证不需要保存输出文件,直接解码到空输出即可:
ffmpeg -hide_banner -loglevel error -i <hls-playlist-url> -frames:v 30 -f null -
命令成功只能说明 FFmpeg 能拉取并解码这段媒体;浏览器仍可能受跨域、MIME 类型、HLS.js 支持或网络可达性影响,需要单独检查播放页面和 .m3u8 响应。
5. GIF 规范化的工程做法
上传 GIF、PNG、JPEG 或 WebP 后,如果下游 UI 只接受固定 GIF 规格,可以统一转成 216x216、12.5 FPS,并保留透明背景:
ffmpeg -hide_banner -loglevel error -y -i input.gif -filter_complex "fps=12.5,scale=216:216:force_original_aspect_ratio=decrease:flags=lanczos,pad=216:216:(ow-iw)/2:(oh-ih)/2:color=black@0.0,split[s0][s1];[s0]palettegen=reserve_transparent=1[p];[s1][p]paletteuse=dither=sierra2_4a" -f gif normalized.gif
服务端集成时要同时做好这些保护:
- 先限制上传大小,再落盘。
- 校验文件头,不要只相信扩展名。
- 使用参数数组调用
subprocess,不要拼接 shell 字符串。 - 设置超时,并检查返回码、目标文件存在性和最小文件大小。
- 通过临时文件写入,成功后再
os.replace为最终文件。 - 无论成功或失败都清理输入和中间文件。
- 对生成后的 GIF 再次检查大小,防止转码放大绕过限制。
6. RTSP 转 MJPEG 给浏览器
浏览器不能直接消费所有 RTSP 流时,可以由服务端启动受控的 FFmpeg 子进程:
ffmpeg -hide_banner -loglevel error -rtsp_transport tcp -i <camera-rtsp-url> -an -r 8 -q:v 5 -f mpjpeg -boundary_tag binbotframe pipe:1
HTTP 响应使用:
Content-Type: multipart/x-mixed-replace; boundary=binbotframe
服务端要在首个视频块到达前设置启动超时;客户端断开、取消请求或读取异常时终止子进程,否则会留下孤儿 FFmpeg 进程和持续占用的 RTSP 连接。
7. 常用参数速查
| 参数 | 作用 | 经验 |
|---|---|---|
-f rawvideo |
声明输入是裸视频 | 必须配合像素格式、尺寸、帧率 |
-pix_fmt / -pixel_format |
指定像素格式 | ffmpeg 常用 -pix_fmt,ffplay 常用 -pixel_format |
-video_size 640x480 / -s 640x480 |
指定尺寸 | 尽量使用采集端真实输出尺寸 |
-framerate 30 / -r 30 |
输入或输出帧率 | 输入 rawvideo 时要放在输入参数区域 |
-c:v libx264 |
H.264 编码 | 兼容性和体积通常较平衡 |
-preset ultrafast |
编码速度档位 | 低延迟或嵌入式转码优先,文件会更大 |
-crf 23 |
恒定质量 | 数值越小质量越高、体积越大 |
-rtsp_transport tcp |
RTSP 使用 TCP | 网络不稳定时优先尝试 |
-frames:v 1 |
只输出一帧 | 适合抓图和健康检查 |
-f null - |
丢弃输出 | 适合验证能否持续解码 |
8. 最小排错清单
- 用
ffprobe先确认输入流,不要直接猜参数。 - 原始视频先用
ffplay预览,再开始编码。 - 把输入参数和输出参数分开看,特别是
-r、-pix_fmt和-f。 - 需要浏览器播放时,优先输出 H.264 +
yuv420p,或由服务端转 MJPEG/HLS。 - 服务端记录 FFmpeg 的退出码和最后一段 stderr,但不要把完整输入 URL 中的敏感查询参数写入日志。
- 对每个长时间运行的 FFmpeg 进程设置超时、取消处理和资源回收。