大家好,又见面了,我是你们的朋友全栈君。
摘要
关于像素格式转换,搜到的帖子基本是NV16转RGB24 或 NV12转RGB24,对于NV16转NV12并没太多资料,因此我打算参照这两个像素格式的结构,实现这个转换接口。
NV16像素格式介绍
NV16可以理解为yuyv像素格式的变种,属于YUV422SP类型。整帧图像的大小为 Width * Height * 2
。其像素格式如下:
- start 00: Y00 Y01 Y02 Y03
- start 04: Y10 Y11 Y12 Y13
- start 08: Y20 Y21 Y22 Y23
- start 12: Y30 Y31 Y32 Y33
- start 16: Cb00 Cr00 Cb01 Cr01
- start 20: Cb10 Cr10 Cb11 Cr11
- start 24: Cb20 Cr20 Cb21 Cr21
- start 28: Cb30 Cr30 Cb31 Cr31
NV12像素格式介绍
NV12则属于YUV420SP类型,整帧图像的大小为 Width * Height * 3 / 2
。其像素格式如下:
- start 00: Y00 Y01 Y02 Y03
- start 04: Y10 Y11 Y12 Y13
- start 08: Y20 Y21 Y22 Y23
- start 12: Y30 Y31 Y32 Y33
- start 16: Ub00 Ur00 Ub01 Ur01
- start 20: Ub10 Ur10 Ub11 Ur11
转换规则介绍
- Y数据直接拷贝。
- NV12的 Ubxx取值NV16奇数行的Cbxx
- NV12的 Urxx取值NV16偶数行的Crxx
例如:
代码语言:javascript复制NV16 NV12
Cb00 Cb01 ----> Ub00 Ub01
Cr10 Cr11 ----> Vr00 Vr01
Cb20 Cb21 ----> Ub10 Ub11
Cr30 Cr31 ----> Vr10 Vr11
代码
代码语言:javascript复制#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/** * 功能:nv16像素格式转换为nv12像素格式 * 参数介绍: * nv16_buff:NV16格式一帧数据,大小为 w * h * 2,作为函数输入。 * nv12_buff:NV12格式的一帧数据,大小为 w * h * 3 / 2,作为函数输出。 * w:图像的宽度。 * h:图像高度。 */
int pixel_format_nv16_to_nv12(char *nv16_buff, char *nv12_buff, int w, int h)
{
unsigned char *nv16_y = NULL;
unsigned char *nv16_uv = NULL;
unsigned char *nv12_y = NULL;
unsigned char *nv12_u = NULL;
unsigned char *nv12_v = NULL;
int i, j, offset;
if (!nv16_buff || !nv12_buff || ((w*h) <= 0)) {
printf("ERROR: %s input args invalid!n", __func__);
return -EINVAL;
}
/* get the right point */
nv16_y = (unsigned char *)nv16_buff;
nv16_uv = (unsigned char *)nv16_buff w * h;
nv12_y = (unsigned char *)nv12_buff;
nv12_u = (unsigned char *)nv12_buff w * h;
nv12_v = nv12_u 1;
/* copy y dates directly */
memcpy(nv12_y, nv16_y, w * h);
/* get nv12_uv dates from nv16_uv * * >>>> nv16 pix formate: * start 0: Y'00 Y'01 Y'02 Y'03 * start 4: Y'10 Y'11 Y'12 Y'13 * start 8: Y'20 Y'21 Y'22 Y'23 * start 12: Y'30 Y'31 Y'32 Y'33 * start 16: Cb00 Cr00 Cb01 Cr01 * start 20: Cb10 Cr10 Cb11 Cr11 * start 24: Cb20 Cr20 Cb21 Cr21 * start 28: Cb30 Cr30 Cb31 Cr31 * * >>>> nv12 pix formate: * start 0: Y'00 Y'01 Y'02 Y'03 * start 4: Y'10 Y'11 Y'12 Y'13 * start 8: Y'20 Y'21 Y'22 Y'23 * start 12: Y'30 Y'31 Y'32 Y'33 * start 16: Ub00 Vr00 * start 18: Ub01 Vr01 * start 20: Ub10 Vr10 * start 22: Ub11 Vr11 * * nv16的uv分量与 nv12的uv分量对于关系: * 偶数行取Cb值,奇数行取Cr值 * Cb00 Cb01 ----> Ub00 Ub01 * Cr10 Cr11 ----> Vr00 Vr01 * Cb20 Cb21 ----> Ub10 Ub11 * Cr30 Cr31 ----> Vr10 Vr11 */
/* 奇数行取Cb */
offset = 0;
for (i = 0; i < h; i =2) {
offset = i * w;
for (j = 0; j < w; j =2) {
*nv12_u = *(nv16_uv offset j);
nv12_u = 2;
}
}
/* 偶数行取Cr */
offset = 0;
for (i = 1; i < h; i =2) {
offset = i * w;
for (j = 1; j < w; j =2) {
*nv12_v = *(nv16_uv offset j);
nv12_v = 2;
}
}
return 0;
}
工程下载地址
工程地址:https://download.csdn.net/download/lyy901135/11458140
完整工程,包含main函数,以及测试输入的nv16图片,只需执行make
编译后即可运行。
运行命令:./nv16_to_nv12 test.nv16 test.nv12
查看输出图片(nv12):ffplay -f rawvideo -video_size 1920x1080 -pixel_format nv12 test.nv12
由图可见,转换后色度都是正确的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。