YU12格式也叫I420格式,是YUV420p其中的一种,NV12是YUV420sp的一种。YU12和NV21中YUV数据的排列方式为:
YU12:YYYYYYYY UU VV
NV12:YYYYYYYY UV UV
针对数据的排列结构,本文将NV12转为YU12以及YU12转NV12。
NV12转为YU12
NV12转为YU12转换接口实现为:
int NV12toYU12(char *data, char *out, int width, int height);
功能描述 : Nv12格式转YU12
输入参数 :
data : NV12图片数据指针
out :YU12图片地址
width: 图像宽度
height : 图像高度
输出参数 : out,YU12图片地址
返 回 值 : int类型
具体代码如下:
/*
***********************************************************************
* 文件名称:Nv12toYU12.c
* 文件描述:Nv12格式转YU12
* 作 者:Young Fan
*日 期:2021-09-16
************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*****************************************************************************
函 数 名: NV12toYU12
功能描述 : Nv12格式转YU12
输入参数 : data NV12图片数据指针
out 输出的YU12图片地址
width 图像宽度
height 图像高度
输出参数 : 光栅格式yuv数据
返 回 值 : int
*****************************************************************************/
int NV12toYU12(char *data, char *out, int width, int height)
{
if (data == NULL || out == NULL)
{
printf("error:empty pointer \n");
return -1;
}
if (width <= 0 || height <= 0)
{
printf("error:width or height is not positive \n");
return -1;
}
//分别获取NV12数据中的Y、U、V分量。NV12:YYYYYYYY UVUV => YU12: YYYYYYYY UU VV
//Y
memcpy(out, data, width * height);
printf("Y分量转换完成!\n");
//U
char * ptr1 = out + width * height; //YU12中U的首地址
char * ptr2 = data + width * height;
int n = 0;
while (n < width * height / 4)
{
//赋值
*(ptr1) = *(ptr2);
ptr1++;
ptr2 = ptr2 + 2;
n++;
}
printf("U分量转换完成!\n");
//V
ptr1 = out + width * height * 5 / 4; //YU12中V的首地址
ptr2 = data + width * height + 1;
n = 0;
while (n < width * height / 4)
{
//赋值
*(ptr1) = *(ptr2);
ptr1++;
ptr2 = ptr2 + 2;
n++;
}
printf("V分量转换完成!\n");
return 0;
}
int main(void)
{
int width = 512;
int height = 288;
int size = width * height * 3 / 2;
char *data = (char *)malloc(size);
char *out = (char *)malloc(size);
memset(data, 0, size);
memset(out, 0, size);
FILE *fp = fopen("./pic/NV12.yuv","rb");
fread(data, 1, size, fp);
int ret = NV12toYU12(data, out, width, height);
if (ret < 0)
{
printf("error: NV12toYU12 failed, ret %d\n", ret);
return -1;
}
//保存已转换好的YU12数据到本地
FILE *out_fp = fopen("./out_YU12.yuv", "wb");
fwrite(out, 1, size, out_fp);
printf("整体转换完成并将YU12图像保存在本地!\n");
//释放资源
fclose(fp);
fclose(out_fp);
if(data != NULL)
{
free(data);
data = NULL;
}
if(out != NULL)
{
free(out);
out = NULL;
}
return 0;
}
打印输出如下:
输出图片:
原图:
YU12转NV12
YU12转NV12转换接口实现为:
int YU12toNV12(unsigned char *src[3], unsigned char *dst, int width, int height);
功能描述 : YU12转NV12
输入参数 :
unsigned char *src[3] : YU12图片地址,这里使用的是Y、U、V三个分量地址独立分开的
unsigned char *dst :NV12图片地址
width: 图像宽度
height : 图像高度
输出参数 : dst,NV12图片地址
返 回 值 : int类型
代码如下:
static int YU12toNV12(unsigned char *src[3], unsigned char *dst, int width, int height)
{
if (src == NULL || dst == NULL)
{
printf("error:empty pointer \n");
return -1;
}
if (width <= 0 || height <= 0)
{
printf("error:width or height is not positive \n");
return -1;
}
//分别获取YU12数据中的Y、U、V分量。YU12: YYYYYYYY UU VV => NV12:YYYYYYYY UVUV
//Y
memcpy(dst, src[0], width * height);
printf("Y分量转换完成!\n");
//U
unsigned char * ptr1 = dst + width * height; //NV12中UV的首地址
unsigned char * ptr2 = src[1]; //YU12中U的首地址
unsigned char * ptr3 = src[2]; //YU12中V的首地址
int n = 0;
while (n < width * height / 4)
{
//赋值
*(ptr1) = *(ptr2);
ptr1++;
ptr2++;
*(ptr1) = *(ptr3);
ptr1++;
ptr3++;
n++;
}
printf("UV分量转换完成!\n");
return 0;
}