http://stackoverflow.com/questions/1106741/need-help-with-yuv-display-in-opengl 

I am having trouble displaying a raw YUV file that it is in NV12 format.

I can display a selected frame, however, it is still mainly in black and white with certain shades of pink and green.

Here is how my output looks like 

Anyways, here is how my program works. (This is done in cocoa/objective-c, but I need your expert advice on program algorithm, not on syntax.)

Prior to program execution, the YUV file is stored in a binary file named "test.yuv". The file is in NV12 format, meaning the Y plan is stored first, then the UV plan is interlaced. My file extraction has no problem because I did a lot testings on it.

During initiation, I create a lookup table that will convert binary/8 bites/a byte/chars into respected Y, U, V float values

For the Y plane this is my code

-(void)createLookupTableY //creates a lookup table for converting a single byte into a float between 0 and 1{ NSLog(@"YUVFrame: createLookupTableY");     lookupTableY = new float [256]; for (int i = 0; i < 256; i++) {     	lookupTableY[i] = (float) i /255; //NSLog(@"lookupTableY[%d]: %f",i,lookupTableY[i]);//prints out the value of each float }}

The U Plane lookup table

-(void)createLookupTableU //creates a lookup table for converting a single byte into a float between 0 and 1{ NSLog(@"YUVFrame: createLookupTableU");     lookupTableU = new float [256]; for (int i = 0; i < 256; i++) {     	lookupTableU[i] = -0.436 + (float) i / 255* (0.436*2); NSLog(@"lookupTableU[%d]: %f",i,lookupTableU[i]);//prints out the value of each float }}

And the V look-up table

-(void)createLookupTableV //creates a lookup table for converting a single byte into a float between 0 and 1{ NSLog(@"YUVFrame: createLookupTableV");     lookupTableV = new float [256]; for (int i = 0; i < 256; i++) {     	lookupTableV[i] = -0.615 + (float) i /255 * (0.615*2); NSLog(@"lookupTableV[%d]: %f",i,lookupTableV[i]);//prints out the value of each float }}

after this point, I extract the Y & UV plan and store them into two buffers, yBuffer & uvBuffer

at this point, I attempt to convert the YUV data and stored it into a RGB buffer array called "frameImage"

-(void)sortAndConvert//sort the extracted frame data into an array of float{ NSLog(@"YUVFrame: sortAndConvert"); int frameImageCounter = 0; int pixelCounter = 0; for (int y = 0; y < YUV_HEIGHT; y++)//traverse through the frame's height { for ( int x = 0; x < YUV_WIDTH; x++)//traverse through the frame's width { float Y = lookupTableY [yBuffer [y*YUV_WIDTH + x] ]; float U = lookupTableU [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 ] ]; float V = lookupTableV [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 + 1] ]; float RFormula = Y + 1.13983f * V; float GFormula = Y - 0.39465f * U - 0.58060f * V; float BFormula = Y + 2.03211f * U;      		 frameImage [frameImageCounter++] = [self clampValue:RFormula];     		 frameImage [frameImageCounter++] = [self clampValue:GFormula];     		 frameImage [frameImageCounter++] = [self clampValue:BFormula]; } }}

then I tried to draw the Image in OpenGl

-(void)drawFrame:(int )x { GLuint texture;      glGenTextures(1, &texture);     glBindTexture(GL_TEXTURE_2D, texture);     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_FLOAT, frameImage);      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);      glEnable(GL_TEXTURE_2D);     glBindTexture(GL_TEXTURE_2D, texture);     glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );      glBegin( GL_QUADS );     glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);     glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);     glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);     glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);     glEnd();      glFlush();}

so basically this my program in a nut shell. essentially i read the binary YUV files, stores all the data in a char array buffer. i then translate these values into their respected YUV float values.

This is where I think the error might be: in the Y lookup table I standardize the Y plane to [0,1], in the U plane I standardized the values between [-0.435,0.436], and in the V plane I standardized it bewteen [-0.615,0.615]. I did this because those are the YUV value ranges according to wikipedia.

And the YUV to RGB formula is the same formula from Wikipedia. I have also tried various other formulas, and this is the only formula that gives the rough outlook of the frame. Anyone might venture to guess to why my program is not correctly displaying the YUV frame data. I think it is something to do with my standardization technique, but it seems alright to me.

I have done a lot of testings, and I am 100% certain that the error is caused by by look up table. I don't think my setting formulas are correct.

A note to everyone who is reading this. For the longest time, my frame was not displaying properly because I was not able to extract the frame data correctly.

When I first started to program, I was under the impression that in a clip of say 30 frames, all 30 Y planar datas are first written in the data file, followed then by UV plane datas.

What I found out through trial and error was that for a YUV data file, specifically NV12, the data file is stored in the following fashion

Y(1) UV(1) Y(2) UV(2) ... ...

@nschmidt

I changed my code to what you suggested

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]

and this is the result that i get 

