继续Android音视频编码(2)中的内容,在上一篇文章中,对视频解码和编码进行了详细的介绍,具体可参见这里。
视频解码 Surface播放
@Overridepublic void start(){super.start();mediaCodec.setCallback(new MediaCodec.Callback() {@Overridepublic void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);int size = extractor.readBuffer(inputBuffer, true);long st = extractor.getSampleTime();if (size >= 0) {codec.queueInputBuffer(index,0,size,st,extractor.getSampleFlags());} else {//结束codec.queueInputBuffer(index,0,0,0,BUFFER_FLAG_END_OF_STREAM);}}@Overridepublic void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
...}@Overridepublic void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {codec.stop();}@Overridepublic void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {}});mediaCodec.configure(mediaFormat,mSurface,null,0);//mediaCodec.configure(mediaFormat,null,null,0);mediaCodec.start();}
通过这行 mediaCodec.configure(mediaFormat,mSurface,null,0)
代码就可以将解码后的数据在相应的surface中进行预览播放。
音频解码
这里是音频解码的参考代码。
package com.example.myapplication.media.codec.async;import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Message;
import android.util.Log;import androidx.annotation.NonNull;import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;/*** describe:*/
public class AsyncAudioDecode extends BaseAsyncDecode {private static final String TAG = "AsyncAudioDecode";private int mPcmEncode;//一帧的最小buffer大小private int mMinBufferSize;private AudioTrack mAudioTrack;public AsyncAudioDecode(long progress) {super(progress);//拿到采样率if (mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)) {mPcmEncode = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);} else {//默认采样率为 16bitmPcmEncode = AudioFormat.ENCODING_PCM_16BIT;}//音频采样率int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);//获取视频通道数int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);//拿到声道int channelConfig = channelCount == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO;mMinBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, mPcmEncode);/*** 设置音频信息属性* 1.设置支持多媒体属性,比如audio,video* 2.设置音频格式,比如 music*/AudioAttributes attributes = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();/*** 设置音频数据* 1. 设置采样率* 2. 设置采样位数* 3. 设置声道*/AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate).setEncoding(AudioFormat.ENCODING_PCM_16BIT).setChannelMask(channelConfig).build();//配置 audioTrack,采用流模式mAudioTrack = new AudioTrack(attributes,format,mMinBufferSize,AudioTrack.MODE_STREAM,AudioManager.AUDIO_SESSION_ID_GENERATE);//监听播放mAudioTrack.play();}@Overridepublic void start(){super.start();mediaCodec.setCallback(new MediaCodec.Callback() {@Overridepublic void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {ByteBuffer inputBuffer = mediaCodec.getInputBuffer(index);int size = extractor.readBuffer(inputBuffer, false);if (size >= 0) {codec.queueInputBuffer(index,0,size,extractor.getSampleTime(),extractor.getSampleFlags());} else {//结束codec.queueInputBuffer(index,0,0,0,MediaCodec.BUFFER_FLAG_END_OF_STREAM);}}@Overridepublic void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {Message msg = new Message();msg.what = MSG_AUDIO_OUTPUT;msg.arg1 = index;msg.arg2 = info.size;mHandler.sendMessage(msg);}@Overridepublic void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {codec.stop();}@Overridepublic void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {}});mediaCodec.configure(mediaFormat, null, null, 0);mediaCodec.start();}@Overridepublic boolean handleMessage(@NonNull Message msg) {switch (msg.what){case MSG_AUDIO_OUTPUT:int index = msg.arg1;int size = msg.arg2;ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(index);try {if (outputBuffer != null) {mAudioTrack.write(outputBuffer, size,AudioTrack.WRITE_BLOCKING);mediaCodec.releaseOutputBuffer(index, false);}} catch (Exception e) {e.printStackTrace();}break;default:break;}return super.handleMessage(msg);}@Overridepublic void stop() {super.stop();//释放 AudioTrackif (mAudioTrack.getState() != AudioTrack.STATE_UNINITIALIZED) {try {mAudioTrack.stop();}catch (Exception e){}}}@Overridepublic void release() {super.release();mAudioTrack.release();}@Overrideprotected int decodeType() {return AUDIO;}
}
由于这个例子不需要对音频进行解码。这里直接使用。可参考则这段代码,先添加音频轨道,然后读取音频数据到buffer中,最后通过mediaMuxer将音频混合到视频当中。
@SuppressLint("WrongConstant")public void encodeAudio() {MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);if (audioFormat != null) {//写完视频,再把音频混合进去int audioSize = 0;//读取音频帧的数据,直到结束while ((audioSize = audioExtractor.readBuffer(buffer, false)) > 0) {bufferInfo.offset = 0;bufferInfo.size = audioSize;bufferInfo.presentationTimeUs = audioExtractor.getSampleTime();bufferInfo.flags = audioExtractor.getSampleFlags();mediaMuxer.writeSampleData(audioTrack, buffer, bufferInfo);}}}
更多内容,欢迎关注我的微信公众号:半夏之夜的无情剑客。