本文不讲FFmpeg,而是讲YUV图像格式。因为摄像头拍摄出来的原始图像一般都是YUV格式。在FFmpeg中,视频是通过多张YUV图像而得到。

YUV图像格式是什么,这个可以看一下维基百科。这个超链接打开即可,无需细看。因为看了也不会懂YUV格式是什么。不信的话,我问你,对于耳熟能详的RGB格式,你懂了吗?你除了“用红绿蓝表示各种颜色,并且R、G、B一般用一个字节来存储”还懂其他吗?估计不能再说东西了吧。对于YUV也是这样,所以没必要看了。

YUV中的Y、U、V三个分量分别表示明亮度、色度、浓度,每一个分量也是用一个字节来存放的。我们在学习一样新东西时,总是喜欢拿之前学习过的东西作类比,或者想知道新旧东西的关联,下面就给出YUV和RGB两者相互转换的公式:

从公式中可以看到,两者进行转换的时候,可能会发生溢出。这个在计算的时候需要注意。处理的方法是截断。比如大于255的,就将之设255.小于0的,其值为0.

YUV格式是有很多种的。比较常见的有YUV4:4:4、YUV4:2:0、YUV4:2:2。后两种又可以细分成几种的,比如YUV422有YUYV422、UYVY422、YUV422P等。晕了吧~~

其实只需记得:

  1. YUV 4:4:4采样,每一个Y对应一组UV分量。
  2. YUV 4:2:2采样,每两个Y共用一组UV分量。
  3. YUV 4:2:0采样,每四个Y共用一组UV分量。

维基百科关于他们的布局说明:

  • 4:4:4表示完全取样。
  • 4:2:2表示2:1的水平取样,垂直完全采样。
  • 4:2:0表示2:1的水平取样,2:1垂直采样。
  • 4:1:1表示4:1的水平取样,垂直完全采样。

布局示意图可以参考链接1链接2

上面的只是逻辑布局,但作为码农更想知道他们的物理布局(存储方式),因为要读取数据。这要先了解两个概念:planar和packed。在RGB格式中,假如有3个像素点,那么既可以这样存:RGBRGBRGB,也可以RRRGGGBBB。前面一种称为packed(打包模式),后面一种称为planner(平行模式)。同样对应YUV也是有这两种模式的。

对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。对于packed的YUV格式,每个像素点的Y,U,V是连续交叉存储的。

在FFmpeg中,已经定义了这两种模式。可以查看pixfmt.h文件。每一种图像格式,都会对应的说明是哪种模式的。

(1)YUYV422:  packed模式

(2)UYVY422:  packed模式(只是排列方式和前面的不同)

(3)YUV422P: planner模式

(4)YUV420P: planner模式

这里还有一个问题要注意:对于一个width * height的YUV图像,占有多大的字节。这关乎到读取一个YUV文件时,要读多少字节才能把一张图像完全读进内存。对于不同的YUV格式,有不同的大小。

对于YUV422来说,是两个y共享一对u和v。所以y0  u y1  v(YUYV422)这4个字节存储的内存代表了两个像素(y0, u, v) 和(y1, u, v)。所以,4比2的关系,所以一个像素会占两个字节,所以对应YUV422来说要width * height * 2个字节。

在FFmpeg中,有一个函数,可以直接算这个大小的,函数的输入参数就是图像的格式、图像的width和height。下一篇博文会说到这个函数。

好了,扯了这么多,要写些代码才能满足码农。

