9、封装格式转换:MKV转MP4、AVI转MOV等常见封装转换、保持流完整性
封装格式转换,说白了就是给视频文件「换壳」。
MKV、MP4、AVI、MOV 这些后缀,代表的是不同的容器格式。容器里面装的是视频流、音频流、字幕流、元数据。转换封装格式,就是把这些流原封不动地拿出来,塞进另一个容器里。
我刚开始做视频处理时,以为转换格式就是重新编码一遍。后来发现,大部分场景下根本不需要重新编码。直接「复制流」就行,速度快,质量无损。
9.1 核心思路:流复制(Stream Copy)
FFmpeg 里有个参数叫 -c copy,意思是「直接复制,不重新编码」。
你想想看,如果 MKV 里的视频是 H.264,MP4 也支持 H.264,那为什么要重新编码一遍?直接复制过来就行了。这样转换一个 4K 视频,可能只需要几秒钟,而不是几十分钟。
核心命令模板:
ffmpeg -i input.mkv -c copy output.mp4
这个命令的意思是:读取 input.mkv,所有流都直接复制,输出为 output.mp4。
我在项目中遇到过很多次,客户给的是 MKV 文件,但播放器只支持 MP4。用这个命令,几秒钟就搞定了。客户还以为我在「变魔术」。
9.2 常见封装转换场景
实际工作中,最常见的转换场景就这几个。我列个表,你一看就明白。
| 源格式 | 目标格式 | 命令示例 | 注意事项 |
|---|---|---|---|
| MKV | MP4 | ffmpeg -i input.mkv -c copy output.mp4 |
确保视频编码是 H.264/H.265,音频是 AAC/MP3 |
| AVI | MOV | ffmpeg -i input.avi -c copy output.mov |
AVI 里的旧编码(如 MJPEG)可能不被 MOV 支持 |
| MOV | MP4 | ffmpeg -i input.mov -c copy output.mp4 |
MOV 和 MP4 底层结构相似,兼容性最好 |
| FLV | MKV | ffmpeg -i input.flv -c copy output.mkv |
FLV 里的 AAC 音频可能需要额外处理 |
| TS | MP4 | ffmpeg -i input.ts -c copy -bsf:a aac_adtstoasc output.mp4 |
TS 流的音频需要 bitstream filter 转换 |
嗯,这里要注意。不是所有格式都能直接「复制流」转换。比如 MKV 里装的是 VP9 视频,MP4 就不支持 VP9。这时候 -c copy 会报错,你就得重新编码了。
9.3 保持流完整性的关键参数
直接 -c copy 确实快,但有时候会丢东西。比如字幕流丢了,或者元数据丢了。我踩过这个坑,后来总结了一套「保命参数」。
我的习惯用法:
ffmpeg -i input.mkv -map 0 -c copy -map_metadata 0 output.mp4
-map 0:保留所有流(视频、音频、字幕、数据流)-c copy:所有流都不重新编码-map_metadata 0:保留所有元数据(标题、日期、旋转信息等)
为什么要加 -map 0?因为 FFmpeg 默认只选一个视频流和一个音频流。如果你的 MKV 里有两条音轨、三条字幕,不加 -map 0 就全丢了。
我曾经帮一个朋友转他的婚礼视频,MKV 里有一条导演评论音轨。我没加 -map 0,转完 MP4 后那条音轨没了。朋友很生气,说「我岳父的解说没了」。从那以后,我每次转格式都默认加 -map 0。
9.4 处理不兼容的编码
有时候,源格式里的编码目标格式不支持。比如 MKV 里是 DTS 音频,MP4 不支持 DTS。这时候怎么办?
我的做法是:视频流复制,音频流重新编码。
ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 192k output.mp4
视频直接复制,音频转成 AAC,码率 192k。这样既保证了视频质量,又兼容了 MP4 的规范。
你想想看,如果整个文件重新编码,视频质量会下降,时间也长。只转音频,效率高得多。
9.5 字幕流的处理
MKV 转 MP4 时,字幕是个大坑。MKV 支持 ASS、SRT、PGS 等多种字幕格式。但 MP4 只支持「软字幕」(如 mov_text 或 timed text)。
直接 -c copy 会把 ASS 字幕也复制过去,但 MP4 播放器可能不认。我建议的做法是:
- 如果字幕是 SRT 文本格式,可以转成 MP4 支持的
mov_text - 如果字幕是 ASS(带特效),建议保留 MKV 格式,或者把字幕烧录进视频
- 如果字幕是 PGS(图形字幕),MP4 不支持,只能烧录或丢弃
字幕转换命令:
ffmpeg -i input.mkv -c:v copy -c:a copy -c:s mov_text output.mp4
这样会把所有字幕转成 MP4 兼容的格式。
9.6 实战:MKV 转 MP4 完整示例
假设我有一个 movie.mkv,里面包含:
- 1 条 H.264 视频流
- 2 条 AAC 音频流(英语、日语)
- 3 条字幕流(中文、英文、日文)
- 一些元数据(标题、封面)
我想转成 MP4,保持所有内容完整。我的命令是:
ffmpeg -i movie.mkv \
-map 0 \
-c copy \
-map_metadata 0 \
-movflags +faststart \
output.mp4
这里我加了一个 -movflags +faststart。这个参数的作用是把 MP4 的 moov 元数据移到文件头部。这样视频在网页上可以「边下边播」,不用等整个文件下载完。
我个人习惯,只要是转 MP4 用于网络分发,一定会加 +faststart。这个参数不改变画质,只改变文件结构,但用户体验提升很大。
9.7 实战:AVI 转 MOV
AVI 转 MOV 相对简单。AVI 是微软的老容器,MOV 是苹果的。两者底层结构不同,但 FFmpeg 处理得很好。
ffmpeg -i input.avi -c copy output.mov
但要注意,AVI 里经常出现一些「古老」的编码,比如 MJPEG、DV、MPEG-2。这些编码 MOV 容器不一定支持。如果报错,你就得重新编码了。
警告:AVI 文件经常有「索引损坏」的问题。如果转换时报错 Invalid data found when processing input,可以尝试先修复索引:
ffmpeg -i input.avi -c copy -fflags +genpts fixed.avi
然后再用修复后的文件转 MOV。
9.8 知识体系:封装转换的核心逻辑
下面这张图,是我总结的封装格式转换决策流程。你看完就明白什么时候该复制,什么时候该编码。
9.9 常见问题与避坑
我做了这么多年音视频,封装转换踩过的坑不少。挑几个典型的说说。
坑1:MP4 不支持某些音频格式
MP4 官方支持的音频格式只有 AAC、MP3、ALAC。如果你 MKV 里是 FLAC 或 DTS,直接 -c copy 会报错。解决方案:音频重新编码。
ffmpeg -i input.mkv -c:v copy -c:a aac output.mp4
坑2:MOV 转 MP4 时时间戳错乱
有些 MOV 文件的时间戳是「非连续」的。转成 MP4 后,播放器可能跳帧。我遇到过这种情况,解决方案是加 -fflags +genpts 重新生成时间戳。
ffmpeg -i input.mov -c copy -fflags +genpts output.mp4
坑3:字幕流丢失
不加 -map 0 的话,FFmpeg 默认只选一条字幕。我建议养成习惯,每次转格式都加 -map 0。
9.10 总结
封装格式转换,说白了就是「换壳不换芯」。核心原则就三条:
- 能复制就不编码:用
-c copy保持质量无损 - 保留所有流:用
-map 0防止丢失音轨和字幕 - 处理不兼容:只对不兼容的流重新编码,其他保持复制
你只要记住这三条,大部分封装转换场景都能搞定。遇到特殊情况,查一下 FFmpeg 文档,或者看看报错信息,基本都能解决。
公众号:蓝海资料掘金营,微信deep3321