PHP调用FFmpeg将MOV转MP4并保留元数据的关键是使用-c:v copy -c:a copy -map_metadata 0 -copy_unknown,配合escapeshellarg()安全执行;需FFmpeg≥4.0,必要时加-movflags +use_metadata_tags和-metadata:s:v:0 rotate=修复旋转信息。

PHP 调用 FFmpeg 将 MOV 转为 MP4 时保留元数据(如创建时间、地理位置、相机型号、旋转信息等),关键在于使用 -map_metadata 0 和 -copy_unknown,并避免重新编码视频/音频流(即用 -c:v copy -c:a copy)。只要源 MOV 的元数据存放在标准容器层(QuickTime / MP4 格式通用的 udta、meta box),FFmpeg 就能原样复制过去。
确保 FFmpeg 支持元数据复制
较新版本 FFmpeg(≥ 4.0)对 QuickTime 元数据兼容性更好。运行以下命令确认:
ffmpeg -version
若版本过低(如 3.x),建议升级。旧版可能跳过 com.apple.* 或 GPSCoordinates 等私有项,即使加参数也无效。
立即学习“PHP免费学习笔记(深入)”;
PHP 中安全调用命令(推荐 shell_exec + escapeshellarg)
不要拼接字符串,必须用 escapeshellarg() 防止路径含空格或特殊字符导致失败或命令注入:
$input = '/path/to/video.mov';
$output = '/path/to/video.mp4';
// 关键参数:-c:v copy -c:a copy 复用流;-map_metadata 0 复制所有元数据;-copy_unknown 保留未识别的 box
$cmd = sprintf(
'ffmpeg -i %s -c:v copy -c:a copy -map_metadata 0 -copy_unknown -y %s',
escapeshellarg($input),
escapeshellarg($output)
);
$outputLog = shell_exec($cmd . ' 2>&1');
if (strpos($outputLog, 'error') !== false || !file_exists($output)) {
throw new Exception("转换失败: " . $outputLog);
}
验证元数据是否保留成功
转完后用 ffprobe 检查:
ffprobe -v quiet -print_format json -show_format -show_streams "video.mp4"
重点关注 format.tags 下字段(如 creation_time, encoder, com.apple.quicktime.make)。也可用 exiftool 对比前后:
exiftool video.mov | grep -i "date\|make\|model\|gps"
exiftool video.mp4 | grep -i "date\|make\|model\|gps"
注意:部分 iOS 拍摄的 MOV 含有 com.apple.quicktime.location.ISO6709,FFmpeg 默认不映射为标准 GPSPosition,需额外加 -movflags +use_metadata_tags 才更兼容。
进阶:强制写入旋转信息 & 修复方向异常
有些 MOV 含 rotate 标签但 MP4 不自动应用。可显式提取并写入:
// 先读取原始旋转角度
$rotation = trim(shell_exec("ffprobe -v quiet -select_streams v:0 -show_entries stream_tags=rotate -of default=nw=1 $input"));
// 转换时加入旋转元数据(即使流是 copy,也能带 tag)
$cmd = sprintf(
'ffmpeg -i %s -c:v copy -c:a copy -map_metadata 0 -copy_unknown -metadata:s:v:0 rotate=%s -y %s',
escapeshellarg($input),
escapeshellarg($rotation ?: '0'),
escapeshellarg($output)
);
这样生成的 MP4 在支持 rotate tag 的播放器(如 VLC、iOS 相册)中会自动按正确方向显示。



















