【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();

發佈了429 篇原創文章 · 獲贊 43 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章