最近一直在学习关于音视频处理的知识。因为没有对于YUV进行深入的研究导致在做音视频采集处理以及编码的实验中走了很多的弯路。现在先对YUV的各种常见的数据进行分析。
YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。
好了,言归正传,谈谈如何分析YUV码流吧。YUV码流有多种不同的格式,要分析YUV码流,就必须搞清楚你面对的到底是哪一种格式,并且必须搞清楚这种格式的YUV采样和分布情况。下面我将介绍几种常用的YUV码流格式,供大家参考。
下面我用图的形式给出常见的YUV码流的存储方式,并在存储方式后面附有取样每个像素点的YUV数据的方法,其中,Cb、Cr的含义等同于U、V。
YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。
UYVY格式也是YUV422采样的存储格式中的一种,只不过与YUYV不同的是UV的排列顺序不一样而已,还原其每个像素点的YUV值的方法与上面一样。
YUV422P也属于YUV422的一种,它是一种Plane模式,即打包模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如上图所示。其每一个像素点的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即两个Y共用一个UV。比如,对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00。
YU12和YV12属于YUV420格式,也是一种Plane模式,将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一组UV。注意,上图中,Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。
NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00
例: YUYV转YUV420P
void ffmpeg::YUYV_to_YUV420P(char * image_in, char* image_out, int inwidth, int inheight)
{
AVFrame *frmyuyv = av_frame_alloc();
AVFrame *frm420p = av_frame_alloc();
av_image_fill_arrays(frmyuyv->data, frmyuyv->linesize, (uint8_t*)image_in, AV_PIX_FMT_YUYV422, inwidth, inheight, 16);
av_image_fill_arrays(frm420p->data, frm420p->linesize, (uint8_t*)image_out, AV_PIX_FMT_YUV420P, inwidth, inheight, 16);
struct SwsContext *sws = sws_getContext(inwidth, inheight, AV_PIX_FMT_YUYV422, inwidth,inheight, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
int ret = sws_scale(sws, frmyuyv->data, frmyuyv->linesize, 0, inheight, frm420p->data, frm420p->linesize);
image_out=(char*)frm420p->data;
av_frame_free(&frmyuyv);
av_frame_free(&frm420p);
sws_freeContext(sws);
}