随笔 - 632  文章 - 17  评论 - 54  阅读 - 93万

Android最简单的视频播放器之GLSurfaceView+OpenGL ES+MediaCodec硬件解码实现(四)

一、概述

  案例:使用硬件解码MediaCodec+OpenGL ES来实现一个视频播放器。

  源码下载

  重点概要:

    1.音视频文件提取器MediaExtractor

    2.音视频硬件解码API MediaCodec

    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

posted on   飘杨......  阅读(2287)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示