这段时间一直在搞视频格式的转换问题,终于最近将一个图片的YUV格式转RGB格式转换成功了。下面就来介绍一下:

由于我的工程是在vs2008中的,其中包含一些相关头文件和库,所以下面只是列出部分核心代码,并不是全部代码。


1、下载一个包含YUV数据的文件也可以自己制作一个该文件

下载地址:YUV数据文件

2、读入YUV数据文件中的yuv数据:

关键代码如下:

2.1读文件代码

unsigned char * readYUV(char *path)
{ FILE *fp;
unsigned char * buffer;
long size = 1280 * 720 * 3 / 2; if((fp=fopen(path,"rb"))==NULL)
{
printf("cant open the file");
exit(0);
} buffer = new unsigned char[size];
memset(buffer,'\0',size);
fread(buffer,size,1,fp);
fclose(fp);
return buffer;
}

2.2读入数据,并将YUV数据分别制作成3个纹理

GLuint texYId;
GLuint texUId;
GLuint texVId; void loadYUV(){
int width ;
int height ; width = 640;
height = 480; unsigned char *buffer = NULL;
buffer = readYUV("1.yuv"); glGenTextures ( 1, &texYId );
glBindTexture ( GL_TEXTURE_2D, texYId );
glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_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, &texUId );
glBindTexture ( GL_TEXTURE_2D, texUId );
glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, width / 2, height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer + width * height);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_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, &texVId );
glBindTexture ( GL_TEXTURE_2D, texVId );
glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, width / 2, height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer + width * height * 5 / 4 );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_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 ); }

上述代码中1.yuv就是YUV数据文件

3、将纹理传入

上述片段shader中就是根据yuv转rgb的公式得来的。也就是说是在shader中实现转换的。
3.1 顶点shader和片段shader代码
GLbyte vShaderStr[] =
"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"; GLbyte fShaderStr[] =
  "precision mediump float;                      \n"
"uniform sampler2D tex_y; \n"
"uniform sampler2D tex_u; \n"
"uniform sampler2D tex_v; \n"
"varying vec2 tc; \n"
"void main() \n"
"{ \n"
" vec4 c = vec4((texture2D(tex_y, tc).r - 16./255.) * 1.164);\n"
" vec4 U = vec4(texture2D(tex_u, tc).r - 128./255.);\n"
" vec4 V = vec4(texture2D(tex_v, tc).r - 128./255.);\n"
" c += V * vec4(1.596, -0.813, 0, 0);\n"
" c += U * vec4(0, -0.392, 2.017, 0);\n"
" c.a = 1.0;\n"
" gl_FragColor = c;\n"
"} \n";
上述片段shader中就是根据yuv转rgb的公式得来的。也就是说是在shader中实现转换的。

4、显示结果

结果如下:

注意:该shader是OpenGL格式的shader有一点差别。

--------------------------------------------------------------------------------------------------------------------------------

YV12格式与YUV格式只是在UV的存储位置上不同,需要注意一下

YV12,I420,YUV420P的区别

YV12和I420的区别
一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3 Byte,RGB32的size=width×heigth×4,如果是I420(即YUV标准格式4:2:0)的数据量是 size=width×heigth×1.5 Byte。
在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB2YUV。因为,X264在进行编码的时候需要标准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。如下:
YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
可以看出,YV12和I420基本上是一样的,就是UV的顺序不同。
继续我们的话题,经过第一次数据压缩后RGB24->YUV(I420)。这样,数据量将减少一半,为什么呢?呵呵,这个就太基础了,我就不多写了。同样,如果是RGB24->YUV(YV12),也是减少一半。但是,虽然都是一半,如果是YV12的话效果就有很大损失。然后,经过X264编码后,数据量将大大减少。将编码后的数据打包,通过RTP实时传送。到达目的地后,将数据取出,进行解码。完成解码后,数据仍然是YUV格式的,所以,还需要一次转换,这样windows的驱动才可以处理,就是YUV2RGB24。

补充=============
详细的格式之间的差异可以参考:
 
附一个YUV播放器的源代码:http://download.csdn.net/detail/leixiaohua1020/6374065
查看YUV的时候也可以下载使用成熟的YUV播放器 ——YUV Player Deluxe:http://www.yuvplayer.com/
 

yuv420p就是I420格式,使用极其广泛,它的示意图:

 

