Android OpenGLES绘制yuv420纹理

2024-05-04 03:38

本文主要是介绍Android OpenGLES绘制yuv420纹理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android OpenGLES绘制yuv420纹理

96 曾大稳丶 关注

2018.07.16 11:31 字数 76 阅读 440评论 0喜欢 3

  1. 把shader代码写入raw里面

vertex_shader.glsl

attribute vec4 av_Position;//顶点位置
attribute vec2 af_Position;//纹理位置
varying vec2 v_texPo;//纹理位置  与fragment_shader交互
void main() {v_texPo = af_Position;gl_Position = av_Position;
}

fragment_shader.glsl

precision mediump float;//精度 为float
varying vec2 v_texPo;//纹理位置  接收于vertex_shader
uniform sampler2D sampler_y;//纹理y
uniform sampler2D sampler_u;//纹理u
uniform sampler2D sampler_v;//纹理vvoid main() {//yuv420->rgbfloat y,u,v;y = texture2D(sampler_y,v_texPo).r;u = texture2D(sampler_u,v_texPo).r- 0.5;v = texture2D(sampler_v,v_texPo).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);
}

因为OpenGLES需要用rgb来加载显示,这里就需要将yuvrgb,这里放在OpenGL里面转换,OpenGL里面使用GPU,提高性能。

  1. 数据写入

YUV420Texture.java

import android.content.Context;
import android.opengl.GLES20;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;public class YUV420Texture {private Context context;//顶点坐标static float vertexData[] = {   // in counterclockwise order:-1f, -1f, 0.0f, // bottom left1f, -1f, 0.0f, // bottom right-1f, 1f, 0.0f, // top left1f, 1f, 0.0f,  // top right};//纹理坐标static float textureData[] = {   // in counterclockwise order:0f, 1f, 0.0f, // bottom left1f, 1f, 0.0f, // bottom right0f, 0f, 0.0f, // top left1f, 0f, 0.0f,  // top right};//每一次取点的时候取几个点static final int COORDS_PER_VERTEX = 3;private final int vertexCount = vertexData.length / COORDS_PER_VERTEX;//每一次取的总的点 大小private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex//位置private FloatBuffer vertexBuffer;//纹理private FloatBuffer textureBuffer;private int program;//顶点位置private int avPosition;//纹理位置private int afPosition;//shader  yuv变量private int sampler_y;private int sampler_u;private int sampler_v;private int[] textureId_yuv;//YUV数据private int width_yuv;private int height_yuv;private ByteBuffer y;private ByteBuffer u;private ByteBuffer v;public YUV420Texture(Context context) {this.context = context;vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertexData);vertexBuffer.position(0);textureBuffer = ByteBuffer.allocateDirect(textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureData);textureBuffer.position(0);}public void initYUV() {String vertexSource = ShaderUtil.readRawTxt(context, R.raw.vertex_shader);String fragmentSource = ShaderUtil.readRawTxt(context, R.raw.fragment_shader);program = ShaderUtil.createProgram(vertexSource, fragmentSource);if (program > 0) {//获取顶点坐标字段avPosition = GLES20.glGetAttribLocation(program, "av_Position");//获取纹理坐标字段afPosition = GLES20.glGetAttribLocation(program, "af_Position");//获取yuv字段sampler_y = GLES20.glGetUniformLocation(program, "sampler_y");sampler_u = GLES20.glGetUniformLocation(program, "sampler_u");sampler_v = GLES20.glGetUniformLocation(program, "sampler_v");textureId_yuv = new int[3];//创建3个纹理GLES20.glGenTextures(3, textureId_yuv, 0);//绑定纹理for (int id : textureId_yuv) {GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, id);//环绕(超出纹理坐标范围)  (s==x t==y GL_REPEAT 重复)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);//过滤(纹理像素映射到坐标点)  (缩小、放大:GL_LINEAR线性)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 setYUVData(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);}public void draw() {if (width_yuv > 0 && height_yuv > 0 && y != null && u != null && v != null) {GLES20.glUseProgram(program);GLES20.glEnableVertexAttribArray(avPosition);GLES20.glVertexAttribPointer(avPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);GLES20.glEnableVertexAttribArray(afPosition);GLES20.glVertexAttribPointer(afPosition, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, textureBuffer);//激活纹理0来绑定y数据GLES20.glActiveTexture(GLES20.GL_TEXTURE0);GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId_yuv[0]);//glTexImage2D (int target,//                int level,//                int internalformat,//                int width,//                int height,//                int border,//                int format,//                int type,//                Buffer pixels)GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width_yuv, height_yuv, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, y);//激活纹理1来绑定u数据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);//激活纹理2来绑定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);//给fragment_shader里面yuv变量设置值   0 1 2 标识纹理xGLES20.glUniform1i(sampler_y, 0);GLES20.glUniform1i(sampler_u, 1);GLES20.glUniform1i(sampler_v, 2);//绘制GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);y.clear();u.clear();v.clear();y = null;u = null;v = null;GLES20.glDisableVertexAttribArray(afPosition);GLES20.glDisableVertexAttribArray(avPosition);}}
}

