[FFmpeg + OpenGL + OpenSL ES] OpenGL 渲染MediaCodec解码数据- 12

在项目raw下创建  fragment_mediacodec.glsl  用来渲染视频

#extension GL_OES_EGL_image_external : require
precision mediump float;
varying vec2 v_texPosition;
uniform samplerExternalOES sTexture;

void main() {
    gl_FragColor=texture2D(sTexture, v_texPosition);
}

WlRender中的代码

 

package com.ywl5320.myplayer.opengl;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.view.Surface;

import com.ywl5320.myplayer.R;
import com.ywl5320.myplayer.log.MyLog;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class WlRender implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
    public static final int RENDER_YUV = 1;
    public static final int RENDER_MEDIACODEC = 2;

    private Context mContext;
    private int renderType = RENDER_YUV;

    public void setRenderType(int renderType) {
        this.renderType = renderType;
    }

    /***********************************   yuv   ***********************************************/
    //yuv
    private int program_yuv;
    private int avPosition_yuv;
    private int afPosition_yuv;

    private int sampler_y;
    private int sampler_u;
    private int sampler_v;
    private int[] textureId_yuv;

    private int width_yuv;
    private int height_yuv;
    private ByteBuffer y;
    private ByteBuffer u;
    private ByteBuffer v;

    /***********************************  mediacodec-start  ***********************************************/
    //创建program
    private int program_mediacodec;
    private int avPosition_mediacodec;
    private int afPosition_mediacodec;
    //纹理id
    private int samplerOES_mediacodec;
    private int textureId_mediacodec;
    private SurfaceTexture surfaceTexture;
    private Surface surface;

    private OnSurfaceCreateListener onSurfaceCreateListener;
    private OnRenderListner onRenderListner;

    public void setOnSurfaceCreateListener(OnSurfaceCreateListener onSurfaceCreateListener) {
        this.onSurfaceCreateListener = onSurfaceCreateListener;
    }

    public void setOnRenderListner(OnRenderListner onRenderListner) {
        this.onRenderListner = onRenderListner;
    }

    /***********************************  mediacodec-end  ***********************************************/

    //声明顶点坐标数组 绘制坐标范围
    private final float[] vertexData = {
            -1f, -1f,
            1f, -1f,
            -1f, 1f,
            1f, 1f
    };
    //纹理坐标
    private final float[] textureData = {
            0f, 1f,
            1f, 1f,
            0f, 0f,
            1f, 0f
    };


    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;

    public WlRender(Context context) {
        MyLog.d("WlRender");
        this.mContext = context;
        //为坐标分配本地内存地址
        //.order排序
        //.asFloatBuffer()类型
        //.put(vertexData);放置
        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertexData);
        //移动指针到0
        vertexBuffer.position(0);

        //纹理坐标
        textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(textureData);
        textureBuffer.position(0);
    }

    //加载
    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        initRanderYUV();
        initRanderMediaCodec();
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int i, int i1) {
        //设置长宽高
        GLES20.glViewport(0, 0, i, i1);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        //清屏
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        //使用颜色清屏
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        if (renderType == RENDER_YUV) {
            renderYUV();
        } else if (renderType == RENDER_MEDIACODEC) {
            renderMediacodec();
        }

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }

    private void initRanderYUV() {
        //获取着色器语言    program
        String vertexSource = WlShaderUtil.readRawTxt(mContext, R.raw.vertex_shader);
        String fragmentSource = WlShaderUtil.readRawTxt(mContext, R.raw.fragment_yuv);
        program_yuv = WlShaderUtil.createProgram(vertexSource, fragmentSource);

        //顶点坐标
        avPosition_yuv = GLES20.glGetAttribLocation(program_yuv, "av_Position");
        //纹理坐标
        afPosition_yuv = GLES20.glGetAttribLocation(program_yuv, "af_Position");

        sampler_y = GLES20.glGetUniformLocation(program_yuv, "sampler_y");
        sampler_u = GLES20.glGetUniformLocation(program_yuv, "sampler_u");
        sampler_v = GLES20.glGetUniformLocation(program_yuv, "sampler_v");

        //创建纹理
        textureId_yuv = new int[3];
        //创建和绑定纹理
        GLES20.glGenTextures(3, textureId_yuv, 0);

        for (int i = 0; i < 3; i++) {
            //绑定纹理
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[i]);
            //设置环绕过滤方法
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        }
    }

    public void setYUVRenderData(int width, int height, byte[] y, byte[] u, byte[] v) {
        this.width_yuv = width;
        this.height_yuv = height;
        this.y = ByteBuffer.wrap(y);
        this.u = ByteBuffer.wrap(u);
        this.v = ByteBuffer.wrap(v);
    }

    private void renderYUV() {
        if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) {
            //使用program
            GLES20.glUseProgram(program_yuv);
            //使用顶点坐标
            GLES20.glEnableVertexAttribArray(avPosition_yuv);
            GLES20.glVertexAttribPointer(avPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
            //绘制
            //参数2从哪个顶点绘制
            //参数3 绘制顶点个数
            GLES20.glEnableVertexAttribArray(afPosition_yuv);
            GLES20.glVertexAttribPointer(afPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);

            //纹理赋值
            //激活纹理
            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
            //绑定
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[0]);
            GLES20.glTexImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    GLES20.GL_LUMINANCE,
                    width_yuv, height_yuv,
                    0,
                    GLES20.GL_LUMINANCE,
                    GLES20.GL_UNSIGNED_BYTE,
                    y);
            GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[1]);
            GLES20.glTexImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    GLES20.GL_LUMINANCE,
                    width_yuv / 2, height_yuv / 2,
                    0,
                    GLES20.GL_LUMINANCE,
                    GLES20.GL_UNSIGNED_BYTE,
                    u);
            GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[2]);
            GLES20.glTexImage2D(
                    GLES20.GL_TEXTURE_2D,
                    0,
                    GLES20.GL_LUMINANCE,
                    width_yuv / 2, height_yuv / 2,
                    0,
                    GLES20.GL_LUMINANCE,
                    GLES20.GL_UNSIGNED_BYTE,
                    v);
            GLES20.glUniform1i(sampler_y, 0);
            GLES20.glUniform1i(sampler_u, 1);
            GLES20.glUniform1i(sampler_v, 2);

            y.clear();
            u.clear();
            v.clear();
            y = null;
            u = null;
            v = null;
        }
    }

    private void initRanderMediaCodec() {
        //获取着色器语言    program
        String vertexSource = WlShaderUtil.readRawTxt(mContext, R.raw.vertex_shader);
        String fragmentSource = WlShaderUtil.readRawTxt(mContext, R.raw.fragment_mediacodec);
        program_mediacodec = WlShaderUtil.createProgram(vertexSource, fragmentSource);

        //顶点坐标
        avPosition_mediacodec = GLES20.glGetAttribLocation(program_mediacodec, "av_Position");
        //纹理坐标
        afPosition_mediacodec = GLES20.glGetAttribLocation(program_mediacodec, "af_Position");
        //纹理id
        samplerOES_mediacodec = GLES20.glGetUniformLocation(program_mediacodec, "sTexture");
        //创建纹理
        int[] textureids = new int[1];
        //创建和绑定纹理
        GLES20.glGenTextures(1, textureids, 0);
        textureId_mediacodec = textureids[0];

        //设置环绕
        //GLES11Ext.GL_TEXTURE_EXTERNAL_OES 绘制视频 必须用这个
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
        //过滤方法
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

        //构造器值为纹理
        surfaceTexture = new SurfaceTexture(textureId_mediacodec);
        surface = new Surface(surfaceTexture);
        surfaceTexture.setOnFrameAvailableListener(this);

        //回调
        if (onSurfaceCreateListener != null) {
            onSurfaceCreateListener.onSurfaceCreate(surface);
        }
    }

    //当mediacodec向surface发送数据时的回调
    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        //刷新
        if (onRenderListner != null) {
            onRenderListner.onRender();
        }
    }

    private void renderMediacodec() {
        //更新  surfaceTexture
        surfaceTexture.updateTexImage();
        GLES20.glUseProgram(program_mediacodec);
        //使用顶点坐标
        GLES20.glEnableVertexAttribArray(avPosition_mediacodec);
        GLES20.glVertexAttribPointer(avPosition_mediacodec, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
        //绘制
        //参数2从哪个顶点绘制
        //参数3 绘制顶点个数
        GLES20.glEnableVertexAttribArray(afPosition_mediacodec);
        GLES20.glVertexAttribPointer(afPosition_mediacodec, 2, GLES20.GL_FLOAT, false, 8, textureBuffer);

        //激活纹理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //绑定
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId_mediacodec);
        //使用
        GLES20.glUniform1i(samplerOES_mediacodec, 0);
    }

    public interface OnSurfaceCreateListener {
        void onSurfaceCreate(Surface surface);
    }

    public interface OnRenderListner {
        void onRender();
    }
}