【图像-视频处理】YUV420、YV12与RGB24的转换公式

    1. bool YV12ToBGR24_Native(unsigned char* pYUV,unsigned char* pBGR24,int width,int height)
    2. {
    3. if (width < 1 || height < 1 || pYUV == NULL || pBGR24 == NULL)
    4. return false;
    5. const long len = width * height;
    6. unsigned char* yData = pYUV;
    7. unsigned char* vData = &yData[len];
    8. unsigned char* uData = &vData[len >> 2];
    9. int bgr[3];
    10. int yIdx,uIdx,vIdx,idx;
    11. for (int i = 0;i < height;i++){
    12. for (int j = 0;j < width;j++){
    13. yIdx = i * width + j;
    14. vIdx = (i/2) * (width/2) + (j/2);
    15. uIdx = vIdx;
    16. bgr[0] = (int)(yData[yIdx] + 1.732446 * (uData[vIdx] - 128));                                    // b分量
    17. bgr[1] = (int)(yData[yIdx] - 0.698001 * (uData[uIdx] - 128) - 0.703125 * (vData[vIdx] - 128));    // g分量
    18. bgr[2] = (int)(yData[yIdx] + 1.370705 * (vData[uIdx] - 128));                                    // r分量
    19. for (int k = 0;k < 3;k++){
    20. idx = (i * width + j) * 3 + k;
    21. if(bgr[k] >= 0 && bgr[k] <= 255)
    22. pBGR24[idx] = bgr[k];
    23. else
    24. pBGR24[idx] = (bgr[k] < 0)?0:255;
    25. }
    26. }
    27. }
    28. return true;
    29. }

以上是yv12到RGB24的转换算法,如果是yuv420到RGB24转换,秩序u,v反过来就可以了。

即:

  1. unsigned char* uData = &yData[nYLen];
  2. unsigned char* vData = &vData[nYLen>>2];
 注:海康威视网络摄像头一般就是yu12格式的!

2016-9-22 19:53

张朋艺 pyZhangBIT2010@126.com

找到的英文参考资料:

yv12 to rgb using glsl in iOS ,result image attached

https://stackoverflow.com/questions/11093061/yv12-to-rgb-using-glsl-in-ios-result-image-attached

following is my code for uploading the three planar data to textures:
- (GLuint) textureY: (Byte*)imageData
widthType: (int) width
heightType: (int) height
{
GLuint texName;
glGenTextures( 1, &texName );
glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_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); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData );
//free(imageData); return texName;
} - (GLuint) textureU: (Byte*)imageData
widthType: (int) width
heightType: (int) height
{
GLuint texName; glGenTextures( 1, &texName );
glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_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); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData);
return texName;
} - (GLuint) textureV: (Byte*)imageData
widthType: (int) width
heightType: (int) height
{
GLuint texName;
glGenTextures( 1, &texName );
glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_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); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData);
return texName;
} - (void) readYUVFile
{
NSString *file = [[NSBundle mainBundle] pathForResource:@"video" ofType:@"yv12"];
NSLog(@"%@",file);
NSData* fileData = [NSData dataWithContentsOfFile:file];
//NSLog(@"%@",[fileData description]);
NSInteger width = 352;
NSInteger height = 288;
NSInteger uv_width = width / 2;
NSInteger uv_height = height / 2;
NSInteger dataSize = [fileData length];
NSLog(@"%i\n",dataSize); GLint nYsize = width * height;
GLint nUVsize = uv_width * uv_height;
GLint nCbOffSet = nYsize;
GLint nCrOffSet = nCbOffSet + nUVsize; Byte *spriteData = (Byte *)malloc(dataSize);
[fileData getBytes:spriteData length:dataSize]; Byte* uData = spriteData + nCbOffSet;
//NSLog(@"%@\n",[[NSData dataWithBytes:uData length:nUVsize] description]);
Byte* vData = spriteData + nCrOffSet;
//NSLog(@"%@\n",[[NSData dataWithBytes:vData length:nUVsize] description]);
/**
Byte *YPlanarData = (Byte *)malloc(nYsize);
for (int i=0; i<nYsize; i++) {
YPlanarData[i]= spriteData[i];
} Byte *UPlanarData = (Byte *)malloc(nYsize);
for (int i=0; i<height; i++) {
for (int j=0; j<width; j++) {
int numInUVsize = (i/2)*uv_width+j/2;
UPlanarData[i*width+j]=uData[numInUVsize];
}
} Byte *VPlanarData = (Byte *)malloc(nYsize);
for (int i=0; i<height; i++) {
for (int j=0; j<width; j++) {
int numInUVsize = (i/2)*uv_width+j/2;
VPlanarData[i*width+j]=vData[numInUVsize];
}
}
**/ _textureUniformY = glGetUniformLocation(programHandle, "SamplerY");
_textureUniformU = glGetUniformLocation(programHandle, "SamplerU");
_textureUniformV = glGetUniformLocation(programHandle, "SamplerV");
free(spriteData); }

and my fragment shaders code:

   precision highp float;
uniform sampler2D SamplerY;
uniform sampler2D SamplerU;
uniform sampler2D SamplerV; varying highp vec2 coordinate; void main()
{
highp vec3 yuv,yuv1;
highp vec3 rgb; yuv.x = texture2D(SamplerY, coordinate).r; yuv.y = texture2D(SamplerU, coordinate).r-0.5; yuv.z = texture2D(SamplerV, coordinate).r-0.5 ; rgb = mat3( 1, 1, 1,
0, -.34414, 1.772,
1.402, -.71414, 0) * yuv; gl_FragColor = vec4(rgb, 1);
}
 

