简述视频渲染的过程:
- 视频解码
- 图像处理(裁剪、缩放等)
- 合成处理(帧+叠加文字、动画)
- 显示输出
视频渲染数据源
YUV 或者 RGBA 数据,一般视频是YUV数据,图像使用的是RGBA数据。最终渲染到屏幕上的都是RGBA数据,因为屏幕上的硬件设计就是一个像素点四个像素。
iOS 平台视频渲染方案
Quartz 2D :CGContext、CGPath、CGImage、CGColor、CGGradient、CGShading。使用简单,但功能比较局限,通常用在自定义View上,处理阴影、渐变等,但无法处理美颜、视频贴纸、滤镜。
OpenGL :二维、三维图像处理,强大的底层图形库,提供一组C函数库,可以跨平台使用。但使用门槛比较高,需要掌握以下几个知识点
- 根据使用平台的不同,构建不同平台的上下文环境,提供渲染的基础实现(可以使用SDL,但会失去灵活性,部分功能就无法使用)。
- 学会使用GLSL语言书写着色器,GLSL语言编写的代码最终可以编译、链接成为一个GLProgram。
从代码层面上理解,编写一个着色器需要调用到三个主要函数:glCreateShader、glShaderSource、glCompileShader 、g|CreateProgram,分别是创建着色器对象、设置源代码、编译、最终得到 GLProgram。
OpenGL ES : OpenGL for Embedded Systems , 是 OpenGL 在嵌入式设备上的版本。
渲染管线
OpenGL引擎将图像一步步渲染到屏幕上的步骤
-
指定几何图像:由几何图元 点GL_POINTS、线GL_LINES、三角GL_TRIANGLE_STRIP绘制几何图像,OpenGL通过绘制方法glDrawArrays的第一个参数Mode指定使用的图元。
-
顶点变化:无论使用哪种几何图元,都要进行顶点变换
- 通过模型视图和投影矩阵,改变顶点坐标。
- 通过纹理坐标和纹理矩阵,改变纹理坐标位置。如果使用的是GL_POINTS还需要输出gl_PointSize
- 3D渲染,还需要处理光照计算和法线变换
-
组装图元:顶点坐标+纹理+图元规则
-
栅格化:将图元分解成更小的单元-片元,这个操作能确定片元类型。
-
片元处理:调节饱和度、锐化等
-
帧缓冲操作:执行帧缓冲的写入等操作,OpenGL 引擎负责把最终的像素值写入到帧缓冲区中。
创建一个GLProgram并链接
/*
GL_VERTEX_SHADER:顶点着色器
GL_FRAGMENT_SHADER:片元着色器
@return typedef uint32_t GLuint; 容器的句柄
*/
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
/*
设置顶点着色器源代码
根据 GLSL 语法和内嵌函数书写出来的两个着色器程序,都是字符串类型。这个函数的作用就是把开发者的着色器程序加载到着色器句柄所关联的内存中
*/
const GLchar *vertexShaderSource = "attribute vec4 position; void main() { gl_Position = position; }";
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
// 验证顶点着色器对象是否有效
GLint success;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
// 如果查询到的编译状态为 GL_FALSE,则表示顶点着色器编译失败,可以继续使用 glGetShaderiv 函数查询错误信息。
GLint infoLength;
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLength);
if (infoLength > 0) {
GLchar *infoLog = (GLchar *)malloc(sizeof(GLchar) * infoLength);
glGetShaderInfoLog(vertexShader, infoLength, NULL, infoLog);
NSLog(@"Vertex shader compilation failed: %s", infoLog);
free(infoLog);
}
}
// 创建一个程序的实例作为程序的容器,这个函数返回程序的句柄
GLuint glCreateProgram(void);
// 把上面部分编译的 shader 附加(Attach)到刚刚创建的程序中
glAttachShader(glCreateProgram, vertexShader);
// 最后一步链接程序
glLinkProgram(glCreateProgram);
// 验证程序链接是否成功
GLint linkSuccess;
glGetProgramiv(glCreateProgram, GL_LINK_STATUS, &linkSuccess);
if (!linkSuccess) {
GLint infoLength;
glGetProgramiv(glCreateProgram, GL_INFO_LOG_LENGTH, &infoLength);
if (infoLength > 0) {
GLchar *infoLog = (GLchar *)malloc(sizeof(GLchar) * infoLength);
glGetProgramInfoLog(glCreateProgram, infoLength, NULL, infoLog);
NSLog(@"Program linking failed: %s", infoLog);
free(infoLog);
}
}
NSLog(@"linking Success");
网友评论