继续Android音视频编码(2)中的内容,在上一篇文章中,对视频解码和编码进行了详细的介绍,具体可参见这里。
@Override
public void start(){
super.start();
mediaCodec.setCallback(new MediaCodec.Callback() {
@Override
public 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
);
}
}
@Override
public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
...
}
@Override
public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
codec.stop();
}
@Override
public 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 {
//默认采样率为 16bit
mPcmEncode = 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();
}
@Override
public void start(){
super.start();
mediaCodec.setCallback(new MediaCodec.Callback() {
@Override
public 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
);
}
}
@Override
public 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);
}
@Override
public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
codec.stop();
}
@Override
public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
}
});
mediaCodec.configure(mediaFormat, null, null, 0);
mediaCodec.start();
}
@Override
public 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);
}
@Override
public void stop() {
super.stop();
//释放 AudioTrack
if (mAudioTrack.getState() != AudioTrack.STATE_UNINITIALIZED) {
try {
mAudioTrack.stop();
}catch (Exception e){
}
}
}
@Override
public void release() {
super.release();
mAudioTrack.release();
}
@Override
protected 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);
}
}
}
更多内容,欢迎关注我的微信公众号:半夏之夜的无情剑客。