CMakeLists 文件配置:
cmake_minimum_required(VERSION 3.4.1)
#音频渲染
set(OpenSL ${CMAKE_SOURCE_DIR}/opensl)
#视频渲染
set(OpenGL ${CMAKE_SOURCE_DIR}/gles)
#批量添加自己编写的 cpp 文件,不要把 .h 加入进来了
file(GLOB ALL_CPP ${OpenSL}/.cpp ${OpenGL}/*.cpp)
#添加自己编写 cpp 源文件生成动态库
add_library(audiovideo SHARED ${ALL_CPP})
#找系统中 NDK log库
find_library(log_lib
log)
#最后才开始链接库
target_link_libraries(
#最后生成的 so 库名称
audiovideo
#音频渲染
OpenSLES
OpenGL 与 NativeWindow 连接本地窗口的中间者
EGL
#视频渲染
GLESv2
#添加本地库
android
${log_lib}
)
至此,对于 OpenGL 的开发需要用到的头文件以及库文件就引入完毕了,下面再来看看如何使用 EGL 搭建出 OpenGL 的上下文环境以及渲染视频数据。
-
- 使用 EGL 首先必须创建,建立本地窗口系统和 OpenGL ES 的连接
//1.获取原始窗口
nativeWindow = ANativeWindow_fromSurface(env, surface);
//获取Display
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
LOGD(“egl display failed”);
showMessage(env, “egl display failed”, false);
return;
}
-
- 初始化 EGL
//初始化egl,后两个参数为主次版本号
if (EGL_TRUE != eglInitialize(display, 0, 0)) {
LOGD(“eglInitialize failed”);
showMessage(env, “eglInitialize failed”, false);
return;
}
-
- 确定可用的渲染表面( Surface )的配置。
//surface 配置,可以理解为窗口
EGLConfig eglConfig;
EGLint configNum;
EGLint configSpec[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
if (EGL_TRUE != eglChooseConfig(display, configSpec, &eglConfig, 1, &configNum)) {
LOGD(“eglChooseConfig failed”);
showMessage(env, “eglChooseConfig failed”, false);
return;
}
-
- 创建渲染表面 surface(4/5步骤可互换)
//创建surface(egl和NativeWindow进行关联。最后一个参数为属性信息,0表示默认版本)
winSurface = eglCreateWindowSurface(display, eglConfig, nativeWindow, 0);
if (winSurface == EGL_NO_SURFACE) {
LOGD(“eglCreateWindowSurface failed”);
showMessage(env, “eglCreateWindowSurface failed”, false);
return;
}
-
- 创建渲染上下文 Context
//4 创建关联上下文
const EGLint ctxAttr[] = {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
};
//EGL_NO_CONTEXT表示不需要多个设备共享上下文
context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, ctxAttr);
if (context == EGL_NO_CONTEXT) {
LOGD(“eglCreateContext failed”);
showMessage(env, “eglCreateContext failed”, false);
return;
}
-
- 指定某个 EGLContext 为当前上下文, 关联起来
//将egl和opengl关联
//两个surface一个读一个写。第二个一般用来离线渲染
if (EGL_TRUE != eglMakeCurrent(display, winSurface, winSurface, context)) {
LOGD(“eglMakeCurrent failed”);
showMessage(env, “eglMakeCurrent failed”, false);
return;
}
-
- 使用 OpenGL 相关的 API 进行绘制操作
GLint vsh = initShader(vertexShader, GL_VERTEX_SHADER);
GLint fsh = initShader(fragYUV420P, GL_FRAGMENT_SHADER);
//创建渲染程序
GLint program = glCreateProgram();
if (program == 0) {
LOGD(“glCreateProgram failed”);
showMessage(env, “glCreateProgram failed”, false);
return;
}
//向渲染程序中加入着色器
glAttachShader(program, vsh);
glAttachShader(program, fsh);
//链接程序
glLinkProgram(program);
GLint status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == 0) {
LOGD(“glLinkProgram failed”);
showMessage(env, “glLinkProgram failed”, false);
return;
}
LOGD(“glLinkProgram success”);
//激活渲染程序
glUseProgram(program);
//加入三维顶点数据
static float ver[] = {
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f
};
GLuint apos = static_cast(glGetAttribLocation(program, “aPosition”));
glEnableVertexAttribArray(apos);
glVertexAttribPointer(apos, 3, GL_FLOAT, GL_FALSE, 0, ver);
//加入纹理坐标数据
static float fragment[] = {
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
GLuint aTex = static_cast(glGetAttribLocation(program, “aTextCoord”));
glEnableVertexAttribArray(aTex);
glVertexAttribPointer(aTex, 2, GL_FLOAT, GL_FALSE, 0, fragment);
//纹理初始化
//设置纹理层对应的对应采样器?
/**
- //获取一致变量的存储位置
GLint textureUniformY = glGetUniformLocation(program, “SamplerY”);
GLint textureUniformU = glGetUniformLocation(program, “SamplerU”);
GLint textureUniformV = glGetUniformLocation(program, “SamplerV”);
//对几个纹理采样器变量进行设置
glUniform1i(textureUniformY, 0);
glUniform1i(textureUniformU, 1);
glUniform1i(textureUniformV, 2);
*/
//对sampler变量,使用函数glUniform1i和glUniform1iv进行设置
glUniform1i(glGetUniformLocation(program, “yTexture”), 0);
glUniform1i(glGetUniformLocation(program, “uTexture”), 1);
glUniform1i(glGetUniformLocation(program, “vTexture”), 2);
//纹理ID
GLuint texts[3] = {0};
//创建若干个纹理对象,并且得到纹理ID
glGenTextures(3, texts);
//绑定纹理。后面的的设置和加载全部作用于当前绑定的纹理对象
//GL_TEXTURE0、GL_TEXTURE1、GL_TEXTURE2 的就是纹理单元,GL_TEXTURE_1D、GL_TEXTURE_2D、CUBE_MAP为纹理目标
//通过 glBindTexture 函数将纹理目标和纹理绑定后,对纹理目标所进行的操作都反映到对纹理上
glBindTexture(GL_TEXTURE_2D, texts[0]);
//缩小的过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//放大的过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理的格式和大小
// 加载纹理到 OpenGL,读入 buffer 定义的位图数据,并把它复制到当前绑定的纹理对象
// 当前绑定的纹理对象就会被附加上纹理图像。
//width,height表示每几个像素公用一个yuv元素?比如width / 2表示横向每两个像素使用一个元素?
glTexImage2D(GL_TEXTURE_2D,
0,//细节基本 默认0
GL_LUMINANCE,//gpu内部格式 亮度,灰度图(这里就是只取一个亮度的颜色通道的意思)
width,//加载的纹理宽度。最好为2的次幂(这里对y分量数据当做指定尺寸算,但显示尺寸会拉伸到全屏?)
height,//加载的纹理高度。最好为2的次幂
0,//纹理边框
GL_LUMINANCE,//数据的像素格式 亮度,灰度图
GL_UNSIGNED_BYTE,//像素点存储的数据类型
NULL //纹理的数据(先不传)
);
//绑定纹理
glBindTexture(GL_TEXTURE_2D, texts[1]);
//缩小的过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理的格式和大小
glTexImage2D(GL_TEXTURE_2D,
0,//细节基本 默认0
GL_LUMINANCE,//gpu内部格式 亮度,灰度图(这里就是只取一个颜色通道的意思)
width / 2,//u数据数量为屏幕的4分之1
height / 2,
0,//边框
GL_LUMINANCE,//数据的像素格式 亮度,灰度图
GL_UNSIGNED_BYTE,//像素点存储的数据类型
NULL //纹理的数据(先不传)
);
//绑定纹理
glBindTexture(GL_TEXTURE_2D, texts[2]);
//缩小的过滤器
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//设置纹理的格式和大小
glTexImage2D(GL_TEXTURE_2D,
0,//细节基本 默认0
GL_LUMINANCE,//gpu内部格式 亮度,灰度图(这里就是只取一个颜色通道的意思)
width / 2,
height / 2,//v数据数量为屏幕的4分之1
0,//边框
GL_LUMINANCE,//数据的像素格式 亮度,灰度图
GL_UNSIGNED_BYTE,//像素点存储的数据类型
NULL //纹理的数据(先不传)
);
unsigned char *buf[3] = {0};
buf[0] = new unsigned char[width * height];//y
buf[1] = new unsigned char[width * height / 4];//u
buf[2] = new unsigned char[width * height / 4];//v
showMessage(env, “onSucceed”, true);
FILE *fp = fopen(data_source, “rb”);
if (!fp) {
LOGD(“oepn file %s fail”, data_source);
return;
}
while (!feof(fp)) {
//解决异常退出,终止读取数据
if (!isPlay)
return;
fread(buf[0], 1, width * height, fp);
fread(buf[1], 1, width * height / 4, fp);
fread(buf[2], 1, width * height / 4, fp);
//激活第一层纹理,绑定到创建的纹理
//下面的width,height主要是显示尺寸?
glActiveTexture(GL_TEXTURE0);
//绑定y对应的纹理
glBindTexture(GL_TEXTURE_2D, texts[0]);
//替换纹理,比重新使用glTexImage2D性能高多
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, 0,//相对原来的纹理的offset
width, height,//加载的纹理宽度、高度。最好为2的次幂
GL_LUMINANCE, GL_UNSIGNED_BYTE,
buf[0]);
//激活第二层纹理,绑定到创建的纹理
glActiveTexture(GL_TEXTURE1);
//绑定u对应的纹理
glBindTexture(GL_TEXTURE_2D, texts[1]);
//替换纹理,比重新使用glTexImage2D性能高
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_LUMINANCE,
GL_UNSIGNED_BYTE,
buf[1]);
//激活第三层纹理,绑定到创建的纹理
glActiveTexture(GL_TEXTURE2);
//绑定v对应的纹理
glBindTexture(GL_TEXTURE_2D, texts[2]);
//替换纹理,比重新使用glTexImage2D性能高
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_LUMINANCE,
GL_UNSIGNED_BYTE,
buf[2]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//8. 窗口显示,交换双缓冲区
eglSwapBuffers(display, winSurface);
}
-
- 交换 EGL 的 Surface 的内部缓冲和 EGL 创建的和平台无关的窗口 diaplay
//窗口显示,交换双缓冲区
eglSwapBuffers(display, winSurface);
复制代码
-
- 释放资源
/**
- 销毁数据
*/
void Gles_play::release() {
if (display || winSurface || context) {
//销毁显示设备
eglDestroySurface(display, winSurface);
//销毁上下文
eglDestroyContext(display, context);
//释放窗口
ANativeWindow_release(nativeWindow);
//释放线程
eglReleaseThread();
//停止
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://img-blog.csdnimg.cn/img_convert/40c1e77dce63cc3dd13294dbca5cf5b3.jpeg)
最后:学习总结——Android框架体系架构知识脑图(纯手绘xmind文档)
学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。
下方即为我手绘的Android框架体系架构知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的Android框架体系架构知识脑图原件(包括上方的面试解析xmind文档)
除此之外,前文所提及的Alibaba珍藏版 Android框架体系架构 手写文档以及一本 《大话数据结构》 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!
——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的Android框架体系架构知识脑图原件(包括上方的面试解析xmind文档)
[外链图片转存中…(img-2Qsh3mIO-1713216956664)]
除此之外,前文所提及的Alibaba珍藏版 Android框架体系架构 手写文档以及一本 《大话数据结构》 书籍等等相关的学习笔记文档,也皆可分享给认可的朋友!
——感谢大家伙的认可支持,请注意:点赞+点赞+点赞!!!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!