Android最简单的视频播放器之GLSurfaceView+OpenGL ES+MediaCodec硬件解码实现(四)
一、概述
案例:使用硬件解码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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探