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数据

原文地址:https://www.cnblogs.com/y4247464/p/14391676.html