直入正题吧,

关于YUYV编码流的官方介绍:

http://linuxtv.org/downloads/v4l-dvb-apis/V4L2-PIX-FMT-YUYV.html


我们一起看看,

YUYV 这种编码

In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. As you can see, the Cr and Cb components have half the horizontal resolution of the Y component. V4L2_PIX_FMT_YUYV is known in the Windows environment as YUY2.

每四字节表示两个像素,每四字节有两个Y,一个CB和CR。每一个Y分别属于一个像素,CB和CR共同属于这两个点。这种格式在WINDOWS环境下叫YUY2

字节顺序. 表格中每个单元一个字节

start + 0:Y'00Cb00Y'01Cr00Y'02Cb01Y'03Cr01
start + 8:Y'10Cb10Y'11Cr10Y'12Cb11Y'13Cr11
start + 16:Y'20Cb20Y'21Cr20Y'22Cb21Y'23Cr21
start + 24:Y'30Cb30Y'31Cr30Y'32Cb31Y'33Cr31

实际分布. 


0
1
2
3
0YCY
YCY
1YCY
YCY
2YCY
YCY
3YCY
YCY


根据这个,用每个点下的值乘换算公式,就可以得到对应RGB下的点,换算公式我就不多说了,讲到这里,直接贴代码把:

//YUV像素 转 RGB像素的函数
static void yuv_to_rgb_24(unsigned char y, unsigned char u, unsigned char v,
			unsigned char* r, unsigned char* g, unsigned char* b)
{
	int amp=255;
	double R,G,B;
	
	//conversion equations
	B=amp*(0.004565*y+0.000001*u+0.006250*v-0.872);
	G=amp*(0.004565*y-0.001542*u-0.003183*v+0.531);
	R=amp*(0.004565*y+0.007935*u-1.088);

	//R, G and B must be in the range from 0 to 255    
	if (R < 0)
		R=0;
	if (G < 0)
		G=0;
	if (B < 0)
		B=0;
	
	if (R > 255)
		R=255;
	if (G > 255)
		G=255;
	if (B > 255)
		B=255;

	*r=(unsigned char)(R);
	*g=(unsigned char)(G);
	*b=(unsigned char)(B);

}


	//TODO: width*height这个是图像的长宽,这里默认是24位色深,16位的话,原理一样,不懂留言问我吧。
	uint8_t * imageLine1;
	int    xx,yy;
	int    x,y;
	int bpl,Bpp,amp;
	double r,g,b;
	unsigned char Y,U,V;
	unsigned char R,G,B,RG,GB;
	imageLine1 = (uint8_t *)malloc(width*height*3);
	bpl=width*3;//bytes per line,
	Bpp=3;//bytes per pixel,
	/*TODO: 这里把图像像素组读到videoFrame里,根据自己的情况,从网络,从管道还是从其他地方	
	int ret;
	
	ret = read(STDIN_FILENO, videoFrame , width*height*2);
	*/
	
	for (yy = 0; yy < (height); yy++)
	{
		for (xx =0; xx < (width/2); xx++)
		{	
			x=4*xx;
			y=yy;
			U = videoFrame[width*2*y+x+3];				
			V = videoFrame[width*2*y+x+1];

			Y = videoFrame[width*2*y+x];
			yuv_to_rgb_24(Y, U, V, &R,&G,&B);
			imageLine1[(bpl*y)+(Bpp*x/2)]=B;
			imageLine1[(bpl*y)+(Bpp*x/2)+1]=G;
			imageLine1[(bpl*y)+(Bpp*x/2)+2]=R;
						
			Y = videoFrame[width*2*y+x+2];

			yuv_to_rgb_24(Y, U, V, &R,&G,&B);
			imageLine1[(bpl*y)+(Bpp*(x/2+1))]=B;
			mageLine1[(bpl*y)+(Bpp*(x/2+1))+1]=G;
			imageLine1[(bpl*y)+(Bpp*(x/2+1))+2]=R;
		}
	}
				
		



这代码是我从v4l2 sample code改过来的,他们只支持YUV420,不支持YUYV,于是我作了修改。

其他YUV格式的转换思路差不多,有时间的话感觉应该弄个lib,每个刚去接触视频编码的人都要看这个,挺浪费时间的。

Logo

更多推荐