【OpenGL】用OpenGL shader实现将YUV(YUV420,YV12)转RGB-(直接调用GPU实现,纯硬件方式,效率高)的更多相关文章

  1. OpenGL 和OpenGL ES简介

    OpenGL的全称是Open  Graphics  Library,即开放的图形库接口,它定义了一个跨编程语言.跨平台的编程接口的规范,它主要用于三维图形(实际上二维图形也可以)变成.OpenGL的前 ...

  2. opengl笔记——OpenGL好资料备忘

    Plane Equation 注:面可理解为:连接面上的点与原点,投影相同(为:a*x1+b*x2+c*x3) OpenGL Matrix Class (C++) Overview OpenGL fi ...

  3. 有关于OpenGL、OpenGL ES、WebGL的小结

    转自原文 有关于OpenGL.OpenGL ES.WebGL的小结 一.   OpenGL简介 OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言.跨平台的编程接口 ...

  4. YUV图解 (YUV444, YUV422, YUV420, YV12, NV12, NV21)

    背景: 最近在研究音视频,了解YUV这样的格式对于音视频开发比较重要. 虽然这篇文章大部分是转载别人的,但是经过了校对以后,重新排版并补充了一部分内容   概览: 之所以提出yuv格式的原因,是为了解 ...

  5. Android camera2 回调imagereader 从Image拿到YUV数据转化成RGB,生成bitmap并保存

    ImageUtil.java import android.graphics.ImageFormat; import android.media.Image; import android.os.Bu ...

  6. 色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV

    之前做个设计,现在从事IT,脑子里面关于RGB,RGBA,CMY,CMYK,YUV,但是具体理论还是不扎实.若干年前之前写过<水煮RGB与CMYK色彩模型—色彩与光学相关物理理论浅叙>&l ...

  7. Unity在OpenGL模式下Shader编译报错

    报错信息 GLSL compilation failed: 0(21) : error C7528: OpenGL reserves names containing '__' 双击报错VS自动打开V ...

  8. OpenGL笔记<5> shader 调试信息获取 Debug

    我们今天来讲调试信息,这个东西讲起来会比较无聊,因为都是一些函数调用,没啥可讲的,函数就是那样用的,不过其效果挺好玩的,同时在程序设计中也是很必要的,所以还是来写一下,不过,就是因为知识比较固定且简单 ...

  9. GLSL 在OpenGL中向shader传递信息【转】

    http://blog.csdn.net/hgl868/article/details/7872219 引言 一个OpenGL程序可以用多种方式和shader通信.注意这种通信是单向的,因为shade ...

随机推荐

  1. 《java并发编程实战》读书笔记13--Java内存模型,重排序,Happens-Before

    第16章 Java内存模型 终于看到这本书的最后一章了,嘿嘿,以后把这本书的英文版再翻翻.这本书中尽可能回避了java内存模型(JMM)的底层细节,而将重点放在一些高层设计问题,例如安全发布,同步策略 ...

  2. 初次接触express

    今天初次使用express,还是写写心得好了. 中间件 mothod nodemon ~的使用 中间件 中间件我觉得就是个开箱即用的工具,写好中间件函数,直接use就好. 示例1: let myLog ...

  3. 前端读者 | 前端用户体验-UI动效设计

    本文来自互联网 @羯瑞 整理 UI动效现如今在 APP 和网页中几乎已经成为了基本的组成部分,经过仔细打磨的 UI动效对于整个界面的提升是显著的. 动效呈现出状态切换的过程,展现了元素之间的逻辑关系, ...

  4. EL表达式无法显示Model中的数据

    后台程序通过Debug都能正常返回数据并封装到Model中.而在前台通过EL表达式取值时却是原样输出,如${cart.num}... ///展现我的购物车 @RequestMapping(" ...

  5. cocos2d-js中怎么删除一个精灵

    添加元素时,有Name属性 var child = parent.addChild(label, 1, "元素的名字"); 或者给child设置tag child.setTag(& ...

  6. Codeforces 1104 D. Game with modulo-交互题-二分-woshizhizhang(Codeforces Round #534 (Div. 2))

    D. Game with modulo time limit per test 1 second memory limit per test 256 megabytes input standard ...

  7. IEDA快捷键

    前言 开发工具从eclipse过渡到idea了:在刚开始使用的时候被idea强大的快捷键都惊呆了,这里记录了常见的一些快捷键和小伙伴们分享. 快捷键 鼠标悬停在单词上自动提示 : settings-- ...

  8. SCU - 4441 Necklace(树状数组求最长上升子数列)

    Necklace frog has \(n\) gems arranged in a cycle, whose beautifulness are \(a_1, a_2, \dots, a_n\). ...

  9. 【IO】同步、异步、阻塞、非阻塞的理解

    最近一直在看跟IO模型有关的内容,感觉差不多理解了,于是开始写这一篇总结博客.针对的操作系统为UNIX/LINUX,大致的体系结构如上图. 操作系统中的客体主要包括了:文件,Socket和进程,本文主 ...

  10. Linux基础系列-Day8

    Shell编程基础 Shell介绍 Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器).它类似于windows下的的cmd.exe.它接收用户命令,然后调用相应的应用程序 ...