WlGLSurfaceView

package com.ywl5320.myplayer.opengl;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.Surface;

import com.ywl5320.myplayer.log.MyLog;

public class WlGLSurfaceView extends GLSurfaceView {
    private WlRender wlRender;

    public WlGLSurfaceView(Context context) {
        this(context, null);
    }

    public WlGLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        MyLog.d("WlGLSurfaceView");
        //初始化
        //设置OpenGL版本
        setEGLContextClientVersion(2);
        wlRender = new WlRender(context);
        //设置Renderer
        setRenderer(wlRender);
        //渲染模式
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        wlRender.setOnRenderListner(new WlRender.OnRenderListner() {
            @Override
            public void onRender() {
                requestRender();
            }
        });
    }

    public void setYUVData(int width, int height, byte[] y, byte[] u, byte[] v) {
        if (wlRender != null) {
            wlRender.setYUVRenderData(width, height, y, u, v);
            MyLog.d("手动渲染");
            //手动渲染
            requestRender();
        }
    }

    public WlRender getWlRender() {
        return wlRender;
    }
}

WlPlayer

public void setWlGLSurfaceView(WlGLSurfaceView wlGLSurfaceView) {
    this.wlGLSurfaceView = wlGLSurfaceView;

    wlGLSurfaceView.getWlRender().setOnSurfaceCreateListener(new WlRender.OnSurfaceCreateListener() {
        @Override
        public void onSurfaceCreate(Surface s) {
            if (surface == null) {
                surface = s;
                MyLog.d("onSurfaceCreate");
            }
        }
    });
}
//回收Mediacodec
private void releaseMediacodec() {
    if (mediaCodec != null) {
        mediaCodec.flush();
        mediaCodec.stop();
        mediaCodec.release();
        mediaCodec = null;
        mediaFormat = null;
        info = null;
    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值