一、概述
案例:使用硬件解碼MediaCodec+OpenGL ES來實現一個視頻播放器。
重點概要:
3.視頻渲染使用OpenGL ES、音頻渲染使用AudioTrack封裝的AudioPlayer
4.封裝GLSurfaceView並將(1)+(2)+(3)+(4)橋接起來實現簡單的視頻播放器
二、重要代碼實例講解
橋接(一)、(二)、(三)的代碼讓整個播放器串聯起來。
1.封裝GLSurfaceView,並初始化Render
import android.content.Context; import android.opengl.GLSurfaceView; import android.util.AttributeSet; /** * @ProjectName: TheSimpllestplayer * @Package: com.yw.thesimpllestplayer.renderview * @ClassName: RenderGLSurfaceView * @Description: 封裝GLSurfaceView * @Author: wei.yang * @CreateDate: 2021/11/6 16:30 * @UpdateUser: 更新者:wei.yang * @UpdateDate: 2021/11/6 16:30 * @UpdateRemark: 更新說明: * @Version: 1.0 */ public class RenderGLSurfaceView extends GLSurfaceView { private VideoDrawer videoDrawer; private VideoRender videoRender; public RenderGLSurfaceView(Context context) { super(context); initRender(); } public RenderGLSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); initRender(); } /** * 初始化渲染器 */ private void initRender() { setEGLContextClientVersion(2); //初始化繪制器 videoDrawer = new VideoDrawer(); videoDrawer.setVideoSize(1080, 1920); //初始化渲染器 videoRender = new VideoRender(); videoRender.addDrawer(videoDrawer); setRenderer(videoRender); } public VideoDrawer getVideoDrawer() { return videoDrawer; } public VideoRender getVideoRender() { return videoRender; } }
2.具體的播放器頁面
package com.yw.thesimpllestplayer.ui; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.view.Surface; import android.widget.Toast; import androidx.annotation.Nullable; import com.yw.thesimpllestplayer.BaseActivity; import com.yw.thesimpllestplayer.R; import com.yw.thesimpllestplayer.mediaplayer.decoder.AudioDecoder; import com.yw.thesimpllestplayer.mediaplayer.decoder.VideoDecoder; import com.yw.thesimpllestplayer.renderview.RenderGLSurfaceView; import com.yw.thesimpllestplayer.renderview.VideoDrawer; import com.yw.thesimpllestplayer.renderview.VideoRender; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @ProjectName: TheSimpllestplayer * @Package: com.yw.thesimpllestplayer.ui * @ClassName: SimplePlayerActivity * @Description: 簡單的視頻播放器 * @Author: wei.yang * @CreateDate: 2021/11/6 15:59 * @UpdateUser: 更新者:wei.yang * @UpdateDate: 2021/11/6 15:59 * @UpdateRemark: 更新說明: * @Version: 1.0 */ public class SimplePlayerActivity extends BaseActivity { private RenderGLSurfaceView surfaceView; private String videoPath = "/storage/emulated/0/DCIM/Camera/share_06909c9c4e74c23ff62eba7701038719.mp4"; private VideoDecoder videoDecoder; private AudioDecoder audioDecoder; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple_player); initViews(); } private void initViews() { surfaceView = findViewById(R.id.surfaceView); findViewById(R.id.btnChoiceVideo).setOnClickListener(v -> { choiceVideo(); }); findViewById(R.id.btnPlay).setOnClickListener(v -> { if (videoPath != null && videoDecoder != null && audioDecoder != null) { //開始播放 videoDecoder.goOn(); audioDecoder.goOn(); } else { Toast.makeText(SimplePlayerActivity.this, "請先初始化播放器", Toast.LENGTH_SHORT).show(); } }); findViewById(R.id.btnStop).setOnClickListener(v -> { if (videoPath != null && videoDecoder != null && audioDecoder != null) { //暫停播放 videoDecoder.pause(); audioDecoder.pause(); } else { Toast.makeText(SimplePlayerActivity.this, "請先初始化播放器", Toast.LENGTH_SHORT).show(); } }); } @Override public void videoPathCallback(String videoPath) { this.videoPath = videoPath; initPlayer(); } private void initPlayer() { ExecutorService threadPool = Executors.newFixedThreadPool(10); videoDecoder = new VideoDecoder(videoPath, new Surface(surfaceView.getVideoDrawer().getSurfaceTexture())); threadPool.execute(videoDecoder); audioDecoder = new AudioDecoder(videoPath); threadPool.execute(audioDecoder); //開始播放 // videoDecoder.goOn(); // audioDecoder.goOn(); } @Override protected void onResume() { super.onResume(); if (videoDecoder != null && audioDecoder != null) { videoDecoder.goOn(); audioDecoder.goOn(); } } @Override protected void onPause() { super.onPause(); if (videoDecoder != null && audioDecoder != null) { videoDecoder.pause(); audioDecoder.pause(); } } @Override protected void onDestroy() { super.onDestroy(); if (videoDecoder != null) { videoDecoder.stop(); } if (audioDecoder != null) { audioDecoder.stop(); } } }
三、總結
1.SimplePlayerActivity.java類可以選擇視頻播放路徑,並可以執行開始播放、暫停播放以及按返回鍵的時候銷毀播放器
2.RenderGLSurfaceView.java封裝了VideoRender以及VideoDrawer
3.如果視頻播放路徑不為空則初始化音視頻編解碼器VideoDecoder及AudioDecoder