3. MediaMuxer支持的输出格式:MP4、WebM、3GPP等,以及如何选择合适的格式

聊到MediaMuxer,第一个要面对的问题就是:到底该选什么输出格式?

我记得刚接触MediaMuxer那会儿,看到它支持的格式列表,心里还挺高兴——MP4、WebM、3GPP,三个选项,够用了。但真正上手做项目才发现,选错格式,后面全是坑。今天我就把这三个格式的底细给你讲透。

3.1 三种格式的官方定义

MediaMuxer在Android API 18(Android 4.3)中首次引入,支持三种输出格式,定义在MediaMuxer.OutputFormat中:

常量 对应格式 引入API级别 容器类型
MUXER_OUTPUT_MPEG_4 MP4 API 18 ISO Base Media File Format
MUXER_OUTPUT_WEBM WebM API 21 Matroska衍生格式
MUXER_OUTPUT_3GPP 3GPP API 18 基于MP4的3GPP规范

说白了,MP4和3GPP是亲戚,底层都是ISO BMFF结构。WebM则是另一条路线,基于Matroska(MKV)的简化版。

3.2 逐个拆解:MP4

MP4 是使用最广泛的格式,没有之一。我个人的习惯是:只要不是特殊需求,默认选MP4

MP4的核心优势:

  • 兼容性极强:几乎所有播放器、社交平台、浏览器都支持
  • 支持H.264/H.265 + AAC的黄金组合
  • 支持快进快退、章节标记、元数据
  • 支持moov box前置(用于流式播放)

我在项目中遇到过一个问题:用MP4封装H.265视频,在部分旧款手机上播放黑屏。后来发现是MediaMuxer生成的MP4里,avcChvcC box的配置数据顺序不对。嗯,这里要注意——MP4虽然通用,但编码器兼容性还是得测

3.3 逐个拆解:WebM

WebM 是Google主推的开放格式,专门为Web场景设计。它只支持VP8/VP9视频编码和Vorbis/Opus音频编码。

你想想看,为什么会有WebM?因为MP4的专利授权问题。Google想要一个完全免专利费的容器格式,于是WebM就诞生了。

什么时候用WebM?

  • 你的应用主要面向WebView或Chrome浏览器
  • 你需要使用VP9编码(同等画质下比H.264体积小50%)
  • 你希望完全规避MPEG LA的专利授权

我曾经在一个短视频编辑App里尝试用WebM输出VP9编码的视频,结果发现MediaMuxer对WebM的支持有点「半成品」——不支持添加字幕轨道,也不支持自定义元数据。所以如果你需要这些功能,WebM可能不太合适。

3.4 逐个拆解:3GPP

3GPP 格式,说白了就是MP4的一个变种,专门为3G/4G移动网络设计。它的文件扩展名通常是.3gp

我记得早期功能机时代,3GP是手机视频的标配。现在嘛……说实话,我几乎不用它了。除非你的应用需要兼容非常老旧的Android设备(API 18以下),或者需要与某些电信设备交互。

3GPP的局限性:

  • 视频编码通常限制为H.263或MPEG-4 SP(画质差)
  • 音频编码通常限制为AMR-NB或AAC-LC
  • 不支持高清分辨率(超过720p可能出问题)
  • 大部分现代播放器对3GP的支持反而不好

3.5 如何选择合适的格式?

这个问题,我一般用一个简单的决策树来解决:

选择输出格式 需要Web播放? 需要兼容旧设备? WebM (VP9/Opus) MP4 (H.264/AAC) 3GPP (H.263/AMR) MP4 (默认选择) 💡 我的建议: 90%的场景选MP4,Web场景选WebM,兼容旧设备选3GPP

这个决策树是我在实际项目中总结出来的。说白了,MP4是万金油,WebM是特长生,3GPP是备胎

3.6 代码示例:如何设置输出格式

光说不练假把式。我们来看看代码里怎么设置:

// 方式一:使用常量(推荐)
MediaMuxer muxer = new MediaMuxer(
    outputPath,
    MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4  // 输出MP4
);

// 方式二:使用变量(方便切换)
int outputFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
if (useWebM) {
    outputFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
} else if (use3GPP) {
    outputFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP;
}
MediaMuxer muxer = new MediaMuxer(outputPath, outputFormat);

小技巧: 如果你不确定用户需要什么格式,可以在UI里提供选项,但默认选中MP4。我做过一个用户调研,超过85%的用户根本不知道3GP是什么,选MP4准没错。

3.7 格式选择的避坑指南

我曾经踩过几个坑,分享给你:

  • 坑1:WebM不支持B帧 —— 如果你用MediaCodec编码时开启了B帧,封装成WebM会直接崩溃。解决办法:编码时设置KEY_FRAME_RATEKEY_I_FRAME_INTERVAL,但不要设置B帧相关参数。
  • 坑2:3GPP的音频采样率限制 —— 3GPP格式对音频采样率有限制,最高只支持48000Hz。我曾经用96000Hz采样率编码AAC,封装成3GP后播放全是噪音。
  • 坑3:MP4的moov box位置 —— 如果你生成的MP4文件需要用于流式播放(比如上传到服务器后边下边播),记得在封装完成后调用muxer.setLocation()或手动调整moov box到文件头部。否则用户打开视频要等整个文件下载完才能播放。

3.8 总结一下

格式选择这件事,其实没那么复杂:

  • MP4:首选,覆盖99%的场景
  • WebM:Web场景或需要VP9编码时使用
  • 3GPP:除非有明确的兼容性需求,否则忘掉它

下一节我们会深入MP4的内部结构,看看MediaMuxer到底是怎么把视频轨道和音频轨道「缝合」到一起的。到时候你会发现,理解了容器格式的内部原理,很多坑就能提前避开。


公众号:蓝海资料掘金营,微信deep3321