• 摄像头V4L2获取的YUY2格式转YUV420格式


    摄像头取出格式YUY2(YUYV)

    Y   U00Y    V00Y   U01Y    V01Y   U02Y   V02Y   U03Y   V03
    YU10YV10YU11YV11YU12YV12YU13YV13
    YU20YV20YU21YV21YU22YV22YU23YV23
    YU30YV30YU31YV31YU32YV32YU33YV33

    转为 NV12(YUV420) 

    这里的转化主要是我的电脑软件pyuv 只支持yuv420格式的预览

    另一方面主要是因为 ffmpeg 中进行编码时,采用的是 AV_PIX_FMT_YUV420P.

    也是需要把摄像头中的YUYV转化为 ffmpeg 支持的YUV420P格式

    Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  Y  
    YYYYYYYYYYYYYYYY
    U00U01U02U03U20U21U22U23V00V01V02V03V20V21V22V23

    这里转换主要为需要隔1整行取出1整行的UV数据,而不是间隔一个一个取。

    可以看出丢失了一部分UV数据,只要Y数据没有丢失,图像会依然保持完整呈现。

    转换代码:

    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #define CAM_W 640
    #define CAM_H 480

    typedef struct{
        char y1;
        char u;
        char y2;
        char v;
    }TAG_YUY2;

    static int YUYV_TO_NV12(unsigned char yuyv_in[], unsigned char* out){
        TAG_YUY2 *p_yuy2;
        int yuy2_size = CAM_W*CAM_H;
        int i = 0;
        int j = 0;
        int total = CAM_W*CAM_H*2;
        int tag_size = CAM_W*CAM_H/2;
        p_yuy2 = (TAG_YUY2 *)malloc(total);
        memcpy(p_yuy2, yuyv_in, total);
        
        i=0;
        j=0;
        int n = 0;
        for(i=0; i         out[j++] = p_yuy2[i].y1;
            out[j++] = p_yuy2[i].y2;
        }
        int pos = 0;
        int x = 0;
        int y = 0;
        int len_x = CAM_W/2;
        for(y = 0; y < CAM_H; y+=2){ // 每2行取一次值 u
            for(x = 0; x < len_x; x++){
                out[j++] = p_yuy2[y*len_x + x].u;
            }
        }
        for(y = 0; y < CAM_H; y+=2){ // 每2行取一次值 v
            for(x = 0; x < len_x; x++){
                out[j++] = p_yuy2[y*len_x + x].v;
            }
        }
        free(p_yuy2);
        return (CAM_W*CAM_H*3/2);
    }

    int main(){
        int result;
        FILE *fp_yuyv = fopen("frame.yuv", "rb");
        FILE *fp_nv21 = fopen("nv21.yuv", "wb");
        
        unsigned char* buf_yuv = (unsigned char*)malloc(CAM_W*CAM_H*2);
        unsigned char* nv21 = (unsigned char*)malloc(CAM_W*CAM_H*2);

        fread(buf_yuv, 1, CAM_W*CAM_H*2, fp_yuyv);

        memset(nv21, 0, CAM_W*CAM_H*2);
        result = YUYV_TO_NV12(buf_yuv, nv21);

        fwrite(nv21, 1, result, fp_nv21);
        
        free(buf_yuv);
        free(nv21);
        
        fclose(fp_yuyv);
        fclose(fp_nv21);
        return 0;
    }

    整个转换的核心是隔行采样 UV 数据, 而不是间隔1个UV单位采样。

  • 相关阅读:
    Ubuntu 22.04上安装Anaconda,及 conda 的基础使用
    C语言实现输入 n 个字符串,将它们按字母由小到大的顺序排列并输出
    2024牛客寒假算法基础集训营1(补题)
    【JavaScript保姆级教程】输出函数和初识变量
    Python自动化笔记-Allure
    上周热点回顾(6.24-6.30)
    SElinux avc dennied权限问题解决方法
    如何进行编译和链接操作?
    MES系统管理范围及标准
    架构师必修系列:MVC、MVP、MVVM 三者的区别介绍
  • 原文地址:https://blog.csdn.net/dreamInTheWorld/article/details/126267677