ffmpeg是实际执行转码与切片的核心工具,php仅负责调用命令、管理流程和生成符合hls/dash协议的清单文件;多清晰度自适应播放成败取决于ffmpeg命令的精准性、输出结构合规性及web服务器对.m3u8/.ts文件的正确响应。

ffmpeg 是实际干活的,PHP 只是发号施令的——想让视频支持多清晰度自适应播放,核心不在 PHP 写多少行代码,而在转码命令是否精准、输出结构是否符合 HLS 或 DASH 协议要求。
用 ffmpeg 一次性生成多分辨率 HLS 切片
直接跑单条命令就能产出多个清晰度的 .ts 文件和对应 .m3u8 清单,这是最常用也最容易出错的环节。
常见错误现象:生成的 medium.m3u8 播放正常,但 low.m3u8 打不开,或主清单 master.m3u8 里路径错乱、缺少 BANDWIDTH 标签。
- 必须为每个输出流显式指定 -hls_playlist_type vod(点播)或 event(直播),否则默认行为可能不一致
- 每个 -vf scale=xxx:yyy 后必须紧跟对应的 -b:v 和 -c:v libx264,顺序错位会导致后一个流复用前一个流的参数
- 主清单 master.m3u8 需手动拼接,ffmpeg 不会自动创建;可用 echo 命令追加,但更稳妥的是用 PHP 读取各子清单后动态写入
ffmpeg -i input.mp4 \ -vf scale=1280:720 -c:v libx264 -b:v 2500k -an -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "720p_%03d.ts" 720p.m3u8 \ -vf scale=854:480 -c:v libx264 -b:v 1200k -an -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "480p_%03d.ts" 480p.m3u8 \ -vf scale=640:360 -c:v libx264 -b:v 600k -an -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "360p_%03d.ts" 360p.m3u8
PHP 调用 ffmpeg 时必须检查返回值和错误流
exec() 或 shell_exec() 看似简单,但静默失败很常见。
- $returnCode 为 0 仅表示进程退出正常,不代表转码成功;FFmpeg 出错常写入 stderr,而默认被丢弃
- 推荐用 proc_open() 捕获 stderr 输出,至少记录前 20 行错误日志
- 若使用 exec("ffmpeg ...", $output, $returnCode),务必确认 $output 数组非空且含关键提示(如 “frame=”, “speed=”),避免误判成功
容易踩的坑:exec() 在某些 PHP-FPM 配置下会被禁用,或因 open_basedir 限制无法访问 ffmpeg 二进制文件;建议先用 which ffmpeg 测试路径,再在命令中写绝对路径(如 /usr/bin/ffmpeg)
HLS 主清单 master.m3u8 的手动生成要点
浏览器靠它识别可用清晰度,格式稍有偏差就无法加载。
- 每个 EXT-X-STREAM-INF 行必须包含 BANDWIDTH(单位 bit/s)、RESOLUTION 和 AUDIO(若含音频)
- URI 必须是相对路径或可公开访问的 URL,不能是本地文件路径
- 子清单(如 720p.m3u8)本身需为标准 HLS 格式,即每行以 #EXTINF: 开头,后跟 .ts 文件名
示例片段:
#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.64001f" 720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1200000,RESOLUTION=854x480,CODECS="avc1.64001f" 480p.m3u8
前端播放器能否切换清晰度,和 PHP 关系不大
PHP 只负责把master.m3u8 或各清晰度 MP4 地址准备好,切换逻辑全在前端。
- Video.js + videojs-contrib-hls(HLS)或 videojs-contrib-dash(DASH)才能真正解析并切换
- 若用 <source></source> 标签硬写多个 MP4,切换是“重新加载整个视频”,不是平滑自适应;只有 HLS/DASH 才支持边播边切
- PHP 动态输出地址时(如 get_video.php?quality=720),务必校验 $_GET['quality'] 是否在白名单内,防止目录遍历(如 quality=../../../etc/passwd)
真正的难点不在命令怎么写,而在于确保每个 .ts 文件能被 Web 服务器直接响应、每个 .m3u8 的路径可被播放器正确解析、以及当用户网络波动时,播放器能从主清单里选到下一个合适的流——这些细节一旦漏掉,前端再 fancy 也播不出画面。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











