在Android中,可以使用MediaMuxer来封装编码后的视频流和音频流到mp4容器中:

MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or webm file as the output and at most one audio and/or one video elementary stream. MediaMuxer does not support muxing B-frames.

在官方文档的介绍中,MediaMuxer最多仅支持一个视频track和一个音频track,所以如果有多个音频track可以先把它们混合成为一个音频track然后再使用MediaMuxer封装到mp4容器中。

通常视频编码使用H.264(AVC)编码,音频编码使用AAC编码,在MediaFormat中我们可以看到各种编码格式:

public static final String MIMETYPE_VIDEO_AVC = "video/avc";public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";public static final String MIMETYPE_TEXT_CEA_608 = "text/cea-608";

上面只各自摘取了视频、音频、字幕的一种编码格式,更多的编码格式可自行查看MediaFormat源码。

MediaMuxer的使用也比较简单,首先通过new MediaMuxer(String path, int format)指定视频文件输出路径和文件格式:

MediaMuxer mMediaMuxer = new MediaMuxer(mOutputVideoPath,                 MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

创建MediaMuxer对象之后,一个比较重要的操作就是addTrack(MediaFormat format),添加媒体通道,该函数需要传入MediaFormat对象,通常从MediaExtractor或者MediaCodec中获取,如果希望自己创建的话可以直接new或者通过该类如下静态方法创建:

MediaFormat.createAudioFormat(...);MediaFormat.createVideoFormat(...);MediaFormat.createSubtitleFormat(...);

如果是自己创建MediaFormat要根据媒体类型配置好相应的keys,这在MediaFormat官方文档有详细说明。这里注意一定要设置csd参数,否则添加进MediaMuxer的MediaFormat会导致MediaMuxer调用stop()时抛出异常。

csd参数在官方文档中叫Codec-specific Data,详细介绍可以看MediaCodec官方文档 - Codec-specific Data部分。对于H.264来说,"csd-0"和"csd-1"分别对应sps和pps;对于AAC来说,"csd-0"对应ADTS。下面是自己创建视频MediaFormat的例子:

MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);byte[] header_sps = {0, 0, 0, 1, 103, 100, 0, 31, -84, -76, 2, -128, 45, -56};byte[] header_pps = {0, 0, 0, 1, 104, -18, 60, 97, 15, -1, -16, -121, -1, -8, 67, -1, -4, 33, -1, -2, 16, -1, -1, 8, 127, -1, -64};videoFormat.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));videoFormat.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);videoFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);videoFormat.setInteger(MediaFormat.KEY_CAPTURE_RATE, 25);

把MediaFormat添加到MediaMuxer后记录返回的track index,添加完所有track后调用start方法:

videoTrackIndex = mMediaMuxer.addTrack(format);audioTrackIndex = mMediaMuxer.addTrack(format);mMediaMuxer.start();

然后就可以调用MediaMuxer.writeSampleData()向mp4文件中写入数据了。这里要注意每次只能添加一帧视频数据或者单个Sample的音频数据,并且BufferInfo对象的值一定要设置正确:

info.offset = 0;info.size = sampleSize;info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;info.presentationTimeUs = mVideoExtractor.getSampleTime();mMediaMuxer.writeSampleData(videoTrackIndex, buffer, info);
  • info.size 必须填入数据的大小
  • info.flags 需要给出是否为同步帧/关键帧
  • info.presentationTimeUs 必须给出正确的时间戳,注意单位是 us

结束写入后关闭以及释放资源:

mMediaMuxer.stop();mMediaMuxer.release();

更多相关文章

  1. Android 利用PdfDocument产生PDF文档
  2. Android 获取缩略图,网络视频,或者本地视频
  3. android 保存配置文档
  4. Ijkplayer视频播放
  5. Android 视频编辑问题记录
  6. Android学习之Activity生命周期文档翻译
  7. Android app的音视频播放功能
  8. Android获取SD卡视频音频文件

随机推荐

  1. Android 获取系统时间的三种方式
  2. Android 自定义View清除画布Canvas
  3. Android 判断屏幕滑动
  4. Android拖动控件
  5. Android之dialog实现底部出现对话框
  6. Android传感器学习总结
  7. android之线程访问网络并解析数据
  8. Android中判断网络连接是否可用的方法总
  9. Android获取系统储存以及内存信息的方法(
  10. android实现手机传感器调用