Android NDK cpp 使用 OpenGL ES 渲染预览 YUV

3 篇文章 2 订阅
2 篇文章 0 订阅

参考网址:

OpenGL 下的专业名词解析

OpenGL渲染YUV数据

Android native层的opengltest程序学习例子

 

由于项目需要把  Camera HAL 层的部分算法移植到 APK 的 native 用 OpenGL ES 增加特效和渲染预览。

需要两个步骤:

  1. 从 APK 传输数据到 native 层: Android camera2 API 获取相机的 YUV 元数据预览
  2.  在 native 层处理相机的 YUV 数据,并使用 OpenGL ES 增加特效和渲染预览。

 

本代码需要在 android O 源码环境中编译。

重点是 OpenGL ES 顶点着色器片源着色器的 program

android 中 OpenGL ES 和 EGL  结合完成预览的任务

/*
 * 使用 EGL 一般顺序
 * 1. 使用EGL首先必须创建,建立本地窗口系统和OpenGL ES的连接
 *     eglGetDisplay
 * 2. 初始化EGL
 *    eglInitialize
 * 3. 确定可用的渲染表面(Surface)的配置。一旦初始化了 EGL,就可以确定可用渲染表面的类型和配置
 *    chooseConfig
 * 4. 创建渲染表面 surface(4/5步骤可互换)
 *    eglCreateWindowSurface
 * 5. 创建渲染上下文 Context
 *    eglCreateContext
 * 6. 指定某个 EGLContext 为当前上下文, 关联起来
 *    eglMakeCurrent
 * 1~6步完成之后,我们可以通过OpenGL的 API 来绘制东西
 *
 * 7. 使用OpenGL相关的API进行绘制操作
 *
 * 8. 交换EGL的Surface的内部缓冲和EGL创建的和平台无关的窗口 diaplay ;
 *    EGL实际上维护了两个buffer,前台buffer显示的时候,绘制操作会在后台buffer上进行
 *    eglSwapBuffers
 *
 *  9. 销毁display
 *     eglTerminate
 *  10. 销毁上下文
 *      eglDestroyContext
 *  11. 销毁surface
 *      eglDestroySurface
 *
 * */

 

程序如下:

 

Shader.vert   顶点着色器程序

//Shader.vert文件内容
static const char* VERTEX_SHADER =
    "attribute vec4 vPosition;    \n"
    "attribute vec2 a_texCoord;   \n"
    "varying vec2 tc;             \n"
    "void main()                  \n"
    "{                            \n"
        "gl_Position = vPosition; \n"
	"tc = a_texCoord;         \n"
    "}                            \n";

Shader.frag  片源着色器程序

该段程序类似 C 语言中 YUV 转 RGB 的算法

//Shader.frag文件内容
static const char* FRAG_SHADER =
    "varying lowp vec2 tc;                         \n"
    "uniform sampler2D dataY;                      \n"
    "uniform sampler2D dataU;                      \n"
    "uniform sampler2D dataV;                      \n"
    "void main(void)                               \n"
    "{                                             \n"
        "mediump vec3 yuv;                         \n"
        "lowp vec3 rgb;                            \n"
        "yuv.x = texture2D(dataY, tc).r;           \n"
        "yuv.y = texture2D(dataU, tc).r - 0.5;     \n"
	"yuv.z = texture2D(dataV, tc).r - 0.5;     \n"
	"rgb = mat3( 1,   1,   1,                  \n"
        "0,       -0.39465,  2.03211,              \n"
        "1.13983,   -0.58060,  0) * yuv;           \n"
	"gl_FragColor = vec4(rgb, 1);              \n"
    "}                                             \n";

 cur_log.h 打印信息

#ifndef CUR_LOG_H
#define CUR_LOG_H

#include <android/log.h>

#ifdef __cplusplus
extern "C" {
#endif

#undef  LOG_TAG
#define LOG_TAG "cur_log"

#define cur_logi(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)  /* 普通打印信息 */
#define cur_loge(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) /* 错误打印信息 */
// #define cur_logi(fmt, args...)  printf("I %s " fmt "\n", LOG_TAG, ##args)
// #define cur_loge(fmt, args...)  printf("E %s " fmt "\n", LOG_TAG, ##args)
#define cur_enter() cur_logi("enter, %s", __func__)
#define cur_exit()  cur_logi("exit,  %s", __func__)

#ifdef __cplusplus
}
#endif

/* CUR_LOG_H */
#endif

 

yuvTest.h 头文件

#ifndef YUVTEST_H
#define YUVTEST_H


