转自:http://www.latelee.org/my-study/yuv-learning-yuv420p-to-rgb24.html

  对于YUV420的格式,网上有一大堆资料,这里就不说了。直奔主题,给出如何转换的函数,一如既往,只用代码说事。
YUV420有打包格式(Packed),一如前文所述。同时还有平面格式(Planar),即Y、U、V是分开存储的,每个分量占一块地方,其中Y为
width*height,而U、V合占Y的一半,该种格式每个像素占12比特。根据U、V的顺序,分出2种格式,U前V后即YUV420P,也叫
I420,V前U后,叫YV12(YV表示Y后面跟着V,12表示12bit)。另外,还有一种半平面格式(Semi-planar),即Y单独占一块地
方,但其后U、V又紧挨着排在一起,根据U、V的顺序,又有2种,U前V后叫NV12,在国内好像很多人叫它为YUV420SP格式;V前U后叫
NV21。这种格式似乎比NV16稍受欢迎。
首先给出转换查询表的生成函数,代码是在网上找来的,如下:

static long int crv_tab[256];
static long int cbu_tab[256];
static long int cgu_tab[256];
static long int cgv_tab[256];
static long int tab_76309[256];
static unsigned char clp[1024]; //for clip in CCIR601 void init_yuv420p_table()
{
long int crv,cbu,cgu,cgv;
int i,ind;
static int init = 0; if (init == 1) return; crv = 104597; cbu = 132201; /* fra matrise i global.h */
cgu = 25675; cgv = 53279; for (i = 0; i < 256; i++)
{
crv_tab[i] = (i-128) * crv;
cbu_tab[i] = (i-128) * cbu;
cgu_tab[i] = (i-128) * cgu;
cgv_tab[i] = (i-128) * cgv;
tab_76309[i] = 76309*(i-16);
} for (i = 0; i < 384; i++)
clp[i] = 0;
ind = 384;
for (i = 0;i < 256; i++)
clp[ind++] = i;
ind = 640;
for (i = 0;i < 384; i++)
clp[ind++] = 255; init = 1;
}

下面给出YUV420平面格式的转换函数,如下:

/**
内存分布
w
+--------------------+
|Y0Y1Y2Y3... |
|... | h
|... |
| |
+--------------------+
|U0U1 |
|... | h/2
|... |
| |
+----------+
|V0V1 |
|... | h/2
|... |
| |
+----------+
w/2
*/
void yuv420p_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)
{
int y1, y2, u, v;
unsigned char *py1, *py2;
int i, j, c1, c2, c3, c4;
unsigned char *d1, *d2;
unsigned char *src_u, *src_v;
static int init_yuv420p = 0; src_u = yuvbuffer + width * height; // u
src_v = src_u + width * height / 4; // v if (type == FMT_YV12)
{
src_v = yuvbuffer + width * height; // v
src_u = src_u + width * height / 4; // u
}
py1 = yuvbuffer; // y
py2 = py1 + width;
d1 = rgbbuffer;
d2 = d1 + 3 * width; init_yuv420p_table(); for (j = 0; j < height; j += 2)
{
for (i = 0; i < width; i += 2)
{
u = *src_u++;
v = *src_v++; c1 = crv_tab[v];
c2 = cgu_tab[u];
c3 = cgv_tab[v];
c4 = cbu_tab[u]; //up-left
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)]; //down-left
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)]; //up-right
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)]; //down-right
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];
}
d1 += 3*width;
d2 += 3*width;
py1 += width;
py2 += width;
}
}

再给出YUV420SP转换的函数,如下:

void yuv420sp_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)
{
int y1, y2, u, v;
unsigned char *py1, *py2;
int i, j, c1, c2, c3, c4;
unsigned char *d1, *d2;
unsigned char *src_u;
static int init_yuv420p = 0; src_u = yuvbuffer + width * height; // u py1 = yuvbuffer; // y
py2 = py1 + width;
d1 = rgbbuffer;
d2 = d1 + 3 * width; init_yuv420p_table(); for (j = 0; j < height; j += 2)
{
for (i = 0; i < width; i += 2)
{
if (type == FMT_NV12)
{
u = *src_u++;
v = *src_u++; // v紧跟u,在u的下一个位置
}
if (type == FMT_NV21)
{
v = *src_u++;
u = *src_u++; // u紧跟v,在v的下一个位置
} c1 = crv_tab[v];
c2 = cgu_tab[u];
c3 = cgv_tab[v];
c4 = cbu_tab[u]; //up-left
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)]; //down-left
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)]; //up-right
y1 = tab_76309[*py1++];
*d1++ = clp[384+((y1 + c1)>>16)];
*d1++ = clp[384+((y1 - c2 - c3)>>16)];
*d1++ = clp[384+((y1 + c4)>>16)]; //down-right
y2 = tab_76309[*py2++];
*d2++ = clp[384+((y2 + c1)>>16)];
*d2++ = clp[384+((y2 - c2 - c3)>>16)];
*d2++ = clp[384+((y2 + c4)>>16)];
}
d1 += 3*width;
d2 += 3*width;
py1 += width;
py2 += width;
}
}