here is the print line from the console. i am print out the values for Y, U, V and RGB value that are being translated and stored on in the frameImage array

YUV:[0.658824,-0.022227,-0.045824] RGBFinal:[0.606593,0.694201,0.613655]

YUV:[0.643137,-0.022227,-0.045824] RGBFinal:[0.590906,0.678514,0.597969]

YUV:[0.607843,-0.022227,-0.045824] RGBFinal:[0.555612,0.643220,0.562675]

YUV:[0.592157,-0.022227,-0.045824] RGBFinal:[0.539926,0.627534,0.546988]

YUV:[0.643137,0.025647,0.151941] RGBFinal:[0.816324,0.544799,0.695255]

YUV:[0.662745,0.025647,0.151941] RGBFinal:[0.835932,0.564406,0.714863]

YUV:[0.690196,0.025647,0.151941] RGBFinal:[0.863383,0.591857,0.742314]

Update July 13, 2009

The problem was finally solved thanks to the recommendation from nschmidt . It turns out that my YUV file was actually in YUV 4:1:1 format. I was originally told that it was in YUV NV12 format. Anyways, I would like to share my results with you.

Here is output

and my code for decode is as follows

float Y = (float) yBuffer [y*YUV_WIDTH + x] ;float U = (float) uvBuffer [ ((y / 2) * (YUV_WIDTH  / 2) + (x/2)) ] ; float V = (float) uvBuffer [ ((y / 2) * (YUV_WIDTH  / 2) + (x/2)) + UOffset] ;float RFormula = (1.164*(Y-16) + (1.596* (V - 128) ));float GFormula = ((1.164 * (Y - 16)) - (0.813 * ((V) - 128)) - (0.391 * ((U) - 128)));float BFormula = ((1.164 * (Y - 16)) + (2.018 * ((U) - 128)));   		frameImage [frameImageCounter] = (unsigned char)( (int)[self clampValue:RFormula]); 		frameImageCounter ++; 		frameImage [frameImageCounter] = (unsigned char)((int)[self clampValue:GFormula]); 		frameImageCounter++; 		frameImage [frameImageCounter] = (unsigned char)((int) [self clampValue:BFormula]); 		frameImageCounter++;GLuint texture;  glGenTextures(1, &texture); glEnable(GL_TEXTURE_2D);  glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frameImage);//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE_SGIS); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_SGIS); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);  glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );  glBegin( GL_QUADS ); glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0); glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0); glEnd();NSLog(@"YUVFrameView: drawRect complete"); glFlush();

essentially, I used NSData for the raw file extraction. stored in a char array buffer. For YUV to RGB conversion, I used the above formula, afterwards, I clamped the values to [0:255]. then I used a 2DTexture in OpenGL for display.

So if you are converting YUV to RGB in the future, use the formula from above. If are using the YUV to RGB conversion formula from the earlier post, then you need to display the texture in GL_Float from the values for RGB are clamped between [0:1]

<div "="" style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; height: 35px; width: 185px; background: transparent;">

 
 

3 Answers

Next try :) I think you're uv buffer is not interleaved. It looks like the U values come first and then the array of V values. Changing the lines to

unsigned int voffset = YUV_HEIGHT * YUV_WIDTH / 2;float U = lookupTableU [uvBuffer [ y * (YUV_WIDTH / 2) + x/2] ]; float V = lookupTableV [uvBuffer [ voffset + y * (YUV_WIDTH / 2) + x/2] ];

might indicate if this is really the case.

<div "="" style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; height: 35px; width: 185px; background: transparent;">

answered Jul 11 '09 at 12:12
nschmidt
1,816919
    
wow, I tested out my program with your adjustment and it finally worked. thanks a lot man.it turns out that you were right, the U & V plane are not interlaced as I was originally told. thank you so much nschmidt. I'm rating you up –  ReachConnection Jul 13 '09 at 15:07
    
no problem :). for the record the first guess about the format being 4:1:1 was actually incorrect. You have 4:2:2 format. The real problem was only your data not being interleaved. –  nschmidt Jul 14 '09 at 17:54

I think you're addressing U and V values incorrectly. Rather than:

float U = lookupTableU [uvBuffer [ ((y / 2) * (x / 2) + (x/2)) * 2 ] ]; float V = lookupTableV [uvBuffer [ ((y / 2) * (x / 2) + (x/2)) * 2 + 1] ];

It should be something along the lines of

float U = lookupTableU [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 ] ]; float V = lookupTableV [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 + 1] ];
<div "="" style="margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; height: 35px; width: 185px; background: transparent;">

answered Jul 10 '09 at 11:47
nschmidt
1,816919
    
thanks, I missed this mistake. however, I made the changes and the displayed frame is still mainly in black and white, with pink and green shades here and there. –  ReachConnection Jul 10 '09 at 15:08
    
I just added a image to show how my output looks like –  ReachConnection Jul 10 '09 at 15:33

The picture looks like you have 4:1:1 format. You should change your lines to

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]