#ifdef __cplusplus
extern "C"{
#endif

enum
{
    ATTRIB_VERTEX = 0,
    ATTRIB_TEXTURE,
};


typedef struct _gmVector3
{
    GLfloat x;
    GLfloat y;
    GLfloat z;
} gmVector3_s;

typedef struct _gmMatrix4
{
    GLfloat m[16];
} gmMatrix4;

typedef struct _gmVector2
{
    float x;
    float y;
} gmVector2_s;

typedef struct _gmVector4
{
    float x;
    float y;
    float z;
    float w;
} gmVector4_s;

static void printGLString(const char *name, GLenum s);
static void checkEglError(const char *op, EGLBoolean returnVal = EGL_TRUE);
static void checkGlError(const char *op);
GLuint buildShader(GLenum shaderType, const char *pSource);
GLuint createProgram(const char *pVertexSource, const char *pFragmentSource);
bool setupGraphics(int w __unused, int h __unused);
void renderFrame();
void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
int printEGLConfigurations(EGLDisplay dpy);
GLuint bindTexture(GLuint texture, const char *buffer, GLuint w, GLuint h);

#ifdef __cplusplus
}
#endif


#endif // GL2_BASIC_H

 

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <sys/resource.h>
#include <math.h>

#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <utils/Timers.h>
#include <WindowSurface.h>
#include <EGLUtils.h>
#include <unistd.h>
#include "yuvTest.h"
#include "cur_log.h"
#include "Shader.vert"
#include "Shader.frag"

using namespace android;
using namespace std;



GLuint g_texYId;
GLuint g_texUId;
GLuint g_texVId;
GLuint gProgram;
GLuint uLocMvp;


static void printGLString(const char *name, GLenum s)
{

    const char *v = (const char *) glGetString(s);

    fprintf(stderr, "GL %s = %s\n", name, v);
}

static void checkEglError(const char *op, EGLBoolean returnVal)
{
    if(returnVal != EGL_TRUE)
    {
        fprintf(stderr, "%s() returned %d\n", op, returnVal);
    }

    for(EGLint error = eglGetError(); error != EGL_SUCCESS; error
                                                                    = eglGetError())
    {
        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
                error);
    }
}

static void checkGlError(const char *op)
{
    for(GLint error = glGetError(); error; error
                                                   = glGetError())
    {
        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
    }
}




GLuint buildShader(GLenum shaderType, const char *pSource)
{
    // 创建着色器 Shader
    GLuint shader = glCreateShader(shaderType);
    if(shader)
    {
        glShaderSource(shader, 1, &pSource, NULL);  // 替换着色器对象中的源代码
        glCompileShader(shader);   // 编译一个着色器对象
        GLint compiled = 0;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);  // 从着色器对象返回一个参数
        if(!compiled)
        {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if(infoLen)
            {
                char *buf = (char *) malloc(infoLen);
                if(buf)
                {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);  // 返回着色器对象的信息日志
                    fprintf(stderr, "Could not compile shader %d:\n%s\n",
                            shaderType, buf);
                    free(buf);
                }
                glDeleteShader(shader);   // 删除一个着色器对象
                shader = 0;
            }
        }
    }
    return shader;
}