参考资料:
http://www.fourcc.org/yuv.php
https://wiki.videolan.org/YUV/

李迟 2015.8.5 晚上

本文固定链接: http://www.latelee.org/my-study/yuv-learning-yuv420p-to-rgb24.html

YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24(转载)的更多相关文章

  1. 音视频编解码: YUV存储格式中的YUV420P,YUV420SP,NV12, NV21理解(转)

    概述  之前介绍了YUV码流的采样格式,下面分析下YUV码流的存储格式,YUV码流的存储格式与采样格式息息相关.总的来讲,YUV存储格式主要分为两种: planar 平面格式 指先连续存储所有像素点的 ...

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

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

  3. 小白学习Python之路---py文件转换成exe可执行文件

    一.背景 今天闲着无事,写了一个小小的Python脚本程序,然后给同学炫耀的时候,发现每次都得拉着其他人过来看着自己的电脑屏幕,感觉不是很爽,然后我想着网上肯定有关于Python脚本转换成可执行文件的 ...

  4. xml转换为json格式时,如何将指定节点转换成数组 Json.NET

    使用Json.NET转换xml成json时,如果xml只有单个节点,但json要求是数组形式[], JsonConvert.SerializeXmlNode 并不能自动识别 示例如下: RecordA ...

  5. json.net xml转换为json格式时,如何将指定节点转换成数组

    using System.Xml.Linq; using Newtonsoft.Json; Response.ContentType = "application/json"; X ...

  6. OpenCV 学习笔记(13)图像转换成视频

    关键 1参数里的分辨率是图像本身的分辨率,而不是指定生成的视频分辨率.如果要修改分辨率,要么后期软件处理,要么读图的时候resize 2要正常退出,不要强制退出. 3生成的只能是avi格式. #inc ...

  7. Maven 学习笔记——将普通的Java项目转换成Maven项目(3)

    将一个普通的java项目转换成Maven项目并不是一个很大的任务,仅仅只需要下面的几步就能将转换成功.下面我是用一个简单的Selenium测试小demon作为例子来说的. 移调项目中所有关联的Libr ...

  8. OpenCV 学习笔记(9)RGB转换成灰度图像的一个常用公式Gray = R*0.299 + G*0.587 + B*0.114

    https://blog.csdn.net/fly_wt/article/details/86432886 RGB转换成灰度图像的一个常用公式是:Gray = R*0.299 + G*0.587 + ...

  9. OpenGL实现相机视频NV21格式转RGB格式

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

随机推荐

  1. javascript JS递归遍历对象 使用for(variable in object)或者叫for/in和forEach方式

    1.递归遍历查找特定key值(ie9以下不支持forEach) 原文http://www.cnblogs.com/ae6623/p/5938560.html var obj = { first: &q ...

  2. Geoffrey E. Hinton

    https://www.cs.toronto.edu/~hinton/ Geoffrey E. Hinton I am an Engineering Fellow at Google where I ...

  3. the algebra of modulo-2 sums disk failure recovery

    x=y x_+_y=0 The bit in any position is the modulo-2 sum of all the bits in the corresponding positio ...

  4. 解决Windows x64bit环境下无法使用PLSQL Developer连接到Oracle DB中的问题

    本文是原创文章,转载请注明出处: http://blog.csdn.net/msdnchina/article/details/46416455 解决Windows x64bit环境下无法使用PLSQ ...

  5. NSString和NSMutableNSString的基本用法

    // // main.m // NSString /** NSString 1.NSString 是一个不可以变的字符串对象 2.NSMutableString是一个可变字符串. 下面代码为字符串的: ...

  6. DTLS学习笔记 -- RFC 4347- 6347

    想学习一下dtls,是因为想以后没有公司免费VPN可用的时候,我能买一个主机,自己建一个VPN. 1.介绍 Web, email大多用TLS协议来做安全的网络传输,它们必须跑在可靠的TCP传输通道里. ...

  7. Mac下文件编码转换

    参见:http://bbs.feng.com/read-htm-tid-107633.html 使用: sudo find *.txt -exec sh -c "iconv -f GB180 ...

  8. H264视频通过RTMP直播

    http://blog.csdn.net/firehood_/article/details/8783589 前面的文章中提到了通过RTSP(Real Time Streaming Protocol) ...

  9. linux应用之yum命令详解

    linux yum命令详解 yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能 ...

  10. map的详细用法 (转

    map的详细用法: map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能 力,由于这个特性,它完成有可能在我 ...