必须将moov atom移至文件开头,否则浏览器无法边下载边播放;需显式指定H.264视频、AAC音频、yuv420p像素格式及-movflags +faststart参数,缺一不可。

PHP 本身不处理视频编码,所谓“PHP转H264 MP4”,本质是用 PHP 调用 ffmpeg 命令完成转码,并确保输出满足 Web 和主流播放器的硬性要求:H.264 视频流 + AAC 音频流 + moov atom 在文件开头。跳过这三点,哪怕命令跑通,也大概率在 Safari、iOS 或某些安卓设备上无法播放或拖拽卡死。
为什么直接 exec('ffmpeg -i in.mp4 -c:v libx264 out.mp4') 不够用
这条命令看似正确,但实际生成的 MP4 文件常因以下原因被播放器拒收:
-
moovatom 默认写在文件末尾,浏览器无法边下载边播放(无Range支持) - 音频可能被忽略或编码为不兼容格式(如 MP3),导致 iOS 拒绝解码
- 未指定
-pix_fmt yuv420p,部分移动端解码器会黑屏或报错 - 未加
-movflags +faststart,就无法实现首帧秒开
正确写法必须显式补全关键参数:
ffmpeg -i input.mp4 \ -c:v libx264 \ -pix_fmt yuv420p \ -c:a aac \ -b:a 128k \ -movflags +faststart \ output.mp4
PHP 中调用 ffmpeg 的安全执行要点
直接拼接字符串调用 exec() 极易被注入攻击或路径错误中断。必须做三件事:
- 所有文件路径用
escapeshellarg()包裹,尤其用户上传的文件名含空格或单引号时 - 使用绝对路径调用
ffmpeg(如/usr/bin/ffmpeg),避免因 PHP 工作目录不确定导致命令找不到 - 检查
$return_code,非 0 就失败;同时捕获$output数组看具体报错(如No such file or directory或Permission denied)
示例片段:
立即学习“PHP免费学习笔记(深入)”;
$input = escapeshellarg('/var/www/uploads/user_123.mov');
$output = escapeshellarg('/var/www/output/h264_123.mp4');
$cmd = '/usr/bin/ffmpeg -y -i ' . $input . ' -c:v libx264 -pix_fmt yuv420p -c:a aac -movflags +faststart ' . $output . ' 2>&1';
exec($cmd, $log, $code);
if ($code !== 0) {
error_log("FFmpeg failed: " . implode("\n", $log));
}
Web 播放前必须验证的三个文件属性
生成 MP4 后别急着扔进 <video></video> 标签——先确认它真能播:
- 用
ffprobe -v quiet -show_entries stream=codec_name,width,height -of default=nw=1 input.mp4查视频流是否为codec_name=h264、音频流是否为codec_name=mp4a(即 AAC) - 用
ffmpeg -i input.mp4 -c copy -f null -快速验证文件结构是否可读(无报错即基本可用) - 用浏览器开发者工具 Network 面板打开该 MP4 URL,看响应头是否含
Accept-Ranges: bytes——没有就说明faststart没生效或 Web 服务器未启用 Range 支持
Nginx/Apache 对 MP4 的基础配置不能漏
即使 ffmpeg 输出完全合规,Web 服务器没配对,前端照样播不了:
- Nginx 必须有
types { video/mp4 mp4; },否则返回text/plainMIME 类型,浏览器当文本渲染 - Apache 需启用
mod_mime并确保AddType video/mp4 .mp4在配置中生效 - 若用 CDN,确认其未缓存错误响应(比如 404 后又生成了空 MP4 文件,CDN 会一直回源失败)
最简验证方式:curl -I https://yoursite.com/uploads/test.mp4,看 Content-Type 是否为 video/mp4。
moov 位置、yuv420p 格式、MIME 配置这三处无声无息的失效点。每一步都得亲手验证,而不是相信“命令跑完了就万事大吉”。



















