图像视频编码和FFmpeg(2)-----YUV格式介绍和应用

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

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

时间: 2024-10-17 20:58:28

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

网络视频监控系统开发系列---YUV格式详解

转载一篇对yuv格式解释的比较清楚地文章,也可以直接参考微软的那篇文章. 对于YUV格式,比较原始的讲解是MPEG-2 VIDEO部分的解释,当然后来微软有一个比较经典的解释,中文的大多是翻译这篇文章的.文章来源:http://msdn.microsoft.com/en-us/library/aa904813(VS.80).aspx 这里转载有人已经翻译过的, http://hondrif82q.spaces.live.com/blog/cns!776E82726DE60562!177.entr

图像YUV格式介绍

1 YUV格式简介 YUV格式,与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题.并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽. YUV格式有两大类:planar和packed.对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所

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

版权声明:本文为博主原创文章,未经博主允许不得转载. 首先要阐明所谓的AVC其实就是H.264标准,是由ITU-T和ISO/IEC组成的联合视频组(JVT,Joint Video Team)一起开发的,ITU-T给这个标准命名为H.264(以前叫做H.26L),而ISO/IEC称它为MPEG-4 高级视频编码(Advanced Video Coding,AVC)它定位于覆盖整个视频应用领域,包括:低码率的无线应用.标准清晰度和高清晰度的电视广播应用.Internet上的视频流应用,传输高清晰度的

YUV格式具体解释

YUV是指亮度參量和色度參量分开表示的像素格式,而这样分开的优点就是不但能够避免相互干扰,还能够减少色度的採样率而不会对图像质量影响太大.YUV是一个比較笼统地说法,针对它的详细排列方式,能够分为非常多种详细的格式.转载一篇对yuv格式解释的比較清楚地文章,也能够直接參考微软的那篇文章. 对于YUV格式,比較原始的解说是MPEG-2 VIDEO部分的解释,当然后来微软有一个比較经典的解释,中文的大多是翻译这篇文章的.文章来源:http://msdn.microsoft.com/en-us/lib

一款开源的 Android YUV 格式查看工具

1. YUVDroidTools 最近项目比较忙,好久没有写文章了,也没有为开源社区贡献点啥了,这个周末抽空整理了一下自己一直维护的一份基于 ffmpeg 的 YUV 格式转换代码,写了一个简单的 Android YUV 数据查看工具(代码完全开源),截图如下: 特性如下: (1)支持选择导入本地文件,支持实时显示 YUV 格式的图片,简单易用. (2)支持多种 YUV 格式,包括: YU12.YV12.NV21.NV12.YUYV422.YVYU422.YUV422P.UYVY422 等等.

使用ffmpeg视频编码过程中踩的一个坑

今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,很多时候一旦思维定势真的挺难突破的.下面是不正确的编码结果: 使用ffmpeg做视频编码过程中,首先要新建数据帧,并为数据帧分配相应内存,以便于保存图像数据,为数据帧分配内存需要用到av_image_alloc()这个函数,该函数将根据传入的图像宽.高.图像格式.数据对齐基数等参数进行内存分配. 这其中有一个参数可能会让人迷惑,那就是数据对齐基数这个参数该设置多少?顺便说说为什么要数据对齐,之所以要对齐,主要

转 常见视频编码方式以及封装格式

常见视频编码方式以及封装格式 常见视频编码方式 所谓视频编码方式就是指通过特定的压缩技术,将某个视频格式的文件转换成另一种视频格式文件的方式.视频流传输中最为重要的编解码标准有国际电联的H.261.H.263.H.264.H.265,运动静止图像专家组的M-JPEG和国际标准化组织运动图像专家组的MPEG系列标准,此外在互联网上被广泛应用的还有Real-Networks的RealVideo.微软公司的WMV以及Apple公司的QuickTime等. AVI AVI 是 Audio Video I

视频编码与视频格式的区别和联系

视频编码是一种压缩技术,就是把原始的视频流压缩成特定的比特流(视编码方案).视频格式是一种封装格式,就是把编码后的比特流进行封装,不同的视频格式封装方法不同.打个比方,原始的模拟视频采用MPEG2数字化编码后,你可以采用TS流格式封装成TS流文件,也可以采用PS流格式封装成PS流文件,选择权在于你,TS流是称为实时流,他把视频信息分成很多很小的包,损坏了一个包,你解码回放时只是看不见一小部分(例如出现马赛克),但是PS流是文件流,文件损害的话,整个文件都看不了了.再形象的说,一段视频资源用TS流

视频格式和视频编码是什么关系

编解码格式是数据按那种方式编码压缩,便于网络传输和降低带宽的需要:文件格式是将内容按具体的编码格式压缩后,以该文件所规定的格式进行封装的结果,即容器的概念,文件播放则按容器数据的存放方式解析,提取出编码数据然后解码后交由播放设备进行播放. 原始视频通过摄像头采集进来以后很庞大,要想在互联网上进行传输就必须要进行压缩,于是就有了编解码标准,原始视频文件经过压缩以后就有了不同的格式,比如通过h.264压缩的就是.264格式,其它的同理.而我们看的电影之类的视频(AVI,MPEG,MOV)除了包含图像