OpenGL播放yuv数据流(着色器SHADER)-IOS(一).doc_第1页
OpenGL播放yuv数据流(着色器SHADER)-IOS(一).doc_第2页
OpenGL播放yuv数据流(着色器SHADER)-IOS(一).doc_第3页
OpenGL播放yuv数据流(着色器SHADER)-IOS(一).doc_第4页
OpenGL播放yuv数据流(着色器SHADER)-IOS(一).doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

OpenGL播放yuv数据流(着色器SHADER)-IOS(一)和windows平台的类似,只是用object-c编写的,着色器语言shader,rgb转yuv有些不同,具体看代码注释。/.hcpp view plain copy 在CODE上查看代码片派生到我的代码片/* Copyright (c/c+) * Function * Opanal for video rendering related implementation and definition, etc. * OpanAl 用于视频渲染相关实现及定义,等 */ #ifndef _LVS_OPENGL_INTERFACE_H_ #define _LVS_OPENGL_INTERFACE_H_ #include #import #import #import #import #import #include #include #include #include /着色器用的顶点属性索引 position是由3个(x,y,z)组成, #define ATTRIB_VERTEX 3 /着色器用的像素,纹理属性索引 而颜色是4个(r,g,b,a) #define ATTRIB_TEXTURE 4 /是否旋转图像(纹理) #define TEXTURE_ROTATE 0 /显示图像(纹理)的一半 #define TEXTURE_HALF 0 /shader源码用的宏 #define STRINGIZE(x) #x #define STRINGIZE2(x) STRINGIZE(x) #define SHADER_STRING(text) STRINGIZE2(text) /shader的vsh源码字符串 /* static NSString *const vertexShaderString = SHADER_STRING( attribute vec4 position; attribute vec2 TexCoordIn; varying vec2 TexCoordOut; void main(void) gl_Position = position; TexCoordOut = TexCoordIn; ); */ static NSString *const vertexShaderString = SHADER_STRING( attribute vec4 vertexIn; attribute vec2 textureIn; varying vec2 textureOut; void main(void) gl_Position = vertexIn; textureOut = textureIn; ); /shader的fsh源码字符串 static NSString *const yuvFragmentShaderString = SHADER_STRING( varying lowp vec2 textureOut; uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) mediump vec3 yuv; lowp vec3 rgb; yuv.x = texture2D(tex_y, textureOut).r; yuv.y = texture2D(tex_u, textureOut).r - 0.5; yuv.z = texture2D(tex_v, textureOut).r - 0.5; rgb = mat3(1,1,1,0,-0.39465,2.03211,1.13983, -0.58060, 0) * yuv; gl_FragColor = vec4(rgb, 1); ); /* static NSString *const yuvFragmentShaderString = SHADER_STRING( varying vec2 textureOut; uniform sampler2D tex_y; uniform sampler2D tex_u; uniform sampler2D tex_v; void main(void) vec3 yuv; vec3 rgb; yuv.x = texture2D(tex_y, textureOut).r; yuv.y = texture2D(tex_u, textureOut).r - 0.5; yuv.z = texture2D(tex_v, textureOut).r - 0.5; rgb = mat3( 1, 1, 1, 0, -0.39465, 2.03211, 1.13983, -0.58060, 0) * yuv; gl_FragColor = vec4(rgb, 1); ); */ /回调读取数据函数指针,数据及时间戳 typedef int (*DisplayDataCK)(void * data,int * timer_millis); /接口初始化 int lvs_opengl_interface_init(int yuvdata_width,int yuvdata_height, DisplayDataCK displaydatack,void* pview); /接口释放 void lvs_opengl_interface_uninit(); /接口渲染数据(定时器,渲染时间,毫秒),数据及渲染定时时间在回调里面做处理 void lvs_opengl_interface_write(int value); /渲染数据(定时器,渲染时间,毫秒),数据及渲染定时时间在回调里面做处理 void TimerFunc1(int value); /这里如果有可能则调成类的成员函数,以后处理,暂时不知道怎么解决类成员函数递归? interface OpenGL_Display_Interface : UIView public EAGLContext *m_eaglContext; /opengl的view用的context,用于OpenGL 的窗口和ios的view窗口关联,很重要 DisplayDataCK m_displaydatack; /用于显示回调函数,参数数据及时间戳 char * m_yuvbuf; /存放yuv数据的buf指针,申请buffer在外面 int m_millis_realtime; /实时的时间戳,每次回调会更新 int m_yuvdata_width; /数据宽 int m_yuvdata_height; /数据高 private GLuint m_frameBuffer; /framebuffer GLuint m_renderBuffer; /renderbuffer GLuint m_textureid_y, m_textureid_u, m_textureid_v; /纹理的名称,并且,该纹理的名称在当前的应用中不能被再次使用。 GLuint m_textureUniformY, m_textureUniformU,m_textureUniformV; /用于纹理渲染的变量 /创建用于显示的buffer - (int)createFrameAndRenderBuffer; /删除用于显示的buffer - (void)destoryFrameAndRenderBuffer; /初始化 - (int)initopengl: (int)yuvdata_width andyuvdata_height: (int)yuvdata_height anddisplaycallback: (DisplayDataCK)displaydatack; /初始化着色器,类似于告GPU当传进去数据的时候采用什么样的规则。 - (void)InitShaders; /具体显示图像的函数 - (int)DisplayImage: (void*)parm; end; #endif /.mmcpp view plain copy 在CODE上查看代码片派生到我的代码片/ / Lvs_OpenGl_Interface_Ios.cpp / LvsIos_Play / / Created by mx on 2016/12/7. / Copyright 2016年 lvs. All rights reserved. / #include Lvs_OpenGl_Interface_Ios.h static OpenGL_Display_Interface * copengl_interface = NULL; int lvs_opengl_interface_init(int yuvdata_width,int yuvdata_height, DisplayDataCK displaydatack,void* pview) int ret = 0; printf(lvs_opengl_interface_initn); UIImageView * ppview = (UIImageView*)pview; if (copengl_interface = NULL) copengl_interface = OpenGL_Display_Interface allocinitWithFrame:CGRectMake(0, 0, ppview.frame.size.width, ppview.frame.size.height); ppview addSubview:copengl_interface; /初始化 ret =copengl_interface initopengl:yuvdata_width andyuvdata_height: yuvdata_height anddisplaycallback: displaydatack; if (ret != 1) return -1; /初始化着色器,类似于告GPU当传进去数据的时候采用什么样的规则。 copengl_interface InitShaders; ret = 1; return ret; void lvs_opengl_interface_uninit() printf(lvs_opengl_interface_uninitn); if(copengl_interface != NULL) copengl_interface destoryFrameAndRenderBuffer; copengl_interface release; copengl_interface = NULL; return ; void lvs_opengl_interface_write(int value) /这里如果有可能则调成类的成员函数,以后处理,暂时不知道怎么解决类成员函数递归 TimerFunc1(value); void TimerFunc1(int value) int ret = 0; /因为glut的定时器是调用一次才产生一次定时,所以如果要持续产生定时的话, /在定时函数末尾再次调用glutTimerFunc /这里如果有可能则调成类的成员函数,以后处理,暂时不知道怎么解决类成员函数递归 /调用回调函数获取数据 ret= copengl_interface-m_displaydatack(void *)&copengl_interface-m_yuvbuf,&copengl_interface-m_millis_realtime); if (et 0) /这里做具体的处理 copengl_interface DisplayImage: (NULL); struct timeval delay; delay.tv_sec = 0; delay.tv_usec = copengl_interface-m_millis_realtime* 1000; select(0, NULL, NULL, NULL, &delay); else struct timeval delay; delay.tv_sec = 0; delay.tv_usec = 1* 1000; / 1 ms select(0, NULL, NULL, NULL, &delay); /释放yuv队列的节点buffer if (copengl_interface-m_yuvbuf != NULL) free(copengl_interface-m_yuvbuf); copengl_interface-m_yuvbuf = NULL; /递归调用自身 TimerFunc1(0); implementation OpenGL_Display_Interface /设置layer class 为 CAEAGLLayer 想要显示OpenGL的内容,你需要把它缺省的layer设置为一个特殊的layer。(CAEAGLLayer)。这里通过直接复写layerClass的方法。 + (Class)layerClass return CAEAGLLayer class; /用于view初始化时候设置宽高(系统自带函数,重写) - (id)initWithFrame:(CGRect)frame int ret = 0; if (self = super initWithFrame:frame) /oepngl变量 CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer; /设置layer为不透明(Opaque) eaglLayer.opaque = YES; /填写渲染所需的参数 eaglLayer.drawableProperties = NSDictionary dictionaryWithObjectsAndKeys: NSNumber numberWithBool:NO, kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, /NSNumber numberWithBool:YES, kEAGLDrawablePropertyRetainedBacking, nil; m_eaglContext = EAGLContext alloc initWithAPI:kEAGLRenderingAPIOpenGLES2; /使用2.0版初始化EAGLContext if(!m_eaglContext | !EAGLContext setCurrentContext:m_eaglContext) return NULL; /调用glViewPort函数来决定视见区域,告诉OpenGL应把渲染之后的图形绘制在窗体的哪个部位。当视见区域是整个窗体时,OpenGL将把渲染结果绘制到整个窗口。 /glViewport(0, 0,frame.size.width,frame.size.height);/定义视口大小,说白了就是OpenGL ES窗口大小 /UIScreen main scale = 1; /代表320 x 480 的分辨率UIScreen main scale = 2; /代表640 x 960 的分辨率UIScreen main scale = 3; /代表1242 x 2208 的分辨率 self.contentScaleFactor = UIScreen mainScreen.scale; glViewport(0, 0, frame.size.width * self.contentScaleFactor ,frame.size.height * self.contentScaleFactor); /这里不清楚为什么要乘以分辨率 return self; - (int)createFrameAndRenderBuffer glGenFramebuffers(1, &m_frameBuffer); /创建一个帧染缓冲区对象 glGenRenderbuffers(1, &m_renderBuffer); /创建一个渲染缓冲区对象 glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer); /将该帧染缓冲区对象绑定到管线上 glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer); /将该渲染缓冲区对象绑定到管线上 if (!m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer) NSLog(attach渲染缓冲区失败); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderBuffer); /将创建的渲染缓冲区绑定到帧缓冲区上,并使用颜色填充 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) NSLog(创建缓冲区错误 0x%x, glCheckFramebufferStatus(GL_FRAMEBUFFER); return 0; return 1; - (void)destoryFrameAndRenderBuffer if (m_frameBuffer) glDeleteFramebuffers(1, &m_frameBuffer); if (m_renderBuffer) glDeleteRenderbuffers(1, &m_renderBuffer); m_frameBuffer = 0; m_renderBuffer = 0; - (int)initopengl: (int)yuvdata_width andyuvdata_height: (int)yuvdata_height anddisplaycallback: (DisplayDataCK)playdatack int ret = 0; m_yuvdata_width = yuvdata_width; m_yuvdata_height = yuvdata_height; m_displaydatack = displaydatack; self createFrameAndRenderBuffer; return 1; - (void)InitShaders GLint vertCompiled, fragCompiled; /调试 shader的返回值,如果一切正常返回GL_TRUE代,否则返回GL_FALSE。 GLuint p; /Program着色器程序的id GLint linked; /调试 param的返回值,如果一切正常返回GL_TRUE代,否则返回GL_FALSE。 GLint v, f; /shader的id; char vs1024 *10 = 0; /shader源码的字串vsh 是Vertex Shader(顶点着色器) char fs1024 *10 = 0; /shader源码的字串fsh 是Fragment Shader(片元着色器) const char * vs_buf = vs; const char * fs_buf = fs; /shader的处理类似于将OpenGL Shader Language,简称GLSL的源码编译成2进制程序 /“vsh负责搞定像素位置,填写gl_Posizion;fsh负责搞定像素外观,填写 gl_FragColor。” /Shader: step1 创建两个shader 实例。 v = glCreateShader(GL_VERTEX_SHADER); f = glCreateShader(GL_FRAGMENT_SHADER); /着色器源码 /penGL的着色器有.fsh和.vsh两个文件。这两个文件在被编译和链接后就可以产生可执行程序与GPU交互。 /shader.vsh 是Vertex Shader(顶点着色器),用于顶点计算,可以理解控制顶点的位置,在这个文件中我们通常会传入当前顶点的位置,和纹理的坐标。 /shader.fsh 是Fragment Shader(片源着色器),在这里面我可以对于每一个像素点进行重新计算。 /将Vertex Shader和Fragment Shader源码读取到字符串中。 sprintf(vs,%s,vertexShaderString UTF8String); sprintf(fs,%s,yuvFragmentShaderString UTF8String); /Shader: step2 给Shader实例指定源码。 glShaderSource(v, 1, &vs_buf,NULL); glShaderSource(f, 1, &fs_buf,NULL); /Shader: step3 在线编译Shader源码。 glCompileShader(v); /Shader: step4 调试一个Shader /void glGetShaderiv( GLuint shader,GLenum pname,GLint *params); /params:返回值,如果一切正常返回GL_TRUE代,否则返回GL_FALSE。 glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled); if (vertCompiled = GL_FALSE) GLchar messages256; glGetShaderInfoLog(v, sizeof(messages), 0, &messages0); NSString *messageString = NSString stringWithUTF8String:messages; NSLog(vertCompiled : %, messageString); return; glCompileShader(f); glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled); if (fragCompiled = GL_FALSE) GLchar messages256; glGetShaderInfoLog(f, sizeof(messages), 0, &messages0); NSString *messageString = NSString stringWithUTF8String:messages; NSLog(fragCompiled : %, messageString); return; /Program有点类似于一个程序的链接器。program对象提供了把需要做的事连接在一起的机制。在一个program中,shader对象可以连接在一起。 /Program 这个类似于运行OpenGL Shader Language,简称GLSL的源码编译成2进制程序的执行环境,链接器 /Program: Step1 创建program p = glCreateProgram(); /Program: Step2 绑定shader到program glAttachShader(p,v); glAttachShader(p,f); /通过glBindAttribLocation()把“顶点属性索引”绑定到“顶点属性名” glBindAttribLocation(p, ATTRIB_VERTEX, vertexIn); /通过glBindAttribLocation()把“像素纹理属性索引”绑定到“像素纹理属性名” glBindAttribLocation(p, ATTRIB_TEXTURE, textureIn); /Program: Sep3 链接program glLinkProgram(p); /void glGetProgramiv (int program, int pname, int params, int offset) /参数含义: / program:一个着色器程序的id; / pname:GL_LINK_STATUS; / param:返回值,如果一切正常返回GL_TRUE代,否则返回GL_FALSE。 glGetProgramiv(p, GL_LINK_STATUS, &linked); /Program: Step4 在链接了程序以后,我们可以使用glUseProgram()函数来加载并使用链接好的程序 glUseProgram(p); /获取片源着色器源码中的变量,用于纹理渲染 m_textureUniformY = glGetUniformLocation(p, tex_y); m_textureUniformU = glGetUniformLocation(p, tex_u); m_textureUniformV = glGetUniformLocation(p, tex_v); /顶点数组(物体表面坐标取值范围是-1到1,数组坐标:左下,右下,左上,右上) #if TEXTURE_ROTATE static const GLfloat vertexVertices = -1.0f, -0.5f, 0.5f, -1.0f, -0.5f, 1.0f, 1.0f, 0.5f, ; #else static const GLfloat vertexVertices = -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, ; #endif /像素,纹理数组(纹理坐标取值范围是0-1,坐标原点位于左下角,数组坐标:左上,右上,左下,右下,如果先左下,图像会倒过来) #if TEXTURE_HALF static const GLfloat textureVertices = 0.0f, 1.0f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, ; #else static const GLfloat textureVertices = 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, ; #endif /定义顶点数组 glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices); /启用属性数组 glEnableVertexAttribArray(ATTRIB_VERTEX); /定义像素纹理数组 glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices); /启用属性数组 glEnableVertexAttribArray(ATTRIB_TEXTURE); /初始化纹理 glGenTextures(1, &m_textureid_y); /绑定纹理 glBindTexture(GL_TEXTURE_2D, m_textureid_y); /设置该纹理的一些属性 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenTextures(1, &m_textureid_u); glBindTexture(GL_TEXTURE_2D, m_textureid_u); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenTextures(1, &m_textureid_v); glBindTexture(GL_TEXTURE_2D, m_textureid_v); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - (int)DisplayImage: (void*)parm int ret = 0; unsigned char * yuvplaner3 = 0; /存放yuv数据的分量数组(y,u,v) /关联到yuv数据的分量数组 yuvplaner0 = (unsigned char *)m_yuvbuf; yuvplaner1 = yu

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论