PHP调用FFmpeg时,-b:v和-crf不可混用,因二者代表互斥编码策略:-b:v用于带宽受限场景需配-maxrate/-bufsize,-crf推荐点播MP4(默认23);须校验并过滤用户输入的比特率,显式指定音频参数-b:a,动态设置-preset以平衡质量与速度。

PHP调用FFmpeg时,-b:v和-crf不能混用
直接在PHP里写exec("ffmpeg -i input.mp4 -b:v 1000k -crf 23 output.mp4")会导致FFmpeg报错或静默忽略其中一个参数——因为-b:v(固定比特率模式)和-crf(恒定质量模式)是互斥的编码策略。选错会导致输出文件体积失控或画质崩坏。
-
-b:v适合带宽受限场景(如CDN分发),但需配合-maxrate和-bufsize才能稳定输出;单独用-b:v可能造成码率抖动,尤其在动态画面多的视频里 -
-crf更推荐用于点播类MP4生成,默认值23,数值越小画质越高(18~23常见),但无法精确控制文件大小 - PHP中拼接命令时,必须先决定策略再选参数:要么用
-crf 23,要么用-b:v 1000k -maxrate 1200k -bufsize 2000k,不能同时出现
-preset影响比特率实际表现,不是“越快越好”
很多人以为-preset只影响转码速度,其实它会显著改变相同-b:v或-crf下的实际压缩效率。比如-preset fast在-crf 23下可能比-preset slow多占20%空间,而-b:v 1000k在-preset ultrafast下很可能达不到目标码率,反而触发码率溢出警告。
- 常规Web点播推荐
-preset medium,平衡速度与压缩率 - 批量后台转码可选
-preset slow,节省存储空间 - 实时上传场景慎用
-preset ultrafast,除非明确接受画质妥协 - PHP中不要硬编码
-preset,应根据任务类型动态传参,避免统一配置引发质量不一致
PHP里校验比特率输入,防止无效值传给FFmpeg
用户提交的比特率(如表单里的$bitrate = $_POST['bitrate'])若没过滤,可能传入"1000k -force_key_frames"这类恶意字符串,导致命令注入或FFmpeg参数错乱。FFmpeg对非法比特率值(如-b:v 0或-b:v 9999999k)不会报错,但会静默降级为默认行为,最终输出不可控。
- 只允许数字+单位后缀:
preg_match('/^\d+(k|M)$/', $bitrate),拒绝1000kb、1.5M等非标准写法 - 限制合理范围:
if ($bitrate_int 10000) die('Bitrate out of range'); - 单位统一转为k:
escapeshellarg($bitrate_int . 'k'),避免-b:v 1000k被拆成两个参数 - 用
shell_exec()捕获stderr,检查是否含"bitrate not specified"或"Invalid bitrate"字样
音频比特率要独立控制,别指望-b:v管到音频
新手常误以为设了-b:v 1000k就万事大吉,结果生成的MP4音质糊成一片——因为音频编码器(如aac)默认用极低码率(64k左右)。PHP脚本里必须显式指定-b:a,否则FFmpeg按编码器默认值处理,和视频码率完全无关。
立即学习“PHP免费学习笔记(深入)”;
- 语音为主的内容:用
-b:a 64k足够,节省体积 - 音乐/会议录像:至少
-b:a 128k,推荐-b:a 192k - 避免用
-q:a(VBR音频质量),它和-b:v组合时容易引发音画不同步 - PHP中建议固定音频参数:
-c:a aac -b:a 128k -ar 44100,不依赖用户输入
exec(),而是理解-crf和-b:v背后代表的两种完全不同的质量哲学——前者交付画质,后者交付带宽。很多线上问题,根源都在PHP层没把这层逻辑守住,让参数随意混搭或放行非法值。



















