日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【OpenGL】用OpenGL shader实现将YUV(YUV420,YV12)转RGB-(直接调用GPU实现,纯硬件方式,效率高)...

發(fā)布時間:2025/7/14 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OpenGL】用OpenGL shader实现将YUV(YUV420,YV12)转RGB-(直接调用GPU实现,纯硬件方式,效率高)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這段時間一直在搞視頻格式的轉(zhuǎn)換問題,終于最近將一個圖片的YUV格式轉(zhuǎn)RGB格式轉(zhuǎn)換成功了。下面就來介紹一下:


由于我的工程是在vs2008中的,其中包含一些相關(guān)頭文件和庫,所以下面只是列出部分核心代碼,并不是全部代碼。


1、下載一個包含YUV數(shù)據(jù)的文件也可以自己制作一個該文件

下載地址:YUV數(shù)據(jù)文件

2、讀入YUV數(shù)據(jù)文件中的yuv數(shù)據(jù):

關(guān)鍵代碼如下:

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讀入數(shù)據(jù),并將YUV數(shù)據(jù)分別制作成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數(shù)據(jù)文件

3、將紋理傳入

上述片段shader中就是根據(jù)yuv轉(zhuǎn)rgb的公式得來的。也就是說是在shader中實現(xiàn)轉(zhuǎn)換的。 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中就是根據(jù)yuv轉(zhuǎn)rgb的公式得來的。也就是說是在shader中實現(xiàn)轉(zhuǎn)換的。

4、顯示結(jié)果

結(jié)果如下:

注意:該shader是OpenGL格式的shader有一點差別。

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

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

YV12,I420,YUV420P的區(qū)別

YV12和I420的區(qū)別 一般來說,直接采集到的視頻數(shù)據(jù)是RGB24的格式,RGB24一幀的大小size=width×heigth×3 Byte,RGB32的size=width×heigth×4,如果是I420(即YUV標準格式4:2:0)的數(shù)據(jù)量是 size=width×heigth×1.5 Byte。
在采集到RGB24數(shù)據(jù)后,需要對這個格式的數(shù)據(jù)進行第一次壓縮。即將圖像的顏色空間由RGB2YUV。因為,X264在進行編碼的時候需要標準的YUV(4:2:0)。但是這里需要注意的是,雖然YV12也是(4:2:0),但是YV12和I420的卻是不同的,在存儲空間上面有些區(qū)別。如下:
YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
可以看出,YV12和I420基本上是一樣的,就是UV的順序不同。
繼續(xù)我們的話題,經(jīng)過第一次數(shù)據(jù)壓縮后RGB24->YUV(I420)。這樣,數(shù)據(jù)量將減少一半,為什么呢?呵呵,這個就太基礎了,我就不多寫了。同樣,如果是RGB24->YUV(YV12),也是減少一半。但是,雖然都是一半,如果是YV12的話效果就有很大損失。然后,經(jīng)過X264編碼后,數(shù)據(jù)量將大大減少。將編碼后的數(shù)據(jù)打包,通過RTP實時傳送。到達目的地后,將數(shù)據(jù)取出,進行解碼。完成解碼后,數(shù)據(jù)仍然是YUV格式的,所以,還需要一次轉(zhuǎn)換,這樣windows的驅(qū)動才可以處理,就是YUV2RGB24。

補充============= 詳細的格式之間的差異可以參考: FFMPEG 實現(xiàn) YUV,RGB各種圖像原始數(shù)據(jù)之間的轉(zhuǎn)換(swscale) 附一個YUV播放器的源代碼:http://download.csdn.net/detail/leixiaohua1020/6374065 查看YUV的時候也可以下載使用成熟的YUV播放器 ——YUV Player Deluxe:http://www.yuvplayer.com/ ?

yuv420p就是I420格式,使用極其廣泛,它的示意圖:

【圖像-視頻處理】YUV420、YV12與RGB24的轉(zhuǎn)換公式


[cpp] view plaincopy print?
  • bool?YV12ToBGR24_Native(unsigned?char*?pYUV,unsigned?char*?pBGR24,int?width,int?height)??
  • {??
  • ????if?(width?<?1?||?height?<?1?||?pYUV?==?NULL?||?pBGR24?==?NULL)??
  • ????????return?false;??
  • ????const?long?len?=?width?*?height;??
  • ????unsigned?char*?yData?=?pYUV;??
  • ????unsigned?char*?vData?=?&yData[len];??
  • ????unsigned?char*?uData?=?&vData[len?>>?2];??
  • ??
  • ????int?bgr[3];??
  • ????int?yIdx,uIdx,vIdx,idx;??
  • ????for?(int?i?=?0;i?<?height;i++){??
  • ????????for?(int?j?=?0;j?<?width;j++){??
  • ????????????yIdx?=?i?*?width?+?j;??
  • ????????????vIdx?=?(i/2)?*?(width/2)?+?(j/2);??
  • ????????????uIdx?=?vIdx;??
  • ??
  • ????????????bgr[0]?=?(int)(yData[yIdx]?+?1.732446?*?(uData[vIdx]?-?128));????????????????????????????????????//?b分量??
  • ????????????bgr[1]?=?(int)(yData[yIdx]?-?0.698001?*?(uData[uIdx]?-?128)?-?0.703125?*?(vData[vIdx]?-?128));????//?g分量??
  • ????????????bgr[2]?=?(int)(yData[yIdx]?+?1.370705?*?(vData[uIdx]?-?128));????????????????????????????????????//?r分量??
  • ??
  • ????????????for?(int?k?=?0;k?<?3;k++){??
  • ????????????????idx?=?(i?*?width?+?j)?*?3?+?k;??
  • ????????????????if(bgr[k]?>=?0?&&?bgr[k]?<=?255)??
  • ????????????????????pBGR24[idx]?=?bgr[k];??
  • ????????????????else??
  • ????????????????????pBGR24[idx]?=?(bgr[k]?<?0)?0:255;??
  • ????????????}??
  • ????????}??
  • ????}??
  • ????return?true;??
  • }?
  • 以上是yv12到RGB24的轉(zhuǎn)換算法,如果是yuv420到RGB24轉(zhuǎn)換,秩序u,v反過來就可以了。

    即:

    [cpp] view plaincopy print?
  • unsigned?char*?uData?=?&yData[nYLen];??
  • unsigned?char*?vData?=?&vData[nYLen>>2];??
  • 注:海康威視網(wǎng)絡攝像頭一般就是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); } ?

    ?

    總結(jié)

    以上是生活随笔為你收集整理的【OpenGL】用OpenGL shader实现将YUV(YUV420,YV12)转RGB-(直接调用GPU实现,纯硬件方式,效率高)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。