YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24(转载)
转自: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(转载)的更多相关文章
- 音视频编解码: YUV存储格式中的YUV420P,YUV420SP,NV12, NV21理解(转)
概述 之前介绍了YUV码流的采样格式,下面分析下YUV码流的存储格式,YUV码流的存储格式与采样格式息息相关.总的来讲,YUV存储格式主要分为两种: planar 平面格式 指先连续存储所有像素点的 ...
- YUV图解 (YUV444, YUV422, YUV420, YV12, NV12, NV21)
背景: 最近在研究音视频,了解YUV这样的格式对于音视频开发比较重要. 虽然这篇文章大部分是转载别人的,但是经过了校对以后,重新排版并补充了一部分内容 概览: 之所以提出yuv格式的原因,是为了解 ...
- 小白学习Python之路---py文件转换成exe可执行文件
一.背景 今天闲着无事,写了一个小小的Python脚本程序,然后给同学炫耀的时候,发现每次都得拉着其他人过来看着自己的电脑屏幕,感觉不是很爽,然后我想着网上肯定有关于Python脚本转换成可执行文件的 ...
- xml转换为json格式时,如何将指定节点转换成数组 Json.NET
使用Json.NET转换xml成json时,如果xml只有单个节点,但json要求是数组形式[], JsonConvert.SerializeXmlNode 并不能自动识别 示例如下: RecordA ...
- json.net xml转换为json格式时,如何将指定节点转换成数组
using System.Xml.Linq; using Newtonsoft.Json; Response.ContentType = "application/json"; X ...
- OpenCV 学习笔记(13)图像转换成视频
关键 1参数里的分辨率是图像本身的分辨率,而不是指定生成的视频分辨率.如果要修改分辨率,要么后期软件处理,要么读图的时候resize 2要正常退出,不要强制退出. 3生成的只能是avi格式. #inc ...
- Maven 学习笔记——将普通的Java项目转换成Maven项目(3)
将一个普通的java项目转换成Maven项目并不是一个很大的任务,仅仅只需要下面的几步就能将转换成功.下面我是用一个简单的Selenium测试小demon作为例子来说的. 移调项目中所有关联的Libr ...
- 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 + ...
- OpenGL实现相机视频NV21格式转RGB格式
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
随机推荐
- C递归算法与栈的分析,非全然二叉树遍历分析---ShinePans
对于递归,这里面的分析最好当然是用图形的方式来分析了.这里来总结一下 1.首先对于栈的理解: 先进后出,后进先出 先进后出 2.在进行非全然二叉树的存储之后,我们要做的是对其 ...
- shiro框架的使用
1.配置二级缓存 <ehcache updateCheck="false" name="shiroCache"> <defaultCache ...
- php 数组转xml 数组转json xml转数组 json转数组
array->xml <?php function array2xml($array, $tag) { function ia2xml($array) { $xml="" ...
- Android-通过SlidingMenu高仿微信6.2最新版手势滑动返回(二)
转载请标明出处: http://blog.csdn.net/hanhailong726188/article/details/46453627 本文出自:[海龙的博客] 一.概述 在上一篇博文中,博文 ...
- EasyDarwin开源团队招募开发组成员
EasyDarwin开源流媒体服务器项目招募开发组成员,共同更新和维护EasyDarwin流媒体服务器,决策EasyDarwin后续开发方向: 加入要求: 1.对开源流媒体项目有浓厚兴趣: 2.有一定 ...
- SQuirreL – Phoenix的GUI
本文主要介绍如何通过SQuirreL访问Phoenix,以及如何在SQuirreL中配置Phoenix参数. 什么是SQuirrel? SQuirreL SQL Client是一个开源免费软件, 可以 ...
- types of transfrmations
http://math.wallawalla.edu/~duncjo/courses/math113/winter08/notes/9-1_math113.pdf Name What Changes ...
- 03-树2 List Leaves(25 point(s)) 【Tree】
03-树2 List Leaves(25 point(s)) Given a tree, you are supposed to list all the leaves in the order of ...
- Algorithm: Euclid's algorithm of finding GCD
寻找最大公约数方法 代码如下: int gcd (int a, int b) { return b ? gcd (b, a % b) : a; } 应用:求最小公倍数 代码如下: int lcm (i ...
- 重新认识vue之事件阻止冒泡
冒泡的表现 近期用vue做了一个需求,大概是同一个区域,点击不同位置有不同的响应函数,还有个总的响应函数,好吧,如下图所示: 他们的DOM结构如下: <div v-for="(item ...