NV16 转 NV12

摘要

关于像素格式转换,搜到的帖子基本是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 Vr00 Ub01 Vr01
  • start + 20: Ub10 Vr10 Ub11 Vr11

转换规则介绍

  • Y数据直接拷贝。
  • NV12的 Ubxx取值NV16奇数行的Cbxx
  • NV12的 Urxx取值NV16偶数行的Crxx

例如:

NV16              NV12
Cb00 Cb01  ----> Ub00 Ub01
Cr10 Cr11  ----> Vr00 Vr01
Cb20 Cb21  ----> Ub10 Ub11
Cr30 Cr31  ----> Vr10 Vr11

代码

#include 
#include 
#include 
#include 

/**
 * 功能: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
由图可见,转换后色度都是正确的。
NV16 转 NV12_第1张图片

你可能感兴趣的:(图像处理)