GLuint createProgram(const char *pVertexSource, const char *pFragmentSource)
{
    // 创建一个顶点着色器对象 Vertex Shader
    GLuint vertexShader = buildShader(GL_VERTEX_SHADER, pVertexSource);
    if(!vertexShader)
    {
        return 0;
    }
    // 创建一个像素着色器对象 Fragment Shader
    GLuint pixelShader = buildShader(GL_FRAGMENT_SHADER, pFragmentSource);
    if(!pixelShader)
    {
        return 0;
    }
    // 创建一个 program 对象
    GLuint program = glCreateProgram();
    if(program)
    {
        glAttachShader(program, vertexShader); // 将顶点着色器对象附加到 program 对象
        checkGlError("glAttachShader");
        glAttachShader(program, pixelShader);  // 将像素着色器对象附加到 program 对象
        checkGlError("glAttachShader");
        glLinkProgram(program);                // 连接一个 program 对象
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);  // 获取参数,判断链接状态
        if(linkStatus != GL_TRUE)
        {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if(bufLength)
            {
                char *buf = (char *) malloc(bufLength);
                if(buf)
                {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    fprintf(stderr, "Could not link program:\n%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}





bool setupGraphics(int w __unused, int h  __unused)
{

   // gProgram = createProgram(gVertexShader, gFragmentShader); // 创建一个顶点着色器,一个像素着色器
   gProgram = createProgram(VERTEX_SHADER, FRAG_SHADER); // 创建一个顶点着色器,一个像素着色器
    if(!gProgram)
    {
        return false;
    }

    // 否则颜色清除错误错误
    glUseProgram(gProgram);  // 使用 program 对象作为当前 render 渲染状态的一部分
    checkGlError("glUseProgram");

    uLocMvp = glGetUniformLocation(gProgram, "uMvp");  // 返回统一变量的位置(句柄)
    glGenTextures(1, &g_texYId);    // 生成纹理名称(ID)
    glGenTextures(1, &g_texUId);
    glGenTextures(1, &g_texVId);

    return true;
}



void renderFrame()
{
#if 1
    static GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        1.0f,  1.0f,
    };

    static GLfloat coordVertices[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
    };
#else
    static GLfloat squareVertices[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f,  1.0f,
        1.0f,  1.0f,
    };

    static GLfloat coordVertices[] = {
            -1.0f, 1.0f,
            1.0f, 1.0f,
            -1.0f,  -1.0f,
            1.0f,  -1.0f,
    };
#endif

	glClearColor(0.5f, 0.5f, 0.5f, 1);  // 指定颜色缓冲区清除时的RGBA值,默认都是0
    checkGlError("glClearColor");
	glClear(GL_COLOR_BUFFER_BIT);       // 清除预设值的缓冲区, GL_COLOR_BUFFER_BIT - 表示当前启用了颜色写入的缓冲区。
    checkGlError("glClear");
	//PRINTF("setsampler %d %d %d", g_texYId, g_texUId, g_texVId);
	GLint tex_y = glGetUniformLocation(gProgram, "dataY");   // 返回 dataY 变量的位置
    checkGlError("glGetUniformLocation");
	GLint tex_u = glGetUniformLocation(gProgram, "dataU");
    checkGlError("glGetUniformLocation");
	GLint tex_v = glGetUniformLocation(gProgram, "dataV");
    checkGlError("glGetUniformLocation");


	glBindAttribLocation(gProgram, ATTRIB_VERTEX, "vPosition");  // 将通用顶点属性索引与命名属性变量绑定
    checkGlError("glBindAttribLocation");
	glBindAttribLocation(gProgram, ATTRIB_TEXTURE, "a_texCoord");
    checkGlError("glBindAttribLocation");

    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);  // 定义通用顶点属性数据的数组
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    checkGlError("glEnableVertexAttribArray");

    glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, coordVertices);
    checkGlError("glVertexAttribPointer");
    glEnableVertexAttribArray(ATTRIB_TEXTURE);
    checkGlError("glEnableVertexAttribArray");

	glActiveTexture(GL_TEXTURE0);        // 激活纹理单元
    checkGlError("glActiveTexture");
	glBindTexture(GL_TEXTURE_2D, g_texYId);  // 将一个指定的纹理ID绑定到一个纹理目标上
    checkGlError("glBindTexture");
	glUniform1i(tex_y, 0);               // 通过 glUniform1i 的设置,保证每个uniform采样器对应着正确的纹理单元
    checkGlError("glUniform1i");

	glActiveTexture(GL_TEXTURE1);
    checkGlError("glActiveTexture");
	glBindTexture(GL_TEXTURE_2D, g_texUId);
    checkGlError("glBindTexture");
	glUniform1i(tex_u, 1);
    checkGlError("glUniform1i");

	glActiveTexture(GL_TEXTURE2);
    checkGlError("glActiveTexture");
	glBindTexture(GL_TEXTURE_2D, g_texVId);
    checkGlError("glBindTexture");
	glUniform1i(tex_v, 2);
    checkGlError("glUniform1i");

	//glEnable(GL_TEXTURE_2D);
    //checkGlError("glEnable");
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  // 从数组数据中渲染图元
    checkGlError("glDrawArrays");

}


void printEGLConfiguration(EGLDisplay dpy, EGLConfig config)
{

#define X(VAL) {VAL, #VAL}
    struct
    {
        EGLint attribute;
        const char *name;
    } names[] = {
            X(EGL_BUFFER_SIZE),
            X(EGL_ALPHA_SIZE),
            X(EGL_BLUE_SIZE),
            X(EGL_GREEN_SIZE),
            X(EGL_RED_SIZE),
            X(EGL_DEPTH_SIZE),
            X(EGL_STENCIL_SIZE),
            X(EGL_CONFIG_CAVEAT),
            X(EGL_CONFIG_ID),
            X(EGL_LEVEL),
            X(EGL_MAX_PBUFFER_HEIGHT),
            X(EGL_MAX_PBUFFER_PIXELS),
            X(EGL_MAX_PBUFFER_WIDTH),
            X(EGL_NATIVE_RENDERABLE),
            X(EGL_NATIVE_VISUAL_ID),
            X(EGL_NATIVE_VISUAL_TYPE),
            X(EGL_SAMPLES),
            X(EGL_SAMPLE_BUFFERS),
            X(EGL_SURFACE_TYPE),
            X(EGL_TRANSPARENT_TYPE),
            X(EGL_TRANSPARENT_RED_VALUE),
            X(EGL_TRANSPARENT_GREEN_VALUE),
            X(EGL_TRANSPARENT_BLUE_VALUE),
            X(EGL_BIND_TO_TEXTURE_RGB),
            X(EGL_BIND_TO_TEXTURE_RGBA),
            X(EGL_MIN_SWAP_INTERVAL),
            X(EGL_MAX_SWAP_INTERVAL),
            X(EGL_LUMINANCE_SIZE),
            X(EGL_ALPHA_MASK_SIZE),
            X(EGL_COLOR_BUFFER_TYPE),
            X(EGL_RENDERABLE_TYPE),
            X(EGL_CONFORMANT),
    };
#undef X

    for(size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++)
    {
        EGLint value = -1;
        EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
        EGLint error = eglGetError();
        if(returnVal && error == EGL_SUCCESS)
        {
            printf(" %s: ", names[j].name);
            printf("%d (0x%x)", value, value);
        }
    }
    printf("\n");
}

int printEGLConfigurations(EGLDisplay dpy)
{
    EGLint numConfig = 0;
    EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
    checkEglError("eglGetConfigs", returnVal);
    if(!returnVal)
    {
        return false;
    }

    printf("Number of EGL configuration: %d\n", numConfig);

    EGLConfig *configs = (EGLConfig *) malloc(sizeof(EGLConfig) * numConfig);
    if(!configs)
    {
        printf("Could not allocate configs.\n");
        return false;
    }

    returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
    checkEglError("eglGetConfigs", returnVal);
    if(!returnVal)
    {
        free(configs);
        return false;
    }

    for(int i = 0; i < numConfig; i++)
    {
        printf("Configuration %d\n", i);
        printEGLConfiguration(dpy, configs[i]);
    }

    free(configs);
    return true;
}


GLuint bindTexture(GLuint texture, const char *buffer, GLuint w , GLuint h)
{
//	GLuint texture;
//	glGenTextures ( 1, &texture );
    checkGlError("glGenTextures");
	glBindTexture(GL_TEXTURE_2D, texture); // 指定一个二维的纹理图片
    checkGlError("glBindTexture");
	glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer); // 指定一个二维的纹理图片
    checkGlError("glTexImage2D");
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );  // 纹理过滤函数, GL_TEXTURE_MIN_FILTER 缩小过滤
    checkGlError("glTexParameteri");
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );  // 纹理过滤函数, GL_TEXTURE_MAG_FILTER 放大过滤
    checkGlError("glTexParameteri");
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );  // 纹理过滤函数, GL_TEXTURE_WRAP_S S方向上的贴图模式
    checkGlError("glTexParameteri");
	glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    checkGlError("glTexParameteri");
	//glBindTexture(GL_TEXTURE_2D, 0);

	return texture;
}

// ****************************************************************************

int main(int argc __unused, char **argv __unused)
{
    EGLBoolean returnValue;
    EGLConfig myConfig = {0};

    EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    //当前我们要的是Windows的surface,在屏幕上是可见的,以EGL_NONE结尾。

    EGLint s_configAttribs[] = {
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_NONE};
    EGLint majorVersion;
    EGLint minorVersion;
    EGLContext context;
    EGLSurface surface;
    EGLint w, h;

    EGLDisplay dpy;
// 第一步: 初始化EGL和创建Open GL上下文环境
    checkEglError("<init>");
    // 1. 取得显示设备, 获得默认的 Display 。通常我们只有一块屏幕,参数传 EGL_DEFAULT_DISPLAY 就可以了。
    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    checkEglError("eglGetDisplay");
    if(dpy == EGL_NO_DISPLAY)
    {
        printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
        return 0;
    }

    // 2. 初始化 EGL 显示设备
    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
    checkEglError("eglInitialize", returnValue);
    fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
    if(returnValue != EGL_TRUE)
    {
        printf("eglInitialize failed\n");
        return 0;
    }
    // 打印 EGL 配置
    if(!printEGLConfigurations(dpy))
    {
        printf("printEGLConfigurations failed\n");
        return 0;
    }

    checkEglError("printEGLConfigurations");

    // 3. 确定可用的渲染表面(Surface)的配置。一旦初始化了 EGL,就可以确定可用渲染表面的类型和配置
    WindowSurface windowSurface;
    EGLNativeWindowType window = windowSurface.getSurface();
    returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
    if(returnValue)
    {
        printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
        return 0;
    }

    checkEglError("EGLUtils::selectConfigForNativeWindow");

    printf("Chose this configuration:\n");
    //   printEGLConfiguration(dpy, myConfig);

    // 4. 创建渲染表面 surface。(4/5步骤可互换)
    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
    checkEglError("eglCreateWindowSurface");
    if(surface == EGL_NO_SURFACE)
    {
        printf("gelCreateWindowSurface failed.\n");
        return 0;
    }

    // 5. 创建渲染上下文,使用前面的显示设备和配置信息来创建 OpenGL 上下文环境
    context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
    checkEglError("eglCreateContext");
    if(context == EGL_NO_CONTEXT)
    {
        printf("eglCreateContext failed\n");
        return 0;
    }

    // 将创建的 context 绑定到当前的线程,使用我们创建的 surface 进行读和写。
    // context 绑定到线程上,可不用担心其他进程影响你的 OpenGLES 应用程序。
    // 6. 指定某个 EGLContext 为当前上下文
    returnValue = eglMakeCurrent(dpy, surface, surface, context);
    checkEglError("eglMakeCurrent", returnValue);
    if(returnValue != EGL_TRUE)
    {
        return 0;
    }


    // Surface 也有一些 attribute
    // EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL
    // 通过 eglSurfaceAttrib() 设置、 eglQuerySurface() 读取。 mat

    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
    checkEglError("eglQuerySurface");
    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
    checkEglError("eglQuerySurface");
    // GLint dim = w < h ? w : h;

    fprintf(stderr, "Window dimensions: %d x %d\n", w, h);

    printGLString("Version", GL_VERSION);
    printGLString("Vendor", GL_VENDOR);
    printGLString("Renderer", GL_RENDERER);
    printGLString("Extensions", GL_EXTENSIONS);
//开始绘制

    if(!setupGraphics(w, h))
    {
        fprintf(stderr, "Could not set up graphics.\n");
        return 0;
    }
    int width = 1440, height = 1080;
    FILE *fp = fopen("/sdcard/bb.yuv", "rb");
    if(fp == NULL)
    {
        cur_loge("fopen fp failed");
    }
    char *buffer = (char*)malloc(width * height * 3 / 2);
    if(buffer == NULL)
    {
        cur_loge("malloc buffer failed");
    }
    for (;;)
    {
        if(buffer != NULL && fp != NULL)
        {
            // glViewport(0, 0, width, height);  // 设置视口
            int ret = fread(buffer, 1, width * height * 3 / 2, fp);
            if(ret ==  width * height * 3 / 2)
            {
                bindTexture(g_texYId, buffer, width, height);
                bindTexture(g_texUId, buffer + width * height, width/2, height/2);
                bindTexture(g_texVId, buffer + width * height * 5 / 4, width/2, height/2);
                renderFrame();
                usleep(100 * 1000);
                eglSwapBuffers(dpy, surface); // EGL实际上维护了两个 buffer ,前台 buffer 显示的时候,绘制操作会在后台 buffer 上进行
                checkEglError("eglSwapBuffers");
            }
            else
            {
                cur_logi("end read file");
            }
                }
    }
    if(fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }
    if(buffer != NULL)
    {
        free(buffer);
        buffer = NULL;
    }
    return 0;
}

 

Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := yuvTest.cpp

LOCAL_SHARED_LIBRARIES := \
    libcutils \
    libEGL \
    libGLESv2 \
    libui \
    libgui \
    libutils

LOCAL_STATIC_LIBRARIES += libglTest
LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
LOCAL_MODULE := yuvopenGL
LOCAL_MODULE_TAGS := optional

LOCAL_CFLAGS := -lpthread -DGL_GLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Wno-unused-function -Wno-unused-const-variable -Wno-unused-variable

include $(BUILD_EXECUTABLE)

 

 

运行方法:

adb push out/xxx/xxx/system/bin/yuvopenGL system/bin/
adb shell
yuvopenGL

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值