PHP无法直接处理视频编解码,必须通过proc_open调用ffmpeg命令行实现RTSP转MP4;需强制指定-rtsp_transport tcp、分段录制时必加-reset_timestamps 1,并自行管理进程生命周期与异常恢复。

PHP本身不直接处理视频编解码,所谓“PHP视频转MP4”,本质是调用 ffmpeg 命令行完成转码/录制,PHP只负责拼参数、发命令、管生命周期。直接用 shell_exec 或 proc_open 调用 ffmpeg 是唯一可行路径,别信“纯PHP库能搞定RTSP转MP4”这种说法。
RTSP流拉取失败:-rtsp_transport tcp 必须加
海康、大华等主流摄像头默认走UDP,但UDP在NAT或防火墙后极易卡住、花屏甚至连接超时。不显式指定传输协议,ffmpeg 会尝试 UDP → TCP 回退,但回退过程不可控,经常直接失败。
- 必须在
-i参数前加上-rtsp_transport tcp,例如:ffmpeg -rtsp_transport tcp -i rtsp://admin:12345@192.168.1.100:554/stream1 - 如果仍失败,可追加
-stimeout 5000000(单位微秒,即5秒),避免因网络抖动导致 ffmpeg 卡死在连接阶段 - 某些固件老旧的设备(如部分安讯士)需改用
-rtsp_transport http,但极少见
分段录制MP4:-f segment + -reset_timestamps 1 是关键
直接用 -f mp4 写单个大文件会导致无法中断、难以索引、且出错时整段丢失。生产环境必须分段,但 MP4 原生不支持无缝分段——ffmpeg 的 segment muxer 实际是“伪MP4”,靠重写 moov 头实现,必须配合时间戳重置,否则后段播放会卡顿或黑屏。
- 正确写法:
-f segment -segment_time 300 -reset_timestamps 1 -strftime 1 output_%Y-%m-%d_%H-%M-%S.mp4 -
-reset_timestamps 1不可省略,否则每段起始 PTS 不归零,播放器会认为时间跳变而卡住 -
-strftime 1允许在文件名中使用日期格式,但 Windows 下需确保路径分隔符为/或双反斜杠\,否则ffmpeg报错Invalid argument - 不要用
-c:v copy -c:a copy配合分段——I帧边界不一定对齐-segment_time,会导致首帧丢失或花屏;稳妥做法是至少重编码视频(如-vcodec libx264 -preset ultrafast)
PHP执行阻塞与后台管理:proc_open 比 shell_exec 更可靠
shell_exec 会等待 ffmpeg 完全退出才返回,而 RTSP 录制是长期运行任务,PHP 脚本超时(默认30秒)或被 Nginx/Apache kill 掉,导致进程残留、磁盘写满。
立即学习“PHP免费学习笔记(深入)”;
- 必须用
proc_open启动非阻塞子进程,并将stdout和stderr重定向到文件或管道,避免缓冲区满导致ffmpeg挂起 - 记录子进程 PID 到文件(如
/tmp/rtsp_recorder_123.pid),后续可通过kill $(cat /tmp/rtsp_recorder_123.pid)安全终止 - PHP 进程退出前务必调用
proc_close或proc_terminate,否则僵尸进程累积 - Linux 下建议加
nohup和> /dev/null 2>&1 &双重保险,但 PHP 层面仍要自己管 PID
真正麻烦的不是命令怎么写,而是 ffmpeg 进程状态不可见、崩溃无通知、磁盘满不报警、RTSP 断连后不自动重连——这些都得自己补监控和恢复逻辑,别指望 PHP 一行 shell_exec 就能稳跑一周。



















