簡介
在Android中,可以使用MediaMuxer來封裝編碼后的視頻流和音頻流到mp4容器中,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";
- 使用
-
通過new MediaMuxer(String path, int format)指定視頻文件輸出路徑和文件格式:
MediaMuxer mMediaMuxer = new MediaMuxer(mOutputVideoPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); -
創(chuàng)建MediaMuxer對象之后,一個比較重要的操作就是addTrack(MediaFormat format),添加媒體通道,該函數(shù)需要傳入MediaFormat對象,通常從MediaExtractor或者MediaCodec中獲取,如果希望自己創(chuàng)建的話可以直接new或者通過該類如下靜態(tài)方法創(chuàng)建:
MediaFormat.createAudioFormat(...); MediaFormat.createVideoFormat(...); MediaFormat.createSubtitleFormat(...);如果是自己創(chuàng)建MediaFormat要根據(jù)媒體類型配置好相應的keys,這里注意一定要設置csd參數(shù),否則添加進MediaMuxer的MediaFormat會導致MediaMuxer調(diào)用stop()時拋出異常。csd參數(shù)在官方文檔中叫Codec-specific Data,詳細介紹可以看MediaCodec官方文檔 - Codec-specific Data部分。對于H.264來說,"csd-0"和"csd-1"分別對應sps和pps;對于AAC來說,"csd-0"對應ADTS。
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后調(diào)用start方法:
videoTrackIndex = mMediaMuxer.addTrack(format); audioTrackIndex = mMediaMuxer.addTrack(format); mMediaMuxer.start(); -
然后就可以調(diào)用MediaMuxer.writeSampleData()向mp4文件中寫入數(shù)據(jù)了。這里要注意每次只能添加一幀視頻數(shù)據(jù)或者單個Sample的音頻數(shù)據(jù),并且BufferInfo對象的值一定要設置正確:
info.offset = 0; info.size = sampleSize; 必須填入數(shù)據(jù)的大小 info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME; 需要給出是否為同步幀/關鍵幀 info.presentationTimeUs = mVideoExtractor.getSampleTime(); 必須給出正確的時間戳,注意單位是 us mMediaMuxer.writeSampleData(videoTrackIndex, buffer, info); -
結束寫入后關閉以及釋放資源
mMediaMuxer.stop(); mMediaMuxer.release();