欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

比较YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P和YUV444P:理解并解析YUV420P的不同之处

最编程 2024-08-15 16:17:12
...

下面基于实例来理解Y,U,V分量的作用

先使用ffmpeg将指定的图片转为yuv420p格式

ffmpeg -i input.jpg -s 510x510 -pix_fmt yuv420p input.yuv
  • 分离YUV分量

笔者使用的Clion直接运行下面这段代码,分离出所需的文件

void split_yuv420(char *inputPath, int width, int height) {

    FILE *fp_yuv = fopen(inputPath, "rb+");

    FILE *fp_y = fopen("output_420_y.y", "wb+");
    FILE *fp_u = fopen("output_420_u.y", "wb+");
    FILE *fp_v = fopen("output_420_v.y", "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 3 / 2);

    fread(data, 1, width * height * 3 / 2, fp_yuv);
    //Y
    fwrite(data, 1, width * height, fp_y);
    //U
    fwrite(data + width * height, 1, width * height / 4, fp_u);
    //V
    fwrite(data + width * height * 5 / 4, 1, width * height / 4, fp_v);

    //释放资源
    free(data);

    fclose(fp_yuv);
    fclose(fp_y);
    fclose(fp_u);
    fclose(fp_v);
}

笔者使用的是ubuntu系统,因此运行yuvplayer.exe文件,需要提前安装好winesudo apt install wine,运行yuvplayer之后,需要先设置像素格式为Y,否则你看到的图像可能会有问题

先看output_420_y.y文件:(分辨率设置为510x510)

output_420_u.y显示如下:(分辨率设置为255x255)

output_420_v.y显示如下:(分辨率设置为255x255)

  • 生成灰度图

上面的例子实际上已经生成了一个灰度图了,但是只保留了Y分量,你如果直接用ffplay工具查看会有问题,下面的函数将会生成一个标准的YUV文件并且保留Y分量,你可能会有疑问,为什么U分量和V分量要写入0x80,其实你可以参考上面的YUV转RGB的公式,YUV数据是无法直接显示的,最终需要转成RGB显示,因此我这里是只需要保留Y分量,忽略UV分量的影响,因此根据上面的公式,我在U和V分量中都写入128就是十六进制的0x80

  • 保留Y分量(生成灰度图)
void yuv420p_y(char *inputPath, char *outputPath, int width, int height) {

    FILE *inFile = fopen(inputPath, "rb+");
    FILE *outFile = fopen(outputPath, "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 3 / 2);

    fread(data, 1, width * height * 3 / 2, inFile);

    //Y分量
    fwrite(data, 1, width * height, outFile);

    unsigned char *buffer = (unsigned char *) malloc(width * height / 4);
    memset(buffer, 0x80, width * height / 4);
    //U分量
    fwrite(buffer, 1, width * height / 4, outFile);
    //V分量
    fwrite(buffer, 1, width * height / 4, outFile);

    free(buffer);
    free(data);
    fclose(inFile);
    fclose(outFile);
}
int main() {

    yuv420p_y("/home/byhook/media/input.yuv", "/home/byhook/media/output.yuv", 510, 510);

    return 0;
}

使用ffplay来播放yuv格式的文件:

ffplay -f rawvideo -video_size 510x510 output.yuv

要注意这里的分辨率不能错