【Android音视频开发】【007】SurfaceView实现H264播放器

在前面,我们已经通过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)
	            return;
	
	        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
	        inputBuffer.clear();
	        inputBuffer.put(nalu, 0, nalu.length);
	        mediaCodec.queueInputBuffer(inputBufferIndex, 0, nalu.length, 0, 0);
	
	        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
	        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 100);
	        while (outputBufferIndex >= 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();

发布了442 篇原创文章 · 获赞 45 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/u013718730/article/details/103701743