C realizes the mutual conversion between YUV420SP (NV12) and (NV21)

YUV, divided into three components, "Y" represents the brightness (Luminance or Luma), which is the gray value; while "U" and "V" represent the chroma (Chrominance or Chroma), which is used to describe the image Hue and Saturation, used to specify the color of the pixel.

The length of YUV420 data, Y = width*height, U = width*height/4, V = width*height/4.

The arrangement order of NV12 data is: YYYYYYYYY......, UVUVUV.......

The arrangement order of NV21 data is: YYYYYYYYY......, VUVUVU.......

So the conversion between NV12 and NV21 is: the front width*height data remains unchanged, and the rear width*height/2 data is swapped. The implementation code is as follows:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include<errno.h>

int main(int argc, char const *argv[])
{
    FILE *fp = NULL;
    FILE *fp_w = NULL;
    int fp_size = 0;

    fp = fopen("nv12_720p.yuv","rb");
    if(NULL == fp)
    {
        printf("open is error\n");
        return 1;
    }

    fseek(fp, 0, SEEK_END);
    fp_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);	
    char *nv12_1 = (char *)malloc(fp_size);
    char *nv21_1 = (char *)malloc(fp_size);
    char *nv12 = nv12_1;  
    char *nv21 = nv21_1;  
    fread(nv12, 1, fp_size, fp);
    int framesize = 1280*720;   //12和21前面一部分的大小的数据是一样的,即宽*高的部分的数据是一样的
    int i = 0,j = 0;

    memcpy(nv21, nv12, framesize);
    
    for(i = 0; i < framesize; i++){
        nv21[i] = nv12[i];      //前面宽*高的数据是一样的
    }
    
    //NV12 宽*高 后的数据是:UVUVUV...,UV总的数据是 宽*高/2 。现在把V放在 宽*高 后的第一个位置,+2奇数位置。
    for (j = 0; j < framesize/2; j+=2)
    {
        nv21[framesize + j - 1] = nv12[j+framesize];  
    }

    //NV12 宽*高 后的数据是:UVUVUV...,UV总的数据是 宽*高/2 。现在把U放在 宽*高 后的第二个位置,+2偶数数位置。
    for (j = 0; j < framesize/2; j+=2)
    {
        nv21[framesize + j] = nv12[j+framesize-1]; 
    }

    fclose(fp);
    fp_w = fopen("nv21_720p.yuv","w");
    fwrite(nv21, 1, fp_size, fp_w);
    fclose(fp_w);

    if(nv12_1 != NULL){
        free(nv12_1);
        nv12_1 = NULL;
    }
    if(nv21_1 != NULL){
        free(nv21_1);
        nv21_1 = NULL;
    }

    return 0;
}

Before conversion:

After conversion:

Guess you like

Origin blog.csdn.net/weixin_42432281/article/details/104260117