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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM