• YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24(转载)


      转自:http://www.latelee.org/my-study/yuv-learning-yuv420p-to-rgb24.html

      对于YUV420的格式,网上有一大堆资料,这里就不说了。直奔主题,给出如何转换的函数,一如既往,只用代码说事。
    YUV420有打包格式(Packed),一如前文所述。同时还有平面格式(Planar),即Y、U、V是分开存储的,每个分量占一块地方,其中Y为 width*height,而U、V合占Y的一半,该种格式每个像素占12比特。根据U、V的顺序,分出2种格式,U前V后即YUV420P,也叫 I420,V前U后,叫YV12(YV表示Y后面跟着V,12表示12bit)。另外,还有一种半平面格式(Semi-planar),即Y单独占一块地 方,但其后U、V又紧挨着排在一起,根据U、V的顺序,又有2种,U前V后叫NV12,在国内好像很多人叫它为YUV420SP格式;V前U后叫 NV21。这种格式似乎比NV16稍受欢迎。
    首先给出转换查询表的生成函数,代码是在网上找来的,如下:

    static long int crv_tab[256];   
    static long int cbu_tab[256];   
    static long int cgu_tab[256];   
    static long int cgv_tab[256];   
    static long int tab_76309[256]; 
    static unsigned char clp[1024];   //for clip in CCIR601   
    
    void init_yuv420p_table() 
    {   
        long int crv,cbu,cgu,cgv;   
        int i,ind;      
        static int init = 0;
    
        if (init == 1) return;
    
        crv = 104597; cbu = 132201;  /* fra matrise i global.h */   
        cgu = 25675;  cgv = 53279;   
       
        for (i = 0; i < 256; i++)    
        {   
            crv_tab[i] = (i-128) * crv;   
            cbu_tab[i] = (i-128) * cbu;   
            cgu_tab[i] = (i-128) * cgu;   
            cgv_tab[i] = (i-128) * cgv;   
            tab_76309[i] = 76309*(i-16);   
        }   
       
        for (i = 0; i < 384; i++)   
            clp[i] = 0;   
        ind = 384;   
        for (i = 0;i < 256; i++)   
            clp[ind++] = i;   
        ind = 640;   
        for (i = 0;i < 384; i++)   
            clp[ind++] = 255;
    
        init = 1;
    }
    

    下面给出YUV420平面格式的转换函数,如下:

    /**
    内存分布
                        w
                +--------------------+
                |Y0Y1Y2Y3...         |
                |...                 |   h
                |...                 |
                |                    |
                +--------------------+
                |U0U1      |
                |...       |   h/2
                |...       |
                |          |
                +----------+
                |V0V1      |
                |...       |  h/2
                |...       |
                |          |
                +----------+
                    w/2
     */
    void yuv420p_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)   
    {
        int y1, y2, u, v;    
        unsigned char *py1, *py2;   
        int i, j, c1, c2, c3, c4;   
        unsigned char *d1, *d2;   
        unsigned char *src_u, *src_v;
        static int init_yuv420p = 0;
        
        src_u = yuvbuffer + width * height;   // u
        src_v = src_u + width * height / 4;  //  v
    
        if (type == FMT_YV12)
        {
            src_v = yuvbuffer + width * height;   // v
            src_u = src_u + width * height / 4;  //  u
        }
        py1 = yuvbuffer;   // y
        py2 = py1 + width;   
        d1 = rgbbuffer;   
        d2 = d1 + 3 * width;   
    
        init_yuv420p_table();
    
        for (j = 0; j < height; j += 2)    
        {    
            for (i = 0; i < width; i += 2)    
            {
                u = *src_u++;   
                v = *src_v++;   
       
                c1 = crv_tab[v];   
                c2 = cgu_tab[u];   
                c3 = cgv_tab[v];   
                c4 = cbu_tab[u];   
       
                //up-left   
                y1 = tab_76309[*py1++];    
                *d1++ = clp[384+((y1 + c1)>>16)];     
                *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
                *d1++ = clp[384+((y1 + c4)>>16)];   
       
                //down-left   
                y2 = tab_76309[*py2++];   
                *d2++ = clp[384+((y2 + c1)>>16)];     
                *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
                *d2++ = clp[384+((y2 + c4)>>16)];   
       
                //up-right   
                y1 = tab_76309[*py1++];   
                *d1++ = clp[384+((y1 + c1)>>16)];     
                *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
                *d1++ = clp[384+((y1 + c4)>>16)];   
       
                //down-right   
                y2 = tab_76309[*py2++];   
                *d2++ = clp[384+((y2 + c1)>>16)];     
                *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
                *d2++ = clp[384+((y2 + c4)>>16)];   
            }
            d1  += 3*width;
            d2  += 3*width;
            py1 += width;
            py2 += width;
        }
    }
    

    再给出YUV420SP转换的函数,如下:

    void yuv420sp_to_rgb24(YUV_TYPE type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)   
    {
        int y1, y2, u, v;    
        unsigned char *py1, *py2;   
        int i, j, c1, c2, c3, c4;   
        unsigned char *d1, *d2;   
        unsigned char *src_u;
        static int init_yuv420p = 0;
    
        src_u = yuvbuffer + width * height;   // u
    
        py1 = yuvbuffer;   // y
        py2 = py1 + width;   
        d1 = rgbbuffer;   
        d2 = d1 + 3 * width;   
    
        init_yuv420p_table();
    
        for (j = 0; j < height; j += 2)    
        {    
            for (i = 0; i < width; i += 2)    
            {
                if (type ==  FMT_NV12)
                {
                    u = *src_u++;   
                    v = *src_u++;      // v紧跟u,在u的下一个位置
                }
                if (type == FMT_NV21)
                {
                    v = *src_u++;   
                    u = *src_u++;      // u紧跟v,在v的下一个位置
                }
    
                c1 = crv_tab[v];   
                c2 = cgu_tab[u];   
                c3 = cgv_tab[v];   
                c4 = cbu_tab[u];   
    
                //up-left   
                y1 = tab_76309[*py1++];    
                *d1++ = clp[384+((y1 + c1)>>16)];     
                *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
                *d1++ = clp[384+((y1 + c4)>>16)];   
    
                //down-left   
                y2 = tab_76309[*py2++];   
                *d2++ = clp[384+((y2 + c1)>>16)];     
                *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
                *d2++ = clp[384+((y2 + c4)>>16)];   
    
                //up-right   
                y1 = tab_76309[*py1++];   
                *d1++ = clp[384+((y1 + c1)>>16)];     
                *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
                *d1++ = clp[384+((y1 + c4)>>16)];   
    
                //down-right   
                y2 = tab_76309[*py2++];   
                *d2++ = clp[384+((y2 + c1)>>16)];     
                *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
                *d2++ = clp[384+((y2 + c4)>>16)];   
            }
            d1  += 3*width;
            d2  += 3*width;
            py1 += width;
            py2 += width;
        }
    }
    

    参考资料:
    http://www.fourcc.org/yuv.php
    https://wiki.videolan.org/YUV/

    李迟 2015.8.5 晚上

    本文固定链接: http://www.latelee.org/my-study/yuv-learning-yuv420p-to-rgb24.html

  • 相关阅读:
    Redis学习手册(String数据类型)
    Redis学习手册(开篇)
    android判断当前应用程序处于前台还是后台
    android EditText输入变化事件详解
    Android. Scrolling 2 listviews together
    Android ListView快速定位(四)
    使用【百度云推送】第三方SDK实现推送功能具体解释
    SDN:软件定义网络
    MATLAB中导入数据:importdata函数
    JSP中Session的使用
  • 原文地址:https://www.cnblogs.com/lance-ehf/p/5310092.html
Copyright © 2020-2023  润新知