基本概念

MediaMuxer是 Android 提供的一个用于将音频和视频轨道混合(复用)成一个多媒体文件(如 MP4、3GP 等)的工具类。它允许开发者将来自不同来源(例如通过MediaCodec编码后的音频流和视频流)的媒体数据组合在一起,生成一个完整的多媒体文件。

使用步骤

  1. 初始化 MediaMuxer

    首先,需要创建一个MediaMuxer对象。其构造函数需要传入两个参数,一个是输出文件的路径,另一个是输出文件的格式(例如MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4表示输出为 MP4 格式)。

​ 示例代码:

1
2
String outputFilePath = Environment.getExternalStorageDirectory().getPath() + "/output.mp4";
MediaMuxer mediaMuxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

​ 需要注意的是,要确保应用有写入外部存储的权限,否则会无法创建文件。

  1. 添加轨道(Track)
  • 在将媒体数据写入MediaMuxer之前,需要先为音频和视频分别添加轨道。通过addTrack方法来添加,这个方法需要传入一个MediaFormat对象,该对象描述了轨道的格式信息(如编码格式、帧率、声道数等)。

  • 对于视频轨道,MediaFormat可以从视频编码器(MediaCodec)获取。例如,在配置好视频编码器MediaCodec后,可以通过videoEncoder.getOutputFormat()获取视频轨道的格式信息,然后添加轨道:

    1
    
    int videoTrackIndex = mediaMuxer.addTrack(videoEncoder.getOutputFormat());
    
  • 对于音频轨道,同样可以从音频编码器获取格式信息并添加轨道。假设已经有了音频轨道的MediaFormat对象audioFormat,添加轨道的代码如下:

    1
    
    int audioTrackIndex = mediaMuxer.addTrack(audioFormat);
    
  1. 启动 MediaMuxer

在添加完音频和视频轨道后,需要调用mediaMuxer.start()方法来启动复用过程。只有启动后,才能开始写入音频和视频数据。

示例代码:

1
mediaMuxer.start();
  1. 写入媒体数据

数据写入通过writeSampleData方法来实现。这个方法需要传入三个参数:轨道索引(之前通过addTrack方法获取的音频或视频轨道索引)、包含媒体数据的ByteBuffer和一个MediaCodec.BufferInfo对象,该对象包含了数据的相关信息(如数据的大小、时间戳等)。

例如,写入视频数据的示例代码如下:

1
2
3
4
5
6
ByteBuffer videoBuffer = videoEncoder.getOutputBuffer(bufferInfo.index);
if (videoBuffer!= null) {
    videoBuffer.position(bufferInfo.offset);
    videoBuffer.limit(bufferInfo.offset + bufferInfo.size);
    mediaMuxer.writeSampleData(videoTrackIndex, videoBuffer, bufferInfo);
}

写入音频数据的过程类似,只是轨道索引和数据来源是音频相关的。

  1. 停止和释放 MediaMuxer 当所有的媒体数据都写入完成后,需要调用mediaMuxer.stop()方法来停止复用过程,然后调用mediaMuxer.release()方法释放资源。

示例代码:

1
2
mediaMuxer.stop();
mediaMuxer.release();

注意事项

  • 时间戳同步:在写入音频和视频数据时,要确保时间戳(MediaCodec.BufferInfo中的presentationTimeUs)的正确性。如果时间戳没有正确同步,生成的多媒体文件可能会出现音视频不同步的问题。

  • 数据完整性:要确保所有的音频和视频数据都完整地写入到MediaMuxer中。例如,在使用MediaCodec获取数据时,要正确地处理dequeueOutputBuffer的返回值,避免遗漏数据。

  • 错误处理:在整个过程中,可能会出现各种错误,如文件创建失败、轨道添加失败、数据写入失败等。需要适当地进行错误处理,例如捕获IOException等异常。