Androidオーディオおよびビデオ合成ツール-MediaMuxer

1️⃣、目標:オーディオおよびビデオストリーム(さまざまなチャネルを使用して送信されるバイトストリーム)をビデオファイルに
合成する2️⃣、ツール:Androidネイティブフレームワークに付属するMediaMuxerクラス
3️⃣、ソリューション:

 private MediaMuxer mMuxer;

初期MediaMuxer

mMuxer = new MediaMuxer(“需要保存的路径”,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

MUXER_OUTPUT_MPEG_4 //合成されたビデオファイル形式

MediaMuxerは、オーディオとビデオの設定を追加します

private int mVideoTrackIndex, mAudioTrackIndex;

ビデオトラック

MediaFormat videoMediaformat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);

byte[] header_SPS_1080 = {0, 0, 0, 1, 103, 77, 0, 42, -99, -88, 30, 0, -119, -7, 102, -32, 32, 32, 32, 64};
byte[] header_PPS_1080 = {0, 0, 0, 1, 104, -18, 60, -128};

byte[] header_SPS_720 = {0, 0, 0, 1, 103, 77, 0, 31, -99, -88, 20, 1, 110, -101, -128, -128, -128, -127};
byte[] header_PPS_720 = {0, 0, 0, 1, 104, -18, 60, -128};

byte[] header_SPS_360 = {0, 0, 0, 1, 103, 77, 0, 30, -99, -88, 40, 11, -2, 89, -72, 8, 8, 8, 16};
byte[] header_PPS_360 = {0, 0, 0, 1, 104, -18, 60, -128};

if (width == 640 && height == 360) {
    videoMediaformat.setByteBuffer("csd-0", ByteBuffer.wrap(header_SPS_360));
    videoMediaformat.setByteBuffer("csd-1", ByteBuffer.wrap(header_PPS_360));//H264格式的视频需要添加
    videoMediaformat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities
            .COLOR_FormatYUV420Planar);//视频数据格式
    videoMediaformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 640 * 360);//缓冲区最大值
    videoMediaformat.setInteger(MediaFormat.KEY_CAPTURE_RATE, 20);//帧率
} else if (width == 1280 && height == 720) {
    videoMediaformat.setByteBuffer("csd-0", ByteBuffer.wrap(header_SPS_720));
    videoMediaformat.setByteBuffer("csd-1", ByteBuffer.wrap(header_PPS_720));
    videoMediaformat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities
            .COLOR_FormatYUV420Planar);
    videoMediaformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1280 * 720);
    videoMediaformat.setInteger(MediaFormat.KEY_CAPTURE_RATE, 20);
} else {
    videoMediaformat.setByteBuffer("csd-0", ByteBuffer.wrap(header_SPS_1080));
    videoMediaformat.setByteBuffer("csd-1", ByteBuffer.wrap(header_PPS_1080));
    videoMediaformat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities
            .COLOR_FormatYUV420Planar);
    videoMediaformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1920 * 1080);
    videoMediaformat.setInteger(MediaFormat.KEY_CAPTURE_RATE, 20);
}

mVideoTrackIndex = mMuxer .addTrack(videoMediaformat);

オーディオトラック

 MediaFormat audioFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 8000, 1);//音频格式,采样率,通道数
 audioFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);//AAC音频需要添加
 byte[] bytes = new byte[]{(byte) 0x11, (byte) 0x90};
 ByteBuffer audiobuffer = ByteBuffer.wrap(bytes);
 audioFormat.setByteBuffer("csd-0", audiobuffer);
 audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000);//比特率
 audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
 audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100 * 1024);//作用于inputBuffer的大小
 mAudioTrackIndex = mMuxer .addTrack(audioFormat);

上記の初期化プロセスが完了した後

mMuxer.start();//开启合成器

MediaMuxerは、データの書き込みを行います

private MediaCodec.BufferInfo       bufferInfo     = null;
private MediaCodec.BufferInfo       audioBufferInfo = null;

ビデオストリーミング

bufferInfo.offset = 0;
bufferInfo.size = /*naluIndex*/视频流数据的大小;
 if (/*(naluBuffer[4] & 0x1f) == 5*/判断I帧) {
     bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;//I帧
 } else if (/*(naluBuffer[4] & 0x1f) == 7 || (naluBuffer[4] & 0x1f) == 8 ||
         (frameBuffer[4] & 0x1f) == 6*/判断预测帧) {
     bufferInfo.flags = MediaCodec.BUFFER_FLAG_CODEC_CONFIG;//B,P帧
 } else {
     bufferInfo.flags = 0;//SEI
 }
bufferInfo.presentationTimeUs = getPTSUs();
mMuxer.writeSampleData(mVideoTrackIndex , /*outputBuffer*/视频流, bufferInfo);

BufferInfoは合成時に非常に重要です。異常があると、合成されたビデオも異常になります。

private long prevOutputPTSUs = 0;
/**
  *获取下一个编码表示时间
  */
 protected long getPTSUs() {
     long result = System.nanoTime() / 1000L;

     if (result < prevOutputPTSUs)
         result = (prevOutputPTSUs - result) + result;
     return result;
 }

オーディオストリーム

audioBufferInfo.offset = 0;
audioBufferInfo.size = /*nReadSize*/音频数据流大小;
audioBufferInfo.flags = 0;
audioBufferInfo.presentationTimeUs = getPTSUs();
mMuxer.writeSampleData(mVideoTrackIndex , /*outputBuffer*/音频流, bufferInfo);

停止和リリース
if(mMuxer!= null){ try { mMuxer.stop(); mMuxer.release(); } catch(IllegalStateException ex){ ex.printStackTrace(); } }






4️⃣結論:
1。オーディオデータなしでAudioTrackを追加しないでください。

おすすめ

転載: blog.csdn.net/mozushixin_1/article/details/100741199