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实战核心技术详解 ...
随机推荐
- 虚拟网卡TUN/TAP 驱动程序设计原理
昨天韦哥写了<Linux下Tun/Tap设备通信原理>一文,只提到了两个使用Tun的用户进程之间的通信路径,并没有说明Tun虚拟网卡驱动是如何实现的,而正好看到了这里的一篇讲解这方面的文章 ...
- bootstrap table api
http://blog.csdn.net/rickiyeat/article/details/56483577
- 解决Pods Unable to find a specification for `xxxxx`问题
错误信息为 Unable to find a specification for *RMQClient* (~> 1.x.x) depended upon by Podfile 刚开始以为这个已 ...
- 设置port转发来訪问Virtualbox里linux中的站点
上一篇中我们讲到怎么设置virtuabox来通过SSH登录机器. 相同.我们也能够依照上一篇内容中的介绍,设置port转发,来訪问虚拟linux系统已经搭建的站点: 1.设置port转发: water ...
- [Java SE] 字符串连接
Java 支持多种字符串连接方式,总结如下: package cn.spads.tool.string; import java.text.MessageFormat; /** * <b> ...
- Struts表单重复提交
- Block浅析一
1.在Block结构体中含有isa指针,这就证明了Block其实就是对象,并具有一般对象的所有功能. 2.Block是OC中的一种数据类型,在iOS开发中被广泛使用. 3.block的应用 (1)遍历 ...
- CORS 理解(不要那么多术语)
摘要 谈到跨域,不论前端还是后端,多少有点谈虎色变,面试中也常会问到这些问题,浏览器和服务器端到底怎么做才能跨域,他们都做了什么? 同源 vs 跨域 同源,字面意义是相同的源头,即同一个web服务器( ...
- zabbix 用户自定义监控参数添加
1. item key的添加 key可以带参数,该参数为一个数组列表,可以同时传递多个参数,key的格式如下 key -- [ parameters] -- 例如: vfs.fs.size[/] v ...
- 理解HTML解析过程
浏览器解析html的过程是:接受网络数据->将二进制码变成字符->将字符变为unicode code points.->tokenizer ->tree constructor ...