Maybe you can post the result to see, what else is wrong. I find it always hard to think about it. It's much easier to approach this iteratively.

YUV display in OpenGL的更多相关文章

  1. 记录一次安装OpenGL的漫长过程

    尝试codeblock和Dev-C++ 这学期新开了一门计算机图形图像的课,里面涉及到openGL,中午跑到图书馆开始倒腾OpenGL. 因为电脑里本来有codeblock,于是就想不用教材里面所说的 ...

  2. Draw the RGB data from kinect C++ via opengl

    In order to improve my English writing skills,I am going to  write the blogs in English form now! -- ...

  3. LCD framebuffer驱动设计文档

    内容提要:1. android display相关的名词2. 调试LCD驱动需要注意的步骤3. 关于帧缓冲区及I/O内存---------------------------------------- ...

  4. Direct Access to Video Encoding and Decoding

    来源:http://asciiwwdc.com/2014/sessions/513   Direct Access to Video Encoding and Decoding  Session 5 ...

  5. RTSP H264/HEVC 流 Wasm 播放

    本文将介绍 RTSP H264/HEVC 裸流如何于网页前端播放.涉及 WebSocket 代理发送流数据, Wasm 前端解码等. 代码: https://github.com/ikuokuo/rt ...

  6. C++实现数字媒体三维图像变换

    C++实现数字媒体三维图像变换 必备环境 glut.h 头文件 glut32.lib 对象文件库 glut32.dll 动态连接库 程序说明 C++实现了用glut画物体对象的功能.并附带放大缩小,旋 ...

  7. EGL 1.0 学习笔记

    http://hi.baidu.com/leo_xxx/item/b01b1fc29abff355ac00ef5c 基本概念 EGL是OpenGL ES与本地Window系统之间的桥梁.EGL创建渲染 ...

  8. 【2】【MOOC】Python游戏开发入门-北京理工大学【第三部分-游戏开发之机制(屏幕绘制机制)】

    学习地址链接:http://www.icourse163.org/course/0809BIT021E-1001873001?utm_campaign=share&utm_medium=and ...

  9. Starling 2D框架简介(一)

    本系列是对Introducing Starling pdf的翻译,下文是对adobe开发人员中心的一片日志的转载,地址为http://www.adobe.com/cn/devnet/flashplay ...

随机推荐

  1. javaweb带属性的自定义标签

    带属性的自定义标签: 1.先在标签处理器中定义setter方法,建议把所有的属性类型都设置为String类型. package com.javaweb.tag; import java.io.IOEx ...

  2. react相关知识点链接整理

    1.React组件之间的通信 2.中间件做代理解决跨域问题 3.不要再问我跨域的问题了 4.React 组件数据流 && 组件间沟通 5.如何理解虚拟DOM 6.react性能调谐与d ...

  3. JavaScript中的attachEvent和addEventListener

    attachEvent和addEventListener在前端开发过程中经常性的使用,他们都可以用来绑定脚本事件,取代在html中写obj.onclick=method. 相同点: 它们都是dom对象 ...

  4. Bzoj1492: [NOI2007]货币兑换Cash(不单调的斜率优化)

    题面 传送门 Sol 题目都说了 必然存在一种最优的买卖方案满足: 每次买进操作使用完所有的人民币: 每次卖出操作卖出所有的金券. 设\(f[i]\)表示第\(i\)天可以有的最大钱数 枚举\(j&l ...

  5. Linux基础之-网络配置,主机名设置,ssh登陆,scp传输

    一. 网络配置修改 1.临时修改(ip,dns,netmask,gateway) 临时修改网络配置,只要没有涉及到修改配置文件的,在network服务重启后,所有设置失效 2.永久修改(ip,dns, ...

  6. (C/C++) 用函数返回一个结构体

    方法一: 参数里含有指向指针的指针. 注意:如果函数参数里只有一个指向结构体的指针,是无法正确地返回结构体的值的.原因在于在编译的时候,会对入参p产生一个备份_p. 参考此文:http://www.c ...

  7. 如何在VS2010环境下编译C++程序

    原文:http://blog.csdn.net/gupengnina/article/details/7441203 用 Visual Studio 编写 Visual C++ 程序的第一步是选择项目 ...

  8. Tesseract-OCR-04-使用 jTessBoxEditor 进行训练

    Tesseract-OCR-04-使用 jTessBoxEditor 进行训练 本篇是关于 jTessBoxEditor 进行训练,使 Tesseract-OCR 文字识别准确率得到极大的提高,本篇完 ...

  9. python 测试:生成exe文件

    任务: test.py print(input('请输入:')) 将test.py生成test.exe 解答: 安装: pip install pyinstaller 命令使用: (绝对地址)pyin ...

  10. Apache2.4和IIS7整合共享80端口测试

    言我再重新排版一下 在C:\Windows\System32\drivers\etc\hosts文件中配置2个测试域名用于整合测试 127.0.0.1 www.aaa.com // apache项目 ...