zoukankan      html  css  js  c++  java
  • YUV420sp

    基本概念见:

    一文读懂 YUV 的采样与格式

    音视频编解码: YUV存储格式中的YUV420P,YUV420SP,NV12, NV21理解(转)

    摘录一些笔记:

    RGB与YUV的转换

    对于图像显示器来说,它是通过 RGB 模型来显示图像的,而在传输图像数据时又是使用 YUV 模型,这是因为 YUV 模型可以节省带宽。因此就需要采集图像时将 RGB 模型转换到 YUV 模型,显示时再将 YUV 模型转换为 RGB 模型。

    YUV的采样格式

    1. YUV 444
        //表示色度频道没有下采样
    2. YUV 422
        // 表示 2:1 的水平下采样,没有垂直下采样。
        //对于每两个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。
    3. YUV 420
        //表示 2:1 的水平下采样,2:1 的垂直下采样。

    YUV的存储格式

    1. planar 平面格式
        //指先连续存储所有像素点的 Y 分量,然后存储 U 分量,最后是 V 分量。
        //将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素;
    2. packed 打包模式
       // 指每个像素点的 Y、U、V 分量是连续交替存储的。
       // 使用三个数组分开存放YUV三个分量,就像是一个三维平面一样

    YUV 4:2:0

     YUV 4:2:0 并不意味着不采样 V 分量。它指的是对每条扫描线来说,只有一种色度分量以 2:1 的采样率存储,相邻的扫描行存储不同的色度分量。也就是说,如果第一行是 4:2:0,下一行就是 4:0:2,在下一行就是 4:2:0,以此类推。

     

    图像像素为:
    [Y0 U0 V0]、[Y1 U1 V1]、 [Y2 U2 V2]、 [Y3 U3 V3]
    [Y5 U5 V5]、[Y6 U6 V6]、 [Y7 U7 V7] 、[Y8 U8 V8]
    ​
    采样的码流为:
    Y0 U0 Y1 Y2 U2 Y3 
    Y5 V5 Y6 Y7 V7 Y8
    ​
    映射出的像素点为:
    [Y0 U0 V5]、[Y1 U0 V5]、[Y2 U2 V7]、[Y3 U2 V7]
    [Y5 U0 V5]、[Y6 U0 V5]、[Y7 U2 V7]、[Y8 U2 V7]

    更形象的图如下:YUV420 SP nv12

     yuv420sp 的存储数据分布

     其在码流中的表现形式:

     如上图,假设这是一个6*4像素大小的图片

      1 #include <stdio.h>
      2 #define READ_MAX (1024)
      3  
      4 typedef unsigned char  uInt8;
      5 typedef unsigned short uInt16;
      6 typedef unsigned int uInt32;
      7 typedef char Int8;
      8 typedef short Int16;
      9 typedef int Int32;
     10  
     11 typedef enum
     12 {
     13     TYPE_YUV422I_UYVY,
     14     TYPE_YUV422I_YUYV,
     15     TYPE_YUV420SP_NV12,
     16     TYPE_YUV420SP_NV21,
     17     TYPE_YUV422P,
     18     TYPE_YUV444I,
     19     TYPE_YUV444P,
     20 }enYuvType;
     21  
     22 typedef enum
     23 {
     24     YUV_GREEN,
     25     YUV_RED,
     26     YUV_BLUE,
     27     YUV_PURPLE,
     28     YUV_DARK_GREEN,
     29     YUV_YELLOW,
     30     YUV_LIGHT_BLUE,
     31     YUV_LIGHT_PURPLE,
     32     YUV_DARK_BLACK,
     33     YUV_GRAY,
     34     YUV_WHITE,
     35     YUV_COLOR_MAX,
     36 }enYuvColorIdx;
     37  
     38 typedef struct
     39 {
     40     uInt8 Y;
     41     uInt8 U;
     42     uInt8 V;
     43 }stYuvColor;
     44  
     45 typedef struct
     46 {
     47     uInt16 x;
     48     uInt16 y;
     49 }stPoint;
     50  
     51 typedef struct
     52 {
     53     stPoint startPoint;
     54     stPoint endPoint;
     55     uInt16 lineWidth;
     56     enYuvColorIdx clrIdx;
     57 }stDrawLineInfo;
     58  
     59 typedef struct
     60 {
     61     enYuvType yuvType;
     62     uInt8 *pYuvBuff;
     63     uInt16 width;
     64     uInt16 height;
     65 }stYuvBuffInfo;
     66  
     67 static stYuvColor s_color_table[YUV_COLOR_MAX] = {
     68     {0x00, 0x00, 0x00}, // green
     69     {0x00, 0x00, 0xff}, // red
     70     {0x00, 0xff, 0x00},    // blue
     71     {0x00, 0xff, 0xff},    // purple
     72     {0xff, 0x00, 0x00}, // dark green
     73     {0xff, 0x00, 0xff}, // yellow
     74     {0xff, 0xff, 0x00}, // light blue
     75     {0xff, 0xff, 0xff}, // light purple
     76     {0x00, 0x80, 0x80}, // dark black
     77     {0x80, 0x80, 0x80}, // gray
     78     {0xff, 0x80, 0x80}, // white
     79 };
     80  
     81 Int32 read_file(const char* file, uInt8 *pOut)
     82 {
     83     Int32 size = 0;
     84     uInt8 *p = pOut;
     85     FILE* fp = fopen(file, "rb");
     86     if(fp && pOut) {
     87         int n = 0;
     88         while((n = fread(p, 1, READ_MAX, fp)) > 0) {
     89             size += n;
     90             p += n;
     91             if(n < READ_MAX)
     92                 break;
     93         }
     94         fclose(fp);
     95         printf("    %s, size = %d
    ", file, size);
     96     }
     97     else {
     98         printf("Open %s png file fail
    ", file);
     99     }
    100  
    101     return size;
    102 }
    103  
    104  
    105 void yuv_setdata(
    106     uInt8* YBuff,
    107     uInt8* UVBuff,
    108     enYuvType yuvType,
    109     uInt16 width,
    110     uInt16 height,
    111     stPoint draw_point,
    112     enYuvColorIdx clrIdx)
    113 {
    114     switch(yuvType)
    115     {
    116         case TYPE_YUV422I_UYVY:
    117         case TYPE_YUV422I_YUYV:
    118         {
    119             /*
    120                 UYVY UYVY UYVY UYVY
    121             */
    122             uInt32 tmp = draw_point.y * width * 2;
    123             uInt32 y_offset = 0, u_offset = 0, v_offset = 0;
    124             if(yuvType == TYPE_YUV422I_UYVY) {
    125                 u_offset = tmp + draw_point.x / 2 * 4;
    126                 v_offset = u_offset + 2;
    127                 y_offset = u_offset + 1;
    128             }
    129             else {
    130                 y_offset = tmp + draw_point.x / 2 * 4;
    131                 u_offset = y_offset + 1;
    132                 v_offset = u_offset + 2;
    133             }
    134             YBuff[y_offset] = s_color_table[clrIdx].Y;
    135             YBuff[y_offset + 2] = s_color_table[clrIdx].Y;
    136             YBuff[u_offset] = s_color_table[clrIdx].U;
    137             YBuff[v_offset] = s_color_table[clrIdx].V;
    138         }break;
    139         case TYPE_YUV420SP_NV12:
    140         case TYPE_YUV420SP_NV21:
    141         {
    142             /*
    143                 YY YY
    144                 YY YY
    145                 UV UV
    146             */
    147             uInt32 y_offset = draw_point.y * width + draw_point.x;
    148             uInt32 u_offset = 0, v_offset = 0;
    149             YBuff[y_offset] = s_color_table[clrIdx].Y;
    150             #if 0
    151             Int32 x_flag = 1, y_flag = 1;
    152             if(draw_point.y % 2 == 0) {
    153                 YBuff[y_offset + width] = s_color_table[clrIdx].Y;
    154                 y_flag = 1;
    155             }
    156             else {
    157                 YBuff[y_offset - width] = s_color_table[clrIdx].Y;
    158                 y_flag = -1;
    159             }
    160  
    161             if(draw_point.x % 2 == 0) {
    162                 YBuff[y_offset + 1] = s_color_table[clrIdx].Y;
    163                 x_flag = 1;
    164             }
    165             else {
    166                 YBuff[y_offset - 1] = s_color_table[clrIdx].Y;
    167                 x_flag = -1;
    168             }
    169             YBuff[y_offset + width * y_flag + 1 * x_flag] = s_color_table[clrIdx].Y;
    170             #endif
    171             
    172             if(yuvType == TYPE_YUV420SP_NV12) {
    173                 u_offset = (draw_point.y / 2) * width + draw_point.x / 2 * 2;
    174                 v_offset = u_offset + 1;
    175             }
    176             else {
    177                 v_offset = (draw_point.y / 2) * width + draw_point.x / 2 * 2;
    178                 u_offset = v_offset + 1;
    179             }
    180             UVBuff[u_offset] = s_color_table[clrIdx].U;
    181             UVBuff[v_offset] = s_color_table[clrIdx].V;
    182             //printf("[%d, %d]: y_offset = %d, u_offset = %d, v_offset = %d
    ",
    183             //    draw_point.x, draw_point.y, y_offset, u_offset, v_offset);
    184         }break;
    185         case TYPE_YUV444P:
    186         {
    187             /*
    188                 YYYYYYYY
    189                 UUUUUUUU
    190                 VVVVVVVV
    191             */
    192             uInt32 y_offset = 0, u_offset = 0, v_offset = 0;
    193             uInt32 plane_size = width * height;
    194             y_offset = draw_point.y * width + draw_point.x;
    195             u_offset = y_offset;
    196             v_offset = plane_size + u_offset;
    197             YBuff[y_offset] = s_color_table[clrIdx].Y;
    198             UVBuff[u_offset] = s_color_table[clrIdx].U;
    199             UVBuff[v_offset] = s_color_table[clrIdx].V;
    200         }break;
    201         case TYPE_YUV444I:
    202         {
    203             /*
    204                 YUV YUV YUV YUV YUV YUV YUV YUV
    205             */
    206             uInt32 y_offset = 0, u_offset = 0, v_offset = 0;
    207             y_offset = draw_point.y * width * 3 + draw_point.x * 3;
    208             u_offset = y_offset + 1;
    209             v_offset = u_offset + 1;
    210             YBuff[y_offset] = s_color_table[clrIdx].Y;
    211             YBuff[u_offset] = s_color_table[clrIdx].U;
    212             YBuff[v_offset] = s_color_table[clrIdx].V;
    213         }break;
    214         case TYPE_YUV422P:
    215         {
    216             /*
    217                 YYYYYYYY
    218                 UUUU
    219                 VVVV
    220             */
    221             uInt32 y_offset = 0, u_offset = 0, v_offset = 0;
    222             uInt32 plane_size = width * height / 2;
    223             y_offset = draw_point.y * width + draw_point.x;
    224             u_offset = (draw_point.y / 2) * width + draw_point.x / 2;
    225             v_offset = plane_size + u_offset;
    226             YBuff[y_offset] = s_color_table[clrIdx].Y;
    227             UVBuff[u_offset] = s_color_table[clrIdx].U;
    228             UVBuff[v_offset] = s_color_table[clrIdx].V;
    229         }break;
    230     }
    231 }
    232  
    233 void yuv_drawline(stYuvBuffInfo *pYuvBuffInfo, stDrawLineInfo *pDrawLineInfo)
    234 {
    235     if(!pYuvBuffInfo || !pYuvBuffInfo->pYuvBuff) return;
    236  
    237     uInt8 *YBuff = NULL, *UVBuff = NULL;
    238     uInt16 x0 = pDrawLineInfo->startPoint.x, y0 = pDrawLineInfo->startPoint.y;
    239     uInt16 x1 = pDrawLineInfo->endPoint.x, y1 = pDrawLineInfo->endPoint.y;
    240  
    241     if(pDrawLineInfo->lineWidth == 0) pDrawLineInfo->lineWidth = 1;
    242     x0 = (x0 >= pYuvBuffInfo->width) ? (x0 - pDrawLineInfo->lineWidth) : x0;
    243     x1 = (x1 >= pYuvBuffInfo->width) ? (x1 - pDrawLineInfo->lineWidth) : x1;
    244     y0 = (y0 >= pYuvBuffInfo->height) ? (y0 - pDrawLineInfo->lineWidth) : y0;
    245     y1 = (y1 >= pYuvBuffInfo->height) ? (y1 - pDrawLineInfo->lineWidth) : y1;
    246  
    247     uInt16 dx = (x0 > x1) ? (x0 - x1) : (x1 - x0);
    248     uInt16 dy = (y0 > y1) ? (y0 - y1) : (y1 - y0);
    249  
    250     Int16 xstep = (x0 < x1) ? 1 : -1;
    251     Int16 ystep = (y0 < y1) ? 1 : -1;
    252     Int16 nstep = 0, eps = 0;
    253  
    254     stPoint draw_point;
    255     draw_point.x = x0;
    256     draw_point.y = y0;
    257  
    258     switch(pYuvBuffInfo->yuvType)
    259     {
    260         case TYPE_YUV422I_UYVY:
    261         case TYPE_YUV422I_YUYV:
    262         case TYPE_YUV444I:
    263         {
    264             YBuff = pYuvBuffInfo->pYuvBuff;
    265             UVBuff = NULL;
    266         }break;
    267         case TYPE_YUV420SP_NV12:
    268         case TYPE_YUV420SP_NV21:
    269         case TYPE_YUV444P:
    270         case TYPE_YUV422P:
    271         {
    272             YBuff = pYuvBuffInfo->pYuvBuff;
    273             UVBuff = pYuvBuffInfo->pYuvBuff + pYuvBuffInfo->width * pYuvBuffInfo->height;
    274         }break;
    275         default:
    276             return;
    277     }
    278  
    279     // 布雷森汉姆算法画线
    280     if(dx > dy){
    281         while(nstep <= dx) {
    282             yuv_setdata(YBuff, UVBuff, pYuvBuffInfo->yuvType, pYuvBuffInfo->width, pYuvBuffInfo->height, draw_point, pDrawLineInfo->clrIdx);
    283             eps += dy;
    284             if( (eps << 1) >= dx ) {
    285                 draw_point.y += ystep;
    286                 eps -= dx;
    287             }
    288             draw_point.x += xstep;
    289             nstep++;
    290         }
    291     }else {
    292         while(nstep <= dy){    
    293             yuv_setdata(YBuff, UVBuff, pYuvBuffInfo->yuvType, pYuvBuffInfo->width, pYuvBuffInfo->height, draw_point, pDrawLineInfo->clrIdx);
    294             eps += dx;
    295             if( (eps << 1) >= dy ) {
    296                 draw_point.x += xstep;
    297                 eps -= dy;
    298             }
    299             draw_point.y += ystep;
    300             nstep++;
    301         }
    302     }
    303 }
    304  
    305 void draw_rect(stYuvBuffInfo* yuvBuffInfo)
    306 {
    307     stDrawLineInfo drawLineInfo;
    308     drawLineInfo.clrIdx = YUV_RED;
    309     drawLineInfo.lineWidth = 1;
    310     drawLineInfo.startPoint.x = 160;
    311     drawLineInfo.startPoint.y = 140;
    312     drawLineInfo.endPoint.x = 560;
    313     drawLineInfo.endPoint.y = 340;
    314     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    315  
    316     drawLineInfo.clrIdx = YUV_PURPLE;
    317     drawLineInfo.lineWidth = 1;
    318     drawLineInfo.startPoint.x = 560;
    319     drawLineInfo.startPoint.y = 140;
    320     drawLineInfo.endPoint.x = 160;
    321     drawLineInfo.endPoint.y = 340;
    322     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    323  
    324     drawLineInfo.clrIdx = YUV_YELLOW;
    325     drawLineInfo.lineWidth = 1;
    326     drawLineInfo.startPoint.x = 160;
    327     drawLineInfo.startPoint.y = 140;
    328     drawLineInfo.endPoint.x = 560;
    329     drawLineInfo.endPoint.y = 140;
    330     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    331  
    332     drawLineInfo.clrIdx = YUV_GREEN;
    333     drawLineInfo.lineWidth = 1;
    334     drawLineInfo.startPoint.x = 160;
    335     drawLineInfo.startPoint.y = 140;
    336     drawLineInfo.endPoint.x = 160;
    337     drawLineInfo.endPoint.y = 340;
    338     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    339  
    340     drawLineInfo.clrIdx = YUV_BLUE;
    341     drawLineInfo.lineWidth = 1;
    342     drawLineInfo.startPoint.x = 160;
    343     drawLineInfo.startPoint.y = 340;
    344     drawLineInfo.endPoint.x = 560;
    345     drawLineInfo.endPoint.y = 340;
    346     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    347  
    348     drawLineInfo.clrIdx = YUV_WHITE;
    349     drawLineInfo.lineWidth = 1;
    350     drawLineInfo.startPoint.x = 560;
    351     drawLineInfo.startPoint.y = 140;
    352     drawLineInfo.endPoint.x = 560;
    353     drawLineInfo.endPoint.y = 340;
    354     yuv_drawline(yuvBuffInfo, &drawLineInfo);
    355 }
    356  
    357 void main(int argc, char** argv)
    358 {
    359     stYuvBuffInfo yuvBuffInfo;
    360     uInt8 *pBuff = (uInt8*)malloc(sizeof(uInt8) * 10 * 0x100000); // 10M
    361     // 测试 NV12 格式
    362     Int32 size = read_file("yuv_data.nv12", pBuff);
    363     yuvBuffInfo.pYuvBuff = pBuff;
    364     yuvBuffInfo.width = 720;
    365     yuvBuffInfo.height = 480;
    366     yuvBuffInfo.yuvType = TYPE_YUV420SP_NV12;
    367     draw_rect(&yuvBuffInfo);
    368     FILE* fp_save = fopen("./yuv_data_line.nv12", "wb+");
    369     fwrite(pBuff, size, 1, fp_save);
    370     fclose(fp_save);
    371  
    372     // 测试UYVY 格式
    373     memset(pBuff, 0, sizeof(uInt8) * 10 * 0x100000);
    374     size = read_file("yuv_data.uyvy", pBuff);
    375     yuvBuffInfo.pYuvBuff = pBuff;
    376     yuvBuffInfo.width = 720;
    377     yuvBuffInfo.height = 480;
    378     yuvBuffInfo.yuvType = TYPE_YUV422I_UYVY;
    379     draw_rect(&yuvBuffInfo);
    380     fp_save = fopen("./yuv_data_line.uyvy", "wb+");
    381     fwrite(pBuff, size, 1, fp_save);
    382  
    383     // 测试 NV21 格式
    384     size = read_file("yuv_data.nv21", pBuff);
    385     yuvBuffInfo.pYuvBuff = pBuff;
    386     yuvBuffInfo.width = 720;
    387     yuvBuffInfo.height = 480;
    388     yuvBuffInfo.yuvType = TYPE_YUV420SP_NV21;
    389     draw_rect(&yuvBuffInfo);
    390     fp_save = fopen("./yuv_data_line.nv21", "wb+");
    391     fwrite(pBuff, size, 1, fp_save);
    392     fclose(fp_save);
    393  
    394     // 测试YUYV 格式
    395     memset(pBuff, 0, sizeof(uInt8) * 10 * 0x100000);
    396     size = read_file("yuv_data.yuyv", pBuff);
    397     yuvBuffInfo.pYuvBuff = pBuff;
    398     yuvBuffInfo.width = 720;
    399     yuvBuffInfo.height = 480;
    400     yuvBuffInfo.yuvType = TYPE_YUV422I_YUYV;
    401     draw_rect(&yuvBuffInfo);
    402     fp_save = fopen("./yuv_data_line.yuyv", "wb+");
    403     fwrite(pBuff, size, 1, fp_save);
    404  
    405     // 测试YUV444P 格式
    406     memset(pBuff, 0, sizeof(uInt8) * 10 * 0x100000);
    407     size = read_file("yuv_data.yuv444p", pBuff);
    408     yuvBuffInfo.pYuvBuff = pBuff;
    409     yuvBuffInfo.width = 720;
    410     yuvBuffInfo.height = 480;
    411     yuvBuffInfo.yuvType = TYPE_YUV444P;
    412     draw_rect(&yuvBuffInfo);
    413     fp_save = fopen("./yuv_data_line.yuv444p", "wb+");
    414     fwrite(pBuff, size, 1, fp_save);
    415  
    416     // 测试YUV444I 格式
    417     memset(pBuff, 0, sizeof(uInt8) * 10 * 0x100000);
    418     size = read_file("yuv_data.yuv444i", pBuff);
    419     yuvBuffInfo.pYuvBuff = pBuff;
    420     yuvBuffInfo.width = 720;
    421     yuvBuffInfo.height = 480;
    422     yuvBuffInfo.yuvType = TYPE_YUV444I;
    423     draw_rect(&yuvBuffInfo);
    424     fp_save = fopen("./yuv_data_line.yuv444i", "wb+");
    425     fwrite(pBuff, size, 1, fp_save);
    426  
    427     // 测试YUV422P 格式
    428     memset(pBuff, 0, sizeof(uInt8) * 10 * 0x100000);
    429     size = read_file("yuv_data.yuv422p", pBuff);
    430     yuvBuffInfo.pYuvBuff = pBuff;
    431     yuvBuffInfo.width = 720;
    432     yuvBuffInfo.height = 480;
    433     yuvBuffInfo.yuvType = TYPE_YUV422P;
    434     draw_rect(&yuvBuffInfo);
    435     fp_save = fopen("./yuv_data_line.yuv422p", "wb+");
    436     fwrite(pBuff, size, 1, fp_save);
    437     
    438     fclose(fp_save);
    439     free(pBuff);
    440     return;
    441
    各种YUV格式的画线实现

    海思多媒体(MPP)开发(8)——获取VI中的YUV数据

  • 相关阅读:
    cuda cdnn 安装
    神经网络的例子
    理解pytorch几个高级选择函数(如gather)
    opencv 膨胀和腐蚀
    PyPDF2
    百度ocr
    opencv 代码集合
    tesseract cuda pytorch安装
    Vue路由钩子 afterEach beforeEach区别
    (转载)中文区位码、国标码、机内码、输入码、字形码
  • 原文地址:https://www.cnblogs.com/y4247464/p/14391676.html
Copyright © 2011-2022 走看看