ShaderUtil.java


import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;public class ShaderUtil {private static final String TAG = "ShaderUtil";public static String readRawTxt(Context context, int rawId) {InputStream inputStream = context.getResources().openRawResource(rawId);BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));StringBuffer sb = new StringBuffer();String line;try {while ((line = reader.readLine()) != null) {sb.append(line).append("\n");}reader.close();} catch (Exception e) {e.printStackTrace();}return sb.toString();}public static int loadShader(int shaderType, String source) {// create a vertex shader type (GLES20.GL_VERTEX_SHADER)// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)int shader = GLES20.glCreateShader(shaderType);if (shader != 0) {//添加代码到shaderGLES20.glShaderSource(shader, source);//编译shaderGLES20.glCompileShader(shader);int[] compile = new int[1];//检测是否编译成功GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compile, 0);if (compile[0] != GLES20.GL_TRUE) {Log.d(TAG, "shader compile error");GLES20.glDeleteShader(shader);shader = 0;}}return shader;}public static int createProgram(String vertexSource, String fragmentSource) {//获取vertex shaderint vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);if (vertexShader == 0) {return 0;}//获取fragment shaderint fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);if (fragmentShader == 0) {return 0;}//创建一个空的渲染程序int program = GLES20.glCreateProgram();if (program != 0) {//添加vertexShader到渲染程序GLES20.glAttachShader(program, vertexShader);//添加fragmentShader到渲染程序GLES20.glAttachShader(program, fragmentShader);//关联为可执行渲染程序GLES20.glLinkProgram(program);int[] linsStatus = new int[1];//检测是否关联成功GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linsStatus, 0);if (linsStatus[0] != GLES20.GL_TRUE) {Log.d(TAG, "link program error");GLES20.glDeleteProgram(program);program = 0;}}return program;}}
  1. Render书写
    MyRender.java
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;public class MyRender implements GLSurfaceView.Renderer {private Context context;private YUV420Texture yuv420Texture;public MyRender(Context context) {this.context = context;}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {yuv420Texture = new YUV420Texture(context);yuv420Texture.initYUV();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//宽高GLES20.glViewport(0, 0, width, height);}@Overridepublic void onDrawFrame(GL10 gl) {//清空颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//设置背景颜色
//        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);yuv420Texture.draw();}public void setYuvData(int width, int height, byte[] y, byte[] u, byte[] v) {if (yuv420Texture != null) {yuv420Texture.setYUVData(width, height, y, u, v);}}
}
  1. GLSurfaceView引用Renderer

MyGLSurfaceView.java


import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;public class MyGLSurfaceView extends GLSurfaceView {private MyRender myRender;public MyGLSurfaceView(Context context) {this(context, null);}public MyGLSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);setEGLContextClientVersion(2);myRender = new MyRender(context);setRenderer(myRender);//mode=GLSurfaceView.RENDERMODE_WHEN_DIRTY之后  调用requestRender()触发Render的onDrawFrame函数//mode=GLSurfaceView.RENDERMODE_CONTINUOUSLY之后  自动调用onDrawFrame  60fps左右setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);}public void setYUVData(int width, int height, byte[] y, byte[] u, byte[] v) {if (myRender != null) {myRender.setYuvData(width, height, y, u, v);requestRender();}}
}

这篇关于Android OpenGLES绘制yuv420纹理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/958271

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR