太简便易行的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)

正文记录OpenGL播放视频的技艺。上一致首稿子中,介绍了同样栽简单的应用OpenGL显示视频的方。但是那还未是OpenGL显示视频技术的精粹。和Direct3D一样,OpenGL更好的来得视频的措施啊是经纹理(Texture)。本文介绍OpenGL通过纹理的方式示视频的技术。

金博宝188bet 1

OpenGL中坐标和Direct3D坐标的差

OpenGL中的纹路的坐标和Direct3D中的坐标是无均等的。

以Direct3D中。纹理坐标如下图所著。取值是0到1。坐标系原点在左上角。

金博宝188bet 2

体表面坐标如下图所出示。取值是事实上的像素值。坐标系原点在左上角。

金博宝188bet 3

OpenGL纹理坐标取值范围是0-1,坐标原点位于左下角。这一点暨Direct3D是见仁见智之,Direct3D纹理坐标的取值虽然为是0-1,但是他的坐标原点位于左上角。

金博宝188bet 4 

以OpenGL中,物体表面坐标取值范围是-1到1。坐标系原点在主导岗位。

金博宝188bet 5

 

OpenGL视频显示的流水线

关于纹理方面的文化就当篇章《最简易的视音频播放示例4:Direct3D播放RGB(通过Texture)》中来详尽的笔录。OpenGL中纹理的定义和Direct3D中纹理的概念基本上是如出一辙的,因此不再重复记录了。

正文记录的主次,播放的是YUV420P格式的像素数量。上平等首稿子中之顺序也足以播放YUV420P格式的像素数量。但是她的法则是休一致的。上一样首文章被,输入的YUV420P像素数据经过一个平常的函数转换为RGB数据后,传送给OpenGL播放。也就是如从的转移是经过CPU完成的。本文的次第,输入的YUV420P像素数据经过Shader转换为YUV数据,传送给OpenGL播放。像从的变是经显卡上之GPU完成的。通过本程序,可以了解下OpenGL进行GPU编程的基础知识。

采用Shader通过OpenGL的纹路(Texture)播放视频一般情形下得如下步骤:
1. 初始化

1) 初始化
2) 创建窗口
3) 设置绘图函数
4) 设置定时器
5) 初始化Shader
初始化Shader的步骤比较多,主要可以分成3步:创建Shader,创建Program,初始化Texture。

(1) 创建一个Shader对象

1)编写Vertex Shader和Fragment Shader源码。

2)创建两独shader 实例 。

3)给Shader实例指定源码。

4)在线编译shaer源码。

(2) 创建一个Program对象

1)创建program。

2)绑定shader到program。

3)链接program。

4)使用porgram。

(3) 初始化Texture。可以分成以下步骤。

1)定义定点数组

2)设置极端数组

3)初始化纹理

6) 进入信息循环

2. 巡回显示画面

1) 设置纹理
2) 绘制
3) 显示

脚详述一下使用Shader通过OpenGL的纹理的播放YUV的步子。有些地方以及上一致首文章是双重的,会比较简单的提取一下。
1. 初始化
1) 初始化

glutInit()用于初始化glut库。它原型如下:

[cpp] view
plaincopy金博宝188bet 6金博宝188bet 7

 

  1. void glutInit(int *argcp, char **argv);  

其包含两独参数:argcp和argv。一般景象下,直接拿main()函数中之argc,argv传递让其即可。
glutInitDisplayMode()用于安装初始显示模式。它的原型如下。

[cpp] view
plaincopy金博宝188bet 8金博宝188bet 9

 

  1. void glutInitDisplayMode(unsigned int mode);  

要专注的是,如果应用对缓冲(GLUT_DOUBLE),则要因此glutSwapBuffers
()绘图。如果运用单缓冲(GLUT_SINGLE),则需要因此glFlush()绘图。
在以OpenGL播放视频的时节,我们得使用下述代码:

[cpp] view
plaincopy金博宝188bet 10金博宝188bet 11

 

  1. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );  

2) 创建窗口
glutInitWindowPosition()用于安装窗口的职位。可以指定x,y坐标。
glutInitWindowSize()用于安装窗口的轻重。可以设置窗口的松,高。
glutCreateWindow()创建一个窗口。可以指定窗口的题。
上述几只函数十分基础,不再详细讲述。直接贴有同截示例代码:

[cpp] view
plaincopy金博宝188bet 12金博宝188bet 13

 

  1. glutInitWindowPosition(100, 100);  
  2. glutInitWindowSize(500, 500);  
  3. glutCreateWindow("Simplest Video Play OpenGL");   

3) 设置绘图函数
glutDisplayFunc()用于安装绘图函数。操作系统在必要时刻就是见面调用该函数对窗体进行双重绘制操作。类似于windows程序设计被处理WM_PAINT消息。例如,当把窗口移动及屏幕边上,然后又动回来的早晚,就会调用该函数对窗口进行重绘。它的原型如下。

[cpp] view
plaincopy金博宝188bet 14金博宝188bet 15

 

  1. void glutDisplayFunc(void (*func)(void));  

其中(*func)用于指定重绘函数。
比如当视频播放的时候,指定display()函数用于重绘:

[cpp] view
plaincopy金博宝188bet 16金博宝188bet 17

 

  1. glutDisplayFunc(&display);  

4) 设置定时器
广播视频的当儿,每秒需要播放一定的镜头(一般是25帧),因此用定时器每间隔一段时间调用一下绘制函数绘制图形。定时器函数glutTimerFunc()的原型如下。

[cpp] view
plaincopy金博宝188bet 18金博宝188bet 19

 

  1. void glutTimerFunc(unsigned int millis, void (*func)(int value), int value);  

她的参数含义如下:

millis:定时之日子,单位凡毫秒。1秒=1000毫秒。

(*func)(int value):用于指定定时器调用的函数。

value:给回调函数传参。比较高端,没有点了。

 

假定光当主函数惨遭形容一个glutTimerFunc()函数的讲话,会发现就会调用该函数同一蹩脚。因此用以回调函数中再度写一个glutTimerFunc()函数,并调用回调函数自己。只有这么才能够促成再循环调用回调函数。
像当视频播放的时,指定每40毫秒调用一浅timeFunc ()函数:
主函数惨遭:

[cpp] view
plaincopy金博宝188bet 20金博宝188bet 21

 

  1. glutTimerFunc(40, timeFunc, 0);  

自此在timeFunc()函数中如下设置。

[cpp] view
plaincopy金博宝188bet 22金博宝188bet 23

 

  1. void timeFunc(int value){  
  2.     display();  
  3.     // Present frame every 40 ms  
  4.     glutTimerFunc(40, timeFunc, 0);  
  5. }  

诸如此类尽管实现了各国40ms调用平等不行display()。

5) 初始化Shader
初始化Shader的步骤比较多,主要得分成3步:创建Shader,创建Program,初始化Texture。它们的步骤如下所示。
(1) 创建一个Shader对象
Shader有点类似于一个顺序的编译器。创建一个Shader可以分为以下4步:

1)编写Vertex Shader和Fragment Shader源码。
2)创建两个shader 实例:glCreateShader()。
3)给Shader实例指定源码:glShaderSource()。
4)在线编译shaer源码 glCompileShader()。

下面详细分析这4步。
1) 编写Vertex Shader和Fragment Shader源码。
在这边用了平栽新的言语:OpenGL Shader
Language,简称GLSL。它是一模一样种恍若于C语言的专门为GPU设计的语言,它好置身GPU里面为并行运行。
OpenGL的着色器有.fsh和.vsh两单公文。这简单单文件于被编译和链接后就是足以起可执行程序与GPU交互。.vsh
是Vertex
Shader(顶点着色器),用于顶点计算,可以掌握控制顶点的职务,在这个文件被我们普通会传当前终端的职,和纹理的坐标。.fsh
是Fragment
Shader(片元在色器),在当时中我得以对各一个如素点进行重复计算。
下面这张图可以另行好之说Vertex Shader和Fragment
Shader的图。这张图是OpenGL的渲染管线。其中的音讯极多先不一一记录了。从图被好见到,Vertex
Shader在前边,Fragment Shader在晚。

 金博宝188bet 24

于这里贴起本文的以身作则程序的fsh和vsh的代码。

Shader.vsh

[plain] view
plaincopy金博宝188bet 25金博宝188bet 26

 

  1. attribute vec4 vertexIn;   
  2. attribute vec2 textureIn;  
  3. varying vec2 textureOut;  
  4. void main(void)  
  5. {  
  6.     gl_Position = vertexIn;   
  7.     textureOut = textureIn;  
  8. }  

Shader.fsh

[plain] view
plaincopy金博宝188bet 27金博宝188bet 28

 

  1. varying vec2 textureOut;  
  2. uniform sampler2D tex_y;  
  3. uniform sampler2D tex_u;  
  4. uniform sampler2D tex_v;  
  5. void main(void)  
  6. {  
  7.     vec3 yuv;  
  8.     vec3 rgb;      
  9.     yuv.x = texture2D(tex_y, textureOut).r;  
  10.     yuv.y = texture2D(tex_u, textureOut).r - 0.5;  
  11.     yuv.z = texture2D(tex_v, textureOut).r - 0.5;  
  12.     rgb = mat3( 1,       1,         1,  
  13.                 0,       -0.39465,  2.03211,  
  14.                 1.13983, -0.58060,  0) * yuv;      
  15.     gl_FragColor = vec4(rgb, 1);  
  16. }  

于上述代码中得望GLSL的语法和C语言很接近。每一个Shader程序都发一个main函数,这或多或少同c语言是同样的。这里的变量命名规则保持跟c一样就是推行了,注意gl_开始的变量名是系统放的变量。有以下几栽变量:

attribute:外部传入vsh文件的变量,每一个巅峰都见面产生就简单独特性。变化率高,用于定义每个点。
varying:用于 vsh和fsh之间交互传递的参数。
uniform:外部传入vsh文件的变量。变化率较逊色,对于可能以普渲染过程并未改,只是单常量。
上文代码中使用了以下数据类型:
vec2:包含了2只浮点数的向量
vec3:包含了3个浮点数的向量
vec4:包含了4只浮点数的向量
sampler1D:1D纹理着色器
sampler2D:2D纹理着色器
sampler3D:3D纹理着色器
mat2:2*2维矩阵 
mat3:3*3维矩阵 

mat4:4*4维矩阵

 

上文代码中还采用及了OpenGL的几乎单全局变量:
gl_Position:原始之极数据在Vertex
Shader中经过倒、旋转、缩放等数学变换后,生成新的顶峰位置(一个四维
(vec4) 变量,包含顶点的 x、y、z 和 w 值)。新的终极位置通过以Vertex
Shader中形容副gl_Position传递至渲染管线的晚阶段继续处理。
gl_FragColor:Fragment Shader的输出,它是一个四维变量(或称
vec4)。gl_FragColor 表示以经着色器代码处理后,正在显现的像素的
R、G、B、A 值。
Vertex Shader是图被各个一个极的,如果Vertex有三单点,那么Vertex
Shader会被实践三不成。Fragment
Shader是意被每个像素的,一个像素运行一差。从源代码中得看来,像从的易在Fragment
Shader中成功。
在网上来看零星摆设图可以好好地说明Vertex Shader和Fragment Shader的作用:

 金博宝188bet 29

 

金博宝188bet 30

Vertex
Shader(顶点着色器)主要是传播相应的Attribute变量、Uniforms变量、采样器以及临时变量,最后生成Varying变量,以及gl_Posizion等变量。Fragment
Shade(片元在色器)可以实行纹理的访、颜色之汇集、雾化等操作,最后生成gl_FragColor变量。有权威总结如下:“vsh负责将定像素位置,填写gl_Posizion;fsh负责为定像素外观,填写
gl_FragColor。”

2) 创建两只shader 实例。
创一个容纳shader的容器。用glCreateShader
()创建一个容纳shader的容器,它的原型如下:

[cpp] view
plaincopy金博宝188bet 31金博宝188bet 32

 

  1. int glCreateShader (int type)  

其中type包含2种: 

GLES20.GL_VERTEX_SHADER:Vertex Shader.

GLES20.GL_FRAGMENT_SHADER:Fragment Shader. 

 

苟调用成功的讲话,函数将回到一个整形的正整数作为Shader容器的id。
3) 给Shader实例指定源码。
Shader容器中上加shader的源代码。源代码应该因为字符串数组的形式表示。glShaderSource函数的原型如下: 

[cpp] view
plaincopy金博宝188bet 33金博宝188bet 34

 

  1. void glShaderSource (int shader, String string)   

参数含义如下: 

shader:是意味shader容器的id(由glCreateShader()返回的整形数)。

strings:是含有源程序的字符串数组。

 

比方觉得通过“字符串数组”的点子写源代码不绝习惯的话,可以管源代码写到独门的一个文件文件里。然后于得源代码的早晚,读取该文件文件被的享有情节。
4) 在线编译Shader源码。
运glCompileShader()对shader容器中的源代码进行编译。函数的原型如下:  

[cpp] view
plaincopy金博宝188bet 35金博宝188bet 36

 

  1. void glCompileShader (int shader)  

其中shader是代表Shader容器的id。
以编译完成后,可能需要调剂。调试一个Shader是充分艰苦的。Shader的社会风气里无printf,无法在控制台中打印调试信息。但是可由此有些OpenGL提供的函数来得到编译和连过程被的音信。在编译阶段采取glGetShaderiv获取编译情况。glGetShaderiv()函数原型如下:

[cpp] view
plaincopy金博宝188bet 37金博宝188bet 38

 

  1. void glGetShaderiv (int shader, int pname, int[] params, int offset)   

参数含义: 

shader:一个shader的id; 
pname:使用GL_COMPILE_STATUS; 
params:返回值,如果一切正常返回GL_TRUE代,否则回GL_FALSE。

(2) 创建一个Program对象
Program有点类似于一个主次的链接器。program对象提供了将要开的从连在同步的机制。在一个program中,shader对象足以连接于联名。
创建一个Program可以分为以下4步:

1)创建program:glCreateProgram()
2)绑定shader到program :glAttachShader()。
*每个program必须绑定一个Vertex Shader 和一个Fragment Shader。
3)链接program :glLinkProgram()。
4)使用porgram :glUseProgram()。

下面详细分析这4步。
1) 创建program。
首先以glCreateProgram
()创建一个盛程序(Program)的器皿,我们叫程序容器。
函数的原型如下:

[cpp] view
plaincopy金博宝188bet 39金博宝188bet 40

 

  1. int glCreateProgram ()  

要函数调用成功用回一个整形正整数作为该在色器程序的id。
2) 绑定shader到program。
使用glAttachShader()将shader容器添加到程序中。这时的shader容器不自然得被编译,他们还无待包含其他的代码。
函数的原型如下:  

[cpp] view
plaincopy金博宝188bet 41金博宝188bet 42

 

  1. void glAttachShader (int program, int shader)   

参数含义: 

program:着色器程序容器的id。
shader:要加上的极或者片元shader容器的id。 

Vertex Shader和Fragment
Shader需要各自以她们各自的蝇头独shader容器添加的程序容器中。

3) 链接program。
运用glLinkProgram()链接程序对象。
函数的原型如下:  

[cpp] view
plaincopy金博宝188bet 43金博宝188bet 44

 

  1. void glLinkProgram (int program)   

program是在色器程序容器的id。
设另外项目也GL_VERTEX_SHADER的shader对象连接到program,它以发出于“顶点在色器”(Vertex
Shader)上但尽之次第;如果另外类型为GL_FRAGMENT_SHADER的shader对象连接到program,它用时有发生于“像从方色器”(Pixel
Shader)上可是实行之次序。
当链接阶段采取glGetProgramiv()获取编译情况。glGetProgramiv
()函数原型如下:

[cpp] view
plaincopy金博宝188bet 45金博宝188bet 46

 

  1. void glGetProgramiv (int program, int pname, int[] params, int offset)   

参数含义: 

program:一个着色器程序的id; 
pname:GL_LINK_STATUS; 
param:返回值,如果一切正常返回GL_TRUE代,否则回GL_FALSE。

经glBindAttribLocation()把“顶点属于性索引”绑定到“顶点属于性名”。

[cpp] view
plaincopy金博宝188bet 47金博宝188bet 48

 

  1. void glBindAttribLocation(GLuint program,GLuint index,const GLchar* name);  

参数含义:

program:着色器程序容器的id。
index:顶点属性索引。
name:顶点属性名。

4) 使用porgram。
于链接了序后,我们得用glUseProgram()函数来加载并使链接好的顺序。glUseProgram函数原型如下: 

[cpp] view
plaincopy金博宝188bet 49金博宝188bet 50

 

  1. void glUseProgram (int program)   

里program是只要采取的着色器程序的id。

(3) 初始化Texture

初始化Texture可以分为以下步骤。

1) 定义顶点数组

这无异步要初始化两只数组,

2) 设置极端数组

立即等同步通过glVertexAttribPointer()完成。glVertexAttribPointer()定义一个通用顶点属性数组。当渲染时,它指定了通用顶点属性数组从索引index处开始的职以及多少格式。
glVertexAttribPointer()原型如下。

[cpp] view
plaincopy金博宝188bet 51金博宝188bet 52

 

  1. void glVertexAttribPointer(    
  2.     GLuint   index,   
  3.     GLint   size,   
  4.     GLenum   type,   
  5.     GLboolean   normalized,   
  6.     GLsizei   stride,   
  7.     const GLvoid *   pointer);   

每个参数的意思:

index:指示以于修改的通用顶点属性之索引 
size:指点每个终端元素个数(1~4)  
type:数组中每个元素的数据类型 
normalized:指示一定数据值是否被归一化(归一化<[-1,1]或[0,1]>:GL_TRUE,直接利用:GL_FALSE)
 
stride:连续顶点属性间的偏移量,如果也0,相邻顶点属性间紧紧相邻 
pointer:顶点数组 

采取函数glEnableVertexAttribArray()启用属性数组。默认状态下,所有客户端的力为Disabled,包括所有通用顶点属性数组。如果吃Enable,通用顶点属性数组中的价值将被访并为用于Rendering。函数的原型如下:

[cpp] view
plaincopy金博宝188bet 53金博宝188bet 54

 

  1. void glEnableVertexAttribArray( GLuint   index);  

 

里面index用于指定通用顶点属性之目。

3) 初始化纹理

采取glGenTextures()初始化纹理,其原型如下。

[cpp] view
plaincopy金博宝188bet 55金博宝188bet 56

 

  1. glGenTextures(GLsizei n, GLuint *textures)   

参数含义:

n:用来特别成纹理的多少

textures:存储纹理索引的数组

 

glGenTextures()就是用来闹而如操作的纹理对象的目录的,比如您告知OpenGL,我索要5独纹理对象,它会打没有采用的整数里返回5只叫您。
有纹理索引之后,需要用glBindTexture()绑定纹理,才能够针对该纹理进行操作。glBindTexture()告诉OpenGL下面对纹理的其它操作都是对她所绑定的纹理对象的,比如glBindTexture(GL_TEXTURE_2D,1)即告OpenGL下面代码中对2D纹理的旁设置都是本着索引为1之纹路的。
glBindTexture()函数的宣示如下所示:

[cpp] view
plaincopy金博宝188bet 57金博宝188bet 58

 

  1. void glBindTexture(GLenum target, GLuint texture );  

函数参数的意思:

target:纹理被绑定的目标,它只能取值GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D或者GL_TEXTURE_CUBE_MAP。

texture:纹理的名目,并且,该纹理的名号在目前的应用中无克让再度行使。

 

绑定纹理之后,就可安装该纹理的组成部分特性了。
纹理过滤函数glTexParameteri()可以据此来确定哪些将图像于纹理图象空间映射到帧缓冲图象空间。即把纹理像素映射成像素。glTexParameteri()的原型如下。

[cpp] view
plaincopy金博宝188bet 59金博宝188bet 60

 

  1. void glTexParameteri(GLenum target,GLenum pname,GLint param);  

一对参数功能说明如下:

pname:参数。可以指定为GL_TEXTURE_MAG_FILTER(放大过滤),GL_TEXTURE_MIN_FILTER(缩小过滤)等。
param:参数的值。例如GL_LINEAR(线性插值。使用离时渲染像素中心近日的4只纹素加权平均值),GL_NEAREST(临近像素插值。该办法质量比较差)

 

6) 进入信息循环

glutMainLoop()将见面进入GLUT事件处理循环。一旦让调用,这个次用永久不会见回到。视频播放的时候,调用该函数之后便始播报视频。

 

2. 循环显示画面

1) 设置纹理

运用glActiveTexture()选择得由纹理函数进行修改的时纹理单位。后续的操作都是指向选择的纹理进行的。glActiveTexture()的原型如下。

[cpp] view
plaincopy金博宝188bet 61金博宝188bet 62

 

  1. void glActiveTexture(GLenum texUnit);  

跟着用glBindTexture()告诉OpenGL下面对纹理的另操作都是针对她所绑定的纹理对象的,这一点前文已经记录,不再另行。
然后运glTexImage2D()根据指定的参数,生成一个2D纹理(Texture)。相似的函数还有glTexImage1D、glTexImage3D。glTexImage2D()原型如下。

[cpp] view
plaincopy金博宝188bet 63金博宝188bet 64

 

  1. void glTexImage2D(  GLenum target,  
  2.     GLint level,  
  3.     GLint internalformat,  
  4.     GLsizei width,  
  5.     GLsizei height,  
  6.     GLint border,  
  7.     GLenum format,  
  8.     GLenum type,  
  9.     const GLvoid * data);  

参数说明如下:

target:指定目标纹理,这个价必须是GL_TEXTURE_2D。
level:执行细节级别。0凡极其核心的图像级别,n表示第N层贴图细化级别。
internalformat:指定纹理中的颜料格式。可卜的价有GL_ALPHA,GL_RGB,GL_RGBA,GL_LUMINANCE,
GL_LUMINANCE_ALPHA 等几种。
width:纹理图像的增长率。
height:纹理图像的莫大。
border:边框的宽窄。必须为0。
format:像素数据的颜料格式,
不需要以及internalformatt取值必须一律。可挑选的值参考internalformat。
type:指定像素数据的数据类型。可以行使的价值有GL_UNSIGNED_BYTE,GL_UNSIGNED_SHORT_5_6_5,GL_UNSIGNED_SHORT_4_4_4_4,GL_UNSIGNED_SHORT_5_5_5_1等。
pixels:指定内存中指向图像数据的指针

glUniform()为当下程序对象指定Uniform变量的价。(注意,由于OpenGL由C语言编写,但是C语言不支持函数的重载,所以会见生出过多名字如出一辙后缀不同之函数版本有。其中函数名为中含数字(1、2、3、4)表示接受该数字只用于更改uniform变量的价值,i表示32号整形,f表示32号浮点型,ub表示8各类无符号byte,ui表示32各项无符号整形,v表示接受相应的指针类型。

2) 绘制

使glDrawArrays()进行绘图。glDrawArrays()原型如下。

[cpp] view
plaincopy金博宝188bet 65金博宝188bet 66

 

  1. void glDrawArrays (GLenum mode, GLint first, GLsizei count);  

参数说明:

mode:绘制方式,提供以下参数:GL_POINTS、GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN。
first:从数组缓存中的呐一样位开绘制,一般为0。
count:数组中极的数量。

 

3) 显示

一旦利用“双缓冲”方式吧,使用glutSwapBuffers()绘制。如果运用“单缓冲”方式吧,使用glFlush()绘制。glutSwapBuffers()的效能是换成两单缓冲区指针,表现的花样就凡是管镜头展现到屏幕及。

简单解释一下双缓冲技术。当我们开展复杂的绘图操作时,画面就唯恐发明确的闪光。这是由绘制的物从来不同时出现在屏幕及一旦致使的。使用对缓冲可以缓解者问题。所谓双缓冲技术,
是指利用简单只缓冲区:
前台缓冲和后台缓冲。前台缓冲即我们看看底屏幕,后台缓冲则于内存当中,对我们吧是不可见的。每次的有绘图操作不是于屏幕及直接绘制,而是以后台缓冲中展开,
当绘制就时,再将绘制的末梢结果显示到屏幕上。

glutSwapBuffers()函数执行后,缓冲区指针交换,两个缓冲的“角色”也发了易。原先的前台缓冲变成了后高缓冲,等待进行下同样不善绘制。而原来的后台缓冲变成了前台缓冲,展现出绘制的结果。

 

视频显示(使用Texture)流程总结

上文流程的函数流程可以用生图表示。

 金博宝188bet 67

 

代码

源代码如下所示。

[cpp] view
plaincopy金博宝188bet 68金博宝188bet 69

 

  1. /** 
  2.  * 最简便易行的OpenGL播放视频的例证(OpenGL播放YUV)[Texture] 
  3.  * Simplest Video Play OpenGL (OpenGL play YUV) [Texture] 
  4.  * 
  5.  * 雷霄骅 Lei Xiaohua 
  6.  * leixiaohua1020@126.com 
  7.  * 中国传媒大学/数字电视技术 
  8.  * Communication University of China / Digital TV Technology 
  9.  * http://blog.csdn.net/leixiaohua1020 
  10.  * 
  11.  * 本程序下OpenGL播放YUV视频像素数据。本程序支持YUV420P之 
  12.  * 像素数据作输入,经过转换后输出及屏幕及。其中以了多种 
  13.  * 技术,例如Texture,Shader等,是一个针锋相对比较复杂的例证。 
  14.  * 适合有自然OpenGL基础的初家学习。 
  15.  * 
  16.  * 函数调用步骤如下:  
  17.  * 
  18.  * [初始化] 
  19.  * glutInit(): 初始化glut库。 
  20.  * glutInitDisplayMode(): 设置显示模式。 
  21.  * glutCreateWindow(): 创建一个窗口。 
  22.  * glewInit(): 初始化glew库。 
  23.  * glutDisplayFunc(): 设置绘图函数(重绘的上调用)。 
  24.  * glutTimerFunc(): 设置定时器。 
  25.  * InitShaders(): 设置Shader。包含了同样名目繁多函数,暂勿列出。 
  26.  * glutMainLoop(): 进入信息循环。 
  27.  * 
  28.  * [巡回渲染数据] 
  29.  * glActiveTexture(): 激活纹理单位。 
  30.  * glBindTexture(): 绑定纹理 
  31.  * glTexImage2D(): 根据像素数量,生成一个2D纹理。 
  32.  * glUniform1i():  
  33.  * glDrawArrays(): 绘制。 
  34.  * glutSwapBuffers(): 显示。 
  35.  * 
  36.  * This software plays YUV raw video data using OpenGL. 
  37.  * It support read YUV420P raw file and show it on the screen. 
  38.  * It's use a slightly more complex technologies such as Texture, 
  39.  * Shaders etc. Suitable for beginner who already has some  
  40.  * knowledge about OpenGL. 
  41.  * 
  42.  * The process is shown as follows: 
  43.  * 
  44.  * [Init] 
  45.  * glutInit(): Init glut library. 
  46.  * glutInitDisplayMode(): Set display mode. 
  47.  * glutCreateWindow(): Create a window. 
  48.  * glewInit(): Init glew library. 
  49.  * glutDisplayFunc(): Set the display callback. 
  50.  * glutTimerFunc(): Set timer. 
  51.  * InitShaders(): Set Shader, Init Texture. It contains some functions about Shader. 
  52.  * glutMainLoop(): Start message loop. 
  53.  * 
  54.  * [Loop to Render data] 
  55.  * glActiveTexture(): Active a Texture unit  
  56.  * glBindTexture(): Bind Texture 
  57.  * glTexImage2D(): Specify pixel data to generate 2D Texture 
  58.  * glUniform1i():  
  59.  * glDrawArrays(): draw. 
  60.  * glutSwapBuffers(): show. 
  61.  */  
  62.   
  63. #include <stdio.h>  
  64.   
  65. #include "glew.h"  
  66. #include "glut.h"  
  67.   
  68. #include <stdio.h>  
  69. #include <stdlib.h>  
  70. #include <malloc.h>  
  71. #include <string.h>  
  72.   
  73. //Select one of the Texture mode (Set '1'):  
  74. #define TEXTURE_DEFAULT   0  
  75. //Rotate the texture  
  76. #define TEXTURE_ROTATE    0  
  77. //Show half of the Texture  
  78. #define TEXTURE_HALF      1  
  79.   
  80. const int screen_w=500,screen_h=500;  
  81. const int pixel_w = 320, pixel_h = 180;  
  82. //YUV file  
  83. FILE *infile = NULL;  
  84. unsigned char buf[pixel_w*pixel_h*3/2];  
  85. unsigned char *plane[3];  
  86.   
  87.   
  88. GLuint p;                  
  89. GLuint id_y, id_u, id_v; // Texture id  
  90. GLuint textureUniformY, textureUniformU,textureUniformV;  
  91.   
  92.   
  93. #define ATTRIB_VERTEX 3  
  94. #define ATTRIB_TEXTURE 4  
  95.   
  96. void display(void){  
  97.     if (fread(buf, 1, pixel_w*pixel_h*3/2, infile) != pixel_w*pixel_h*3/2){  
  98.         // Loop  
  99.         fseek(infile, 0, SEEK_SET);  
  100.         fread(buf, 1, pixel_w*pixel_h*3/2, infile);  
  101.     }  
  102.     //Clear  
  103.     glClearColor(0.0,255,0.0,0.0);  
  104.     glClear(GL_COLOR_BUFFER_BIT);  
  105.     //Y  
  106.     //  
  107.     glActiveTexture(GL_TEXTURE0);  
  108.       
  109.     glBindTexture(GL_TEXTURE_2D, id_y);  
  110.       
  111.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[0]);   
  112.       
  113.     glUniform1i(textureUniformY, 0);      
  114.     //U  
  115.     glActiveTexture(GL_TEXTURE1);  
  116.     glBindTexture(GL_TEXTURE_2D, id_u);  
  117.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w/2, pixel_h/2, 0, GL_RED, GL_UNSIGNED_BYTE, plane[1]);         
  118.     glUniform1i(textureUniformU, 1);  
  119.     //V  
  120.     glActiveTexture(GL_TEXTURE2);  
  121.     glBindTexture(GL_TEXTURE_2D, id_v);  
  122.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w/2, pixel_h/2, 0, GL_RED, GL_UNSIGNED_BYTE, plane[2]);      
  123.     glUniform1i(textureUniformV, 2);     
  124.   
  125.     // Draw  
  126.     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  
  127.     // Show  
  128.     //Double  
  129.     glutSwapBuffers();  
  130.     //Single  
  131.     //glFlush();  
  132. }  
  133.   
  134. void timeFunc(int value){  
  135.     display();  
  136.     // Timer: 40ms  
  137.     glutTimerFunc(40, timeFunc, 0);  
  138. }  
  139.   
  140. char *textFileRead(char * filename)  
  141. {  
  142.     char *s = (char *)malloc(8000);  
  143.     memset(s, 0, 8000);  
  144.     FILE *infile = fopen(filename, "rb");  
  145.     int len = fread(s, 1, 8000, infile);  
  146.     fclose(infile);  
  147.     s[len] = 0;  
  148.     return s;  
  149. }  
  150.   
  151. //Init Shader  
  152. void InitShaders()  
  153. {  
  154.     GLint vertCompiled, fragCompiled, linked;  
  155.       
  156.     GLint v, f;  
  157.     const char *vs,*fs;  
  158.     //Shader: step1  
  159.     v = glCreateShader(GL_VERTEX_SHADER);  
  160.     f = glCreateShader(GL_FRAGMENT_SHADER);  
  161.     //Get source code  
  162.     vs = textFileRead("Shader.vsh");  
  163.     fs = textFileRead("Shader.fsh");  
  164.     //Shader: step2  
  165.     glShaderSource(v, 1, &vs,NULL);  
  166.     glShaderSource(f, 1, &fs,NULL);  
  167.     //Shader: step3  
  168.     glCompileShader(v);  
  169.     //Debug  
  170.     glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);  
  171.     glCompileShader(f);  
  172.     glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);  
  173.   
  174.     //Program: Step1  
  175.     p = glCreateProgram();   
  176.     //Program: Step2  
  177.     glAttachShader(p,v);  
  178.     glAttachShader(p,f);   
  179.   
  180.     glBindAttribLocation(p, ATTRIB_VERTEX, "vertexIn");  
  181.     glBindAttribLocation(p, ATTRIB_TEXTURE, "textureIn");  
  182.     //Program: Step3  
  183.     glLinkProgram(p);  
  184.     //Debug  
  185.     glGetProgramiv(p, GL_LINK_STATUS, &linked);    
  186.     //Program: Step4  
  187.     glUseProgram(p);  
  188.   
  189.   
  190.     //Get Uniform Variables Location  
  191.     textureUniformY = glGetUniformLocation(p, "tex_y");  
  192.     textureUniformU = glGetUniformLocation(p, "tex_u");  
  193.     textureUniformV = glGetUniformLocation(p, "tex_v");   
  194.   
  195. #if TEXTURE_ROTATE  
  196.     static const GLfloat vertexVertices[] = {  
  197.         -1.0f, -0.5f,  
  198.          0.5f, -1.0f,  
  199.         -0.5f,  1.0f,  
  200.          1.0f,  0.5f,  
  201.     };      
  202. #else  
  203.     static const GLfloat vertexVertices[] = {  
  204.         -1.0f, -1.0f,  
  205.         1.0f, -1.0f,  
  206.         -1.0f,  1.0f,  
  207.         1.0f,  1.0f,  
  208.     };      
  209. #endif  
  210.   
  211. #if TEXTURE_HALF  
  212.     static const GLfloat textureVertices[] = {  
  213.         0.0f,  1.0f,  
  214.         0.5f,  1.0f,  
  215.         0.0f,  0.0f,  
  216.         0.5f,  0.0f,  
  217.     };   
  218. #else  
  219.     static const GLfloat textureVertices[] = {  
  220.         0.0f,  1.0f,  
  221.         1.0f,  1.0f,  
  222.         0.0f,  0.0f,  
  223.         1.0f,  0.0f,  
  224.     };   
  225. #endif  
  226.     //Set Arrays  
  227.     glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);  
  228.     //Enable it  
  229.     glEnableVertexAttribArray(ATTRIB_VERTEX);      
  230.     glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);  
  231.     glEnableVertexAttribArray(ATTRIB_TEXTURE);  
  232.   
  233.   
  234.     //Init Texture  
  235.     glGenTextures(1, &id_y);   
  236.     glBindTexture(GL_TEXTURE_2D, id_y);      
  237.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);  
  238.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);  
  239.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  240.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  241.       
  242.     glGenTextures(1, &id_u);  
  243.     glBindTexture(GL_TEXTURE_2D, id_u);     
  244.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);  
  245.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);  
  246.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  247.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  248.       
  249.     glGenTextures(1, &id_v);   
  250.     glBindTexture(GL_TEXTURE_2D, id_v);      
  251.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);  
  252.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);  
  253.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  254.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  255.   
  256. }  
  257.   
  258.   
  259.   
  260. int main(int argc, char* argv[])  
  261. {  
  262.     //Open YUV420P file  
  263.     if((infile=fopen("../test_yuv420p_320x180.yuv", "rb"))==NULL){  
  264.         printf("cannot open this file\n");  
  265.         return -1;  
  266.     }  
  267.   
  268.     //YUV Data  
  269.     plane[0] = buf;  
  270.     plane[1] = plane[0] + pixel_w*pixel_h;  
  271.     plane[2] = plane[1] + pixel_w*pixel_h/4;  
  272.   
  273.     //Init GLUT  
  274.     glutInit(&argc, argv);    
  275.     //GLUT_DOUBLE  
  276.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);  
  277.     glutInitWindowPosition(100, 100);  
  278.     glutInitWindowSize(screen_w, screen_h);  
  279.     glutCreateWindow("Simplest Video Play OpenGL (Texture)");  
  280.     printf("Lei Xiaohua\n");  
  281.     printf("http://blog.csdn.net/leixiaohua1020\\n");  
  282.     printf("Version: %s\n", glGetString(GL_VERSION));  
  283.     GLenum l = glewInit();  
  284.   
  285.     glutDisplayFunc(&display);  
  286.     glutTimerFunc(40, timeFunc, 0);   
  287.   
  288.     InitShaders();  
  289.   
  290.     // Begin!  
  291.     glutMainLoop();  
  292.   
  293.     return 0;  
  294. }  

 

 

Shader.vsh

[plain] view
plaincopy金博宝188bet 70金博宝188bet 71

 

  1. attribute vec4 vertexIn;   
  2. attribute vec2 textureIn;  
  3. varying vec2 textureOut;  
  4. void main(void)  
  5. {  
  6.     gl_Position = vertexIn;   
  7.     textureOut = textureIn;  
  8. }  

Shader.fsh

[plain] view
plaincopy金博宝188bet 72金博宝188bet 73

 

  1. varying vec2 textureOut;  
  2. uniform sampler2D tex_y;  
  3. uniform sampler2D tex_u;  
  4. uniform sampler2D tex_v;  
  5. void main(void)  
  6. {  
  7.     vec3 yuv;  
  8.     vec3 rgb;      
  9.     yuv.x = texture2D(tex_y, textureOut).r;  
  10.     yuv.y = texture2D(tex_u, textureOut).r - 0.5;  
  11.     yuv.z = texture2D(tex_v, textureOut).r - 0.5;  
  12.     rgb = mat3( 1,       1,         1,  
  13.                 0,       -0.39465,  2.03211,  
  14.                 1.13983, -0.58060,  0) * yuv;      
  15.     gl_FragColor = vec4(rgb, 1);  
  16. }  

 

代码注意事项

  1. 眼前支撑读取YUV420P格式的像素数量。

2.
窗口的丰厚高哉screen_w,screen_h。像素数据的充盈高呢pixel_w,pixel_h。它们的定义如下。

[cpp] view
plaincopy金博宝188bet 74金博宝188bet 75

 

  1. //Width, Height      
  2. const int screen_w=500,screen_h=500;      
  3. const int pixel_w=320,pixel_h=180;      
  1. 经过代码前面的大,可以选几栽不同的纹路映射方式

[cpp] view
plaincopy金博宝188bet 76金博宝188bet 77

 

  1. //Select one of the Texture mode (Set '1'):    
  2. #define TEXTURE_DEFAULT 1    
  3. //Rotate the texture    
  4. #define TEXTURE_ROTATE  0    
  5. //Show half of the Texture    
  6. #define TEXTURE_HALF    0    

先是种植是常规的照耀方式,第二栽是“旋转”的方法,第三种是单纯照一半底办法。

结果

程序运行结果如下。默认的纹路映射:

金博宝188bet 78

“旋转”:

金博宝188bet 79

一半纹理:

金博宝188bet 80

 

下载

代码位于“Simplest Media Play”中

SourceForge项目地址:https://sourceforge.net/projects/simplestmediaplay/
CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/8054395

上述工程包含了用各种API(Direct3D,OpenGL,GDI,DirectSound,SDL2)播放多媒体例子。其中音频输入为PCM采样数据。输出到系统的声卡播放出来。视频输入为YUV/RGB像素数据。输出到显示器上之一个窗口播放出来。
经过本工程的代码初家可以长足学习使用即时几乎独API播放视频以及板的技能。
共包括了之类几独子工程:
simplest_audio_play_directsound: 
使用DirectSound播放PCM音频采样数据。
simplest_audio_play_sdl2:  使用SDL2播放PCM音频采样数据。
simplest_video_play_direct3d: 
使用Direct3D的Surface播放RGB/YUV视频像素数据。
simplest_video_play_direct3d_texture:
使用Direct3D的Texture播放RGB视频像素数据。
simplest_video_play_gdi:  使用GDI播放RGB/YUV视频像素数据。
simplest_video_play_opengl:  使用OpenGL播放RGB/YUV视频像素数据。
simplest_video_play_opengl_texture:
使用OpenGL的Texture播放YUV视频像素数据。
simplest_video_play_sdl2:  使用SDL2播放RGB/YUV视频像素数据。

 

from:http://blog.csdn.net/leixiaohua1020/article/details/40379845

相关文章

Comment ()
评论是一种美德,说点什么吧,否则我会恨你的。。。