[FFmpeg + OpenGL + OpenSL ES]OpenGL ES 渲染获取到的yuv数据 - 7

OpenGL中是不能直接渲染YUV数据的,可以用3个纹理来分别获取Y、U和V的值,然后根据公式:

r = y + 1.403 * v;
g = y - 0.344 * u - 0.714 * v;
b = y + 1.770 * u;

转为rgb颜色格式显示出来。这个转换过程是在GPU中完成的,计算效率比在CPU中计算高很多倍


在工程目录res目录下新建    raw文件夹    新建    顶点着色器/片元着色器

vertex_shader.glsl

aattribute vec4 av_Position;
attribute vec2 af_Position;
varying vec2 v_texPosition;
void main() {
 v_texPosition = af_Position;
 gl_Position = av_Position;
}

fragment_shader.glsl

precision mediump float;
varying vec2 v_texPosition;
uniform sampler2D sampler_y;
uniform sampler2D sampler_u;
uniform sampler2D sampler_v;
void main() {
    float y,u,v;
    y = texture2D(sampler_y,v_texPosition).r;
    u = texture2D(sampler_u,v_texPosition).r- 0.5;
    v = texture2D(sampler_v,v_texPosition).r- 0.5;

    vec3 rgb;
    rgb.r = y + 1.403 * v;
    rgb.g = y - 0.344 * u - 0.714 * v;
    rgb.b = y + 1.770 * u;

    gl_FragColor = vec4(rgb,1);
}

在java工程目录下新建opengl包

将    WlGLSurfaceView    WlRender    WlShaderUtil    粘贴过来

修改   WlRender   

package com.ywl5320.myplayer.opengl;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;

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;

import static android.opengl.GLES30.GL_RGB32F;
import static android.opengl.GLES30.GL_RGBA32F;

public class WlRender implements GLSurfaceView.Renderer {
    private Context mContext;
    private int program_yuv;
    private int avPosition_yuv;
    private int afPosition_yuv;
    private int textureid;

    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;

    //声明顶点坐标数组 绘制坐标范围
    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) {
        MyLog.d("onSurfaceCreated");
        initRanderYUV();
    }

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

    @Override
    public void onDrawFrame(GL10 gl10) {
        MyLog.d("onDrawFrame");
        //清屏
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        //使用颜色清屏
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        renderYUV();
        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_shader);
        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) {
        MyLog.d("setYUVRenderData");
        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() {
        MyLog.d("width_yuv " + width_yuv +
                "height_yuv " + height_yuv +
                "y " + y +
                "u " + u +
                "v " + v);
        if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) {
            MyLog.d("renderYUV");
            //使用program
            GLES20.glUseProgram(program_yuv);
            MyLog.d("glUseProgram");
            //使用顶点坐标
            GLES20.glEnableVertexAttribArray(avPosition_yuv);
            GLES20.glVertexAttribPointer(avPosition_yuv, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer);
            MyLog.d("glVertexAttribPointer");
            //绘制
            //参数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,
                    GL_RGBA32F,
                    width_yuv, height_yuv,
                    0,
                    GL_RGBA32F,
                    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,
                    GL_RGBA32F,
                    width_yuv / 2, height_yuv / 2,
                    0,
                    GL_RGBA32F,
                    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;
            MyLog.d("END");
        }
    }
}

* 注意这个类目前绘制有问题但是能保证程序运行   后面明白了怎么做就改掉

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值