在前面,我们已经通过MediaCodec实现了一个AvcDecoder,可以播放H264码流数据 但是AvcDecoder需要手动和Surface绑定,仍然不太方便 这篇文章我们进一步封装,将MediaCodec和SurfaceView集合,实现一个带H264解码功能的控件
AvcPlayer源码
//集成了AvcDecoder解码功能的SurfaceView
//使用AvcDecoder,则需要手动绑定一个SurfaceView
public class AvcPlayer extends SurfaceView {
MediaCodec mediaCodec;
Callback callback;
int width;
int height;
@Getter
boolean playing = false;
public AvcPlayer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void init(int width, int height, Callback callback) {
this.callback = callback;
this.width = width;
this.height = height;
}
@SneakyThrows
private void configureMediaCodec() {
mediaCodec = MediaCodec.createDecoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
mediaCodec.configure(mediaFormat, getHolder().getSurface(), null, 0);
mediaCodec.start();
}
public void decodeNalu(byte[] nalu) {
if (!playing) return;
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex = 0) {
mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
if (callback != null)
callback.onFrameUpdate(nalu);
}
public void startPreview() {
configureMediaCodec();
playing = true;
}
public void stopPreview() {
playing = false;
mediaCodec.stop();
mediaCodec.release();
mediaCodec = null;
}
public interface Callback {
void onFrameUpdate(byte[] frame);
}
}
AvcPlayer使用方法
AvcPlayer player;
//开始播放,建议在onResume中延时2秒执行,等待SurfaceView初始化完成
player.init(width, height, callback);
player.startPreview();
//解码并播放H264流数据,视频源可以来自文件、网络、设备取流等任何方式,只要字节集是由若干Nalu数据组成即可
player.decodeNalu(byte[] nalu);
//停止播放,在onPause中执行
player.stopPreview();