PHP不能直接处理视频帧率,需调用ffmpeg;-r仅修改封装帧率,-vf fps才真正重采样;防命令注入须用escapeshellarg(),慢动作需setpts+fps配合,高质量输出应配preset和GOP参数。

PHP 能直接处理视频帧率吗?不能,别硬上
PHP 本身没有视频编解码能力,ffmpeg 才是实际干活的。PHP 只能调用它——通过 exec()、shell_exec() 或 proc_open() 发起系统命令。试图用 PHP 原生函数读取、解析、重采样视频帧,只会卡死或崩溃。
常见错误现象:Allowed memory size exhausted、脚本超时、输出空文件、生成的视频无声或花屏。
- 必须确认服务器已安装
ffmpeg,且 PHP 进程有执行权限(尤其在 Docker 或 shared hosting 环境下常被禁用) - 不要用
file_get_contents()读整个视频——哪怕 10MB 的 MP4 也会爆内存 - PHP 中所有路径务必用绝对路径,相对路径在 CLI 和 Web 环境下行为不一致
调整帧率:-r 和 -vf fps 有什么区别?选错就丢帧
-r 是输出封装帧率(容器级),-vf fps= 是滤镜级重采样(真正重绘帧)。慢动作必须用后者,否则只是“骗”播放器——源帧没变,只是告诉播放器“每秒播多少帧”,结果就是跳帧或卡顿。
例如把 30fps 视频变成 2× 慢动作(即视觉上每秒显示 15 帧内容),正确做法是保持原帧数、拉长时长:
立即学习“PHP免费学习笔记(深入)”;
ffmpeg -i input.mp4 -vf "setpts=2*PTS,fps=30" -c:a copy output_slow.mp4
说明:setpts=2*PTS 把每帧显示时间翻倍(实现慢放),fps=30 强制输出仍为 30fps(避免播放器误判),音频用 -c:a copy 不重编码(省时且保质)。
- 如果只要“看起来慢”,但不关心音画同步,可只用
-filter:v "setpts=2*PTS",音频需同步处理(加-af "atempo=0.5") -
atempo最大只支持 2.0,要更慢就得链式使用:atempo=0.5,atempo=0.5→ 0.25× - 用
-r 15直接降帧率 = 删除帧,不是慢动作,是抽帧卡顿
PHP 调用 ffmpeg 时怎么防超时和注入?别信用户传的文件名
用户上传的 filename 如果含空格、分号、$()、反引号,直接拼进 exec() 就是远程命令执行漏洞。同时视频转码动辄几十秒,max_execution_time 默认 30 秒根本不够。
- 用
escapeshellarg()包裹每个外部输入:路径、文件名、参数值,例如escapeshellarg('/tmp/upload/'.$user_file) - 改
set_time_limit(0)前,先检查是否 CLI 模式(Web 模式下可能被 SAPI 限制,无效) - 用
proc_open()替代exec():能捕获 stderr 实时日志,便于定位Invalid argument to option 'vf'这类语法错 - 务必加
-y参数自动覆盖输出文件,否则遇到同名文件会阻塞等待 stdin 输入 y/n
慢动作质量差?关键在编码参数和 GOP 设置
默认 ffmpeg 编码用的是快速模式,B帧少、GOP 长,慢动作一拉伸就糊。不是 PHP 问题,是编码器没配对。
实操建议:
- 加
-preset slow或-preset medium提升压缩效率(时间换质量) - 显式指定
-g 30(GOP 大小设为 30 帧),避免默认 250 帧导致关键帧太稀疏 - 慢动作后若画面抖动,加
-vf "minterpolate='mi_mode=mci:mc_mode=aobmc:vsbmc=1'"插帧(但 CPU 开销极大,慎用) - 输出用
-c:v libx264,别用-c:v copy——那是直接复制流,setpts 不生效
复杂点在于:插帧、高质量编码、音频变速三者叠加时,内存和 CPU 消耗陡增,单次请求很容易超限。真要稳定产出,得拆成队列异步处理,PHP 只负责扔任务、查状态。



