这个例子先在YUV文件中读取一个图像,然后转换成RGB24格式,最后用OpenCV播放图像,可以达到视频的效果。

  1. #include<stdio.h>
  2. #include<highgui.h> //for OpenCV
  3.  
  4. //转换函数
  5. void YUV2RGB(int y, int u, int v, int* r, int* g, int* b)
  6. {
  7. assert( r != NULL && g != NULL && b != NULL);
  8.  
  9. *r = y + 1.13983 * (v - );
  10. *g = y - 0.39465 * (u - ) - 0.58060 * (v - );
  11. *b = y + 2.03211 * (u - );
  12.  
  13. *r = *r > ? : *r;
  14. *r = *r < ? : *r;
  15.  
  16. *g = *g > ? : *g;
  17. *g = *g < ? : *g;
  18.  
  19. *b = *b > ? : *b;
  20. *b = *b < ? : *b;
  21. }
  22.  
  23. //把RGB数据填充到OpenCV的IplImage结构体成员imageData中
  24. //imageData是一个数组,其用来存放每一个像素点的BGR。
  25. //其排列的形式很简单(BGR)(BGR)(BGR)(BGR)(BGR)
  26. void fillImage(IplImage* pimg, int r, int g, int b)
  27. {
  28. static int h = , w = ;
  29.  
  30. //这里是BGR的顺序。因为OpenCV存放像素的顺序的BGRBGRBGR
  31. pimg->imageData[h*pimg->widthStep + w++] = b;
  32. pimg->imageData[h*pimg->widthStep + w++] = g;
  33. pimg->imageData[h*pimg->widthStep + w++] = r;
  34.  
  35. //这部分代码是和OpenCV的一些性质有关,如果看不懂,可以忽略。
  36. //上面的pimg->widthStep也是与OpenCV的性质有关
  37. if( w/ >= pimg->width )
  38. {
  39. w = ;
  40. if( h == pimg->height - )
  41. h = ;
  42. else
  43. ++h;
  44. }
  45. }
  46.  
  47. void convertImage(IplImage* pimg, unsigned char* yuv_buff, int len)
  48. {
  49. int i;
  50. int r, g, b;
  51. int y0, y1, u, v;
  52.  
  53. for(i = ; i < len; i += )
  54. {
  55. //其排列方式是y0 u y1 v
  56. //直接提取出来y、u、v三个分量,然后使用公式转成RGB即可
  57. //因为两个y共享一对uv。故y0 u y1 v能提取出两组(y, u, v)
  58. y0 = yuv_buff[i + ];
  59. u = yuv_buff[i + ];
  60. y1 = yuv_buff[i + ];
  61. v = yuv_buff[i + ];
  62.  
  63. YUV2RGB(y0, u, v, &r, &g, &b);
  64. //将RGB分量填充到OpenCV的IplImage中
  65. fillImage(pimg, r, g, b);
  66.  
  67. YUV2RGB(y1, u, v, &r, &g, &b);
  68. fillImage(pimg, r, g, b);
  69. }
  70. }
  71.  
  72. int main(int argc, char** argv)
  73. {
  74. const char* filename = argc > ? argv[] : "waterfall_yuyv422.yuv";
  75.  
  76. FILE* fin = fopen(filename, "rb");
  77. if( fin == NULL )
  78. {
  79. printf("can't open the file\n");
  80. return -;
  81. }
  82.  
  83. int width = ;
  84. int height = ;
  85.  
  86. //一张完整的图像 对应在 yuv文件中 占据的字节数
  87. //因为是yuyv格式的yuv,所以其排列方式是y0 u y1 v y2 u v y3
  88. //因为是两个y共享一对u和v。所以y0 u y1 v代表两个像素(y0, u, v)
  89. //和(y1, u, v),对应地会有两个RGB像素。
  90. //也就是说y0 u y1 v这4个字节的内容等于2个像素, 2比1的关系。
  91. //所以有width * height个像素,就应该要width * height * 2个字节
  92. //这个关系是yuv422特有的。对于yuv444和yuv420会有不同的比例关系
  93. int frame_size = width * height * ;
  94.  
  95. unsigned char* buff = new unsigned char[frame_size];
  96.  
  97. IplImage* pimg = cvCreateImage(cvSize(width, height),
  98. IPL_DEPTH_8U, );
  99. cvNamedWindow("1.jpg");
  100.  
  101. //这里用图像做成一个视频播放器
  102. while( )
  103. {
  104. int ret = fread(buff, , frame_size, fin);
  105. if( ret != frame_size )
  106. {
  107. break;
  108. }
  109.  
  110. convertImage(pimg, buff, frame_size);
  111. cvShowImage("1.jpg", pimg);
  112. cvWaitKey();
  113. }
  114.  
  115. cvReleaseImage(&pimg);
  116. cvDestroyWindow("1.jpg");
  117.  
  118. delete [] buff;
  119.  
  120. return ;
  121. }

http://blog.csdn.net/luotuo44/article/details/26402273?utm_source=tuicool&utm_medium=referral

图像视频编码和FFmpeg(2)-----YUV格式介绍和应用的更多相关文章

  1. 图像YUV格式介绍

    图像YUV格式介绍   1 YUV格式简介 YUV格式,与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样 ...

  2. YUV格式介绍

    原文链接:http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html YUV格式有两大类:planar和packed.对于plana ...

  3. Android 音视频编解码——RGB与YUV格式转换

    一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...

  4. 音视频编解码——RGB与YUV格式转换

    一.RGB模型与YUV模型 1.RGB模型 我们知道物理三基色分别是红(Red).绿(Green).蓝(Blue).现代的显示器技术就是通过组合不同强度的红绿蓝三原色,来达成几乎任何一种可见光的颜色. ...

  5. 【转】H264视频编码级别说明profile level Encoder

    版权声明:本文为博主原创文章,未经博主允许不得转载. 首先要阐明所谓的AVC其实就是H.264标准,是由ITU-T和ISO/IEC组成的联合视频组(JVT,Joint Video Team)一起开发的 ...

  6. YUV格式具体解释

    YUV是指亮度參量和色度參量分开表示的像素格式,而这样分开的优点就是不但能够避免相互干扰,还能够减少色度的採样率而不会对图像质量影响太大.YUV是一个比較笼统地说法,针对它的详细排列方式,能够分为非常 ...

  7. YUV格式全解

    YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大.YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很多 ...

  8. YUV格式详解【转】

    转自:http://blog.csdn.net/searchsun/article/details/2443867 [-] YUV格式解析1播放器project2 YUV 采样 表面定义 YUV格式解 ...

  9. Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图片(不使用OpenGL)(附Demo)

    MediaCodec的使用demo: https://github.com/vecio/MediaCodecDemo https://github.com/taehwandev/MediaCodecE ...

随机推荐

  1. small test on 5.30 night T2

    (题面写错了,应该是一条从b -> a 的边) 让我们设状态 (a,b,c) 表示存在一个点k,使得  dist(k,b) - dist(k,a) * 2 + 3 = c,显然这里的第三维可以压 ...

  2. 千克与磅之间的转换 Exercise05_05

    /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:千克与磅之间的转换 * */ public class Exercise05_05 { public static void ...

  3. Activity组件(传递数据)

    (一) 1.效果图:点击按钮“调用第二个Activity”,转到第二页面,之后点击“返回数据”,将第二个页面的数据传到第一个页面         2. activity_main.xml <?x ...

  4. 大规模请求下,Linux 服务器连接数优化设置

    作者:heiyeluren 一般一个大规模Linux服务器请求数可能是几十万上百万的情况,需要足够的连接数来使用,所以务必进行相应的设置. 默认的Linux服务器文件描述符等打开最大是1024,用 u ...

  5. 我们知道写入过程比ZooKeeper集合中的读取过程要贵,因为所有节点都需要在数据库中写入相同的数据。因此,对于平衡的环境拥有较少数量(例如3,5,7)的节点比拥有大量的节点要好。

    我们知道写入过程比ZooKeeper集合中的读取过程要贵,因为所有节点都需要在数据库中写入相同的数据.因此,对于平衡的环境拥有较少数量(例如3,5,7)的节点比拥有大量的节点要好. 组件 描述 写入( ...

  6. 推荐10个免费的HTML编辑器

    如果你想开发一个网站,你肯定想要一个很棒的HTML编辑器,一个好的编辑器可以让代码更加整齐格式化,前端显示也会更好,从而提升你的工作效率.下面就为开发者推荐10个免费的HTML编辑器,你可以尝试使用. ...

  7. 关于constraint 的disable和enable

    建立主外键的constraint create table emp1(emp_no number(2) constraint emp_emp_no_pk primary key,ename varch ...

  8. 基于CentOS与VmwareStation10搭建Oracle11G RAC 64集群环境:2.搭建环境-2.9. 配置用户等效性(可选项)

    2.9.配置用户等效性(可选项) Oracle 11g r2 ssh也可以在安装过程中配置. 2.9.1. grid用户等效性 1.以下均以grid用户执行: 在两个节点的grid主目录分别创建.ss ...

  9. nagios监控redis

    nagios是非常强大的监控工具,但是它本身没有监控redis的功能 但是网上有很多大神写了监控redis的插件,比较热门的使用perl写的check_redis.pl 但是由于我们监控mongodb ...

  10. 一个简单的JS函数,用于判断文本是否数字

    /****************************************************** 判断是否是数字(整数,小数均可,不包括负数)* 2014年10月10日22:38:19* ...