今天心情非常之好,花了一个下午时间搞定了困扰了我一个月的事情。写了一个程序可以把openCV的BGR图像格式转换成YUV4:2:0,然后通过FFmpeg的API把YUV4:2:0的图像编码压缩,最后利用live555把压缩后的buffer打包成RTP包,最后用Unicast将它们发送出去。简单的说就是 BGR—>YUV4:2:0—>encode to buffer—>RTP—>Unicast这样的过程。
把预想的程序完成真是一大快事,随便记录一部分比较特别的东西,因为openCV没有BGR转YUV420的函数,所以需要自己写一个,我写的这个函数读入一个三通道的图像数据,然后先使用cvCvtColor函数,将BGR转成YCrCb,这个YCrCb是4:4:4也就是全抽样,然后对Cb和Cr分量进行抽样,最后我们可以得到三个数组,分别存Y, U, V三个分量。这个转换不算复杂,就是使用了以下的概念。
YUV4:2:0
4:2:0并不意味着只有Y,Cb而没有Cr分量。它指得是对每行扫描线来说,只有一种色度分量以2:1的抽样率存储。相邻的扫描行存储不同的色度分量,也就是说,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0...以此类推。对每个色度分量来说,水平方向和竖直方向的抽样率都是2:1,所以可以说色度的抽样率是4:1。对非压缩的8比特量化的视频来说,每个由2x2个2行2列相邻的像素组成的宏像素需要占用6字节内存。
八个像素为:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3][Y5 U5 V5] [Y6 U6 V6] [Y7U7 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] [Y7U2 V7] [Y8 U2 V7](来自百度百科)我们可以对每八个像素:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3][Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]进行一次抽样,抽样: Y0 Y1 Y2 Y3 Y4 Y5 Y6 Y7 给Y分量,U0 U2 给U分量,V5 V7给V分量。现在提供另一个简单的转换函数:
{
// first, convert the input image into YCbCr
IplImage *tmp = cvCreateImage(cvSize(in->width, in->height), 8, 3);
cvCvtColor(in, tmp, CV_RGB2YCrCb);
/*
* widthStep = channel number * width
* if width%4 == 0
* for example, width = 352, width%4 == 0, widthStep = 3 * 352 = 1056
*/
int idx_in = 0;
int idx_out = 0;
int idx_out_y = 0;
int idx_out_u = 0;
int idx_out_v = 0;
for(int j = 0; j < in->height; j+=1) {
idx_in = j * in->widthStep;
for(int i = 0; i < in->widthStep; i+=12) {
// We use the chroma sample here, and put it into the out buffer
// take the luminance sample
out_y[idx_out_y] = tmp->imageData[idx_in + i + 0]; // Y
idx_out_y++;
out_y[idx_out_y] = tmp->imageData[idx_in + i + 3]; // Y
idx_out_y++;
out_y[idx_out_y] = tmp->imageData[idx_in + i + 6]; // Y
idx_out_y++;
out_y[idx_out_y] = tmp->imageData[idx_in + i + 9]; // Y
idx_out_y++;
if((j % 2) == 0) {
// take the blue-difference and red-difference chroma components sample
out_u[idx_out_u++] = tmp->imageData[idx_in + i + 1]; // Cr U
out_u[idx_out_u++] = tmp->imageData[idx_in + i + 7]; // Cr U
out_v[idx_out_v++] = tmp->imageData[idx_in + i + 2]; // Cb V
out_v[idx_out_v++] = tmp->imageData[idx_in + i + 8]; // Cb V
}
}
}
cvReleaseImage(&tmp);
}
没有评论:
发表评论