关键不在PHP而在FFmpeg参数组合:CRF(18–23)动态分配码率优于固定码率,-movflags +faststart解决首帧加载卡顿,-pix_fmt yuv420p保障Web兼容,音频用-aac -b:a 96k兼顾体积与清晰度。

直接用默认参数转出来的 MP4 往往要么太大、要么糊得看不清——关键不在 PHP 本身,而在 FFmpeg 的编码策略和参数组合。PHP 只是调度器,真正决定体积和画质的是你传给 ffmpeg 的那些选项。
为什么 setKiloBitrate(500) 不靠谱
固定码率(CBR)对动态内容极不友好:片头静帧浪费带宽,动作场面又明显掉质量。现代转码应优先用 CRF(Constant Rate Factor),它让编码器按视觉复杂度动态分配码率。
-
-crf 18~23是合理区间:18 接近无损,23 是 Web 播放常用平衡点,再高就容易模糊 - 别混用
-b:v和-crf,FFmpeg 会报错或忽略后者 - PHP-FFmpeg 库的
setKiloBitrate()本质就是加-b:v,想用 CRF 得绕过封装,直接拼命令行或改用export()->withCustomParameters()
音频怎么省空间还不丢细节
视频文件里音频常占 15%–30% 体积,但人耳对压缩更宽容。盲目保留 AAC-LC 256kbps 是资源浪费。
- 用
-c:a aac -b:a 96k足够覆盖绝大多数人声/配乐场景,比默认 128k 省 25% - 若原始音频是单声道(如讲座、播客),强制
-ac 1可再减 30% 体积 - 避免
-strict -2:这是旧版 FFmpeg 兼容写法,新版已默认支持 AAC,留着反而可能触发警告
分辨率缩放必须配合像素格式重采样
只用 -vf scale=1280:720 缩放,不指定像素格式,FFmpeg 默认用 yuv420p —— 这没问题;但如果你从高色深源(如 10bit HDR)转出,没加 -pix_fmt yuv420p,部分播放器会直接黑屏或报错。
立即学习“PHP免费学习笔记(深入)”;
- Web 播放必须加
-pix_fmt yuv420p,否则 iOS/Safari 拒绝解码 - 缩放时加
-vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:0:0:0"自动居中补黑边,避免拉伸变形 - 如果源是竖屏短视频(如 TikTok),用
scale=720:-2保持比例,-2 表示自动算出兼容高度
moov atom 前置是卡顿的隐形杀手
FFmpeg 默认把索引信息(moov atom)写在文件末尾,浏览器要播前必须下载整个文件才能定位——50MB 视频拖进度条就得等十几秒。
- 加
-movflags +faststart把 moov 移到开头,首帧加载时间从秒级降到毫秒级 - PHP-FFmpeg 的
save()不自动启用该 flag,得手动:$video->export()->withCustomParameters(['-movflags', '+faststart'])->save($output) - 注意:加了 faststart 会延长转码时间几秒(因需二次扫描),但对用户感知是正向收益
最易被忽略的其实是输入源质量:用低码率 FLV 或 heavily compressed GIF 当输入,再怎么调参也救不回细节。转码不是魔法,是“有损压缩的有损压缩”。



















