ARM平台YUV转RGB888(转)
前段时间,公司有个嵌入式的项目,我做的其中有一项是yuv视频到rgb888图像的转换。我主要是参照一位牛人的博客做的: http://blog.csdn.net/housisong/archive/2007/10/31/1859084.aspxYUV422p To RGB888 C语言版本接口说明:
- /****************************************YUV422P_To_RGB24.c**************************/
- //模块功能:将YUV422_PLANAR图像数据转换成RGB24格式
- typedef unsigned char BYTE; // [0..255]
- /*
- * 接口说明:
- * 功能:构建查询表,转换模块运行前必须进行的初始化操作
- */
- void YUV422P_To_RGB24_init();
- /*
- *接口说明:
- *功能:将YUV422P图像数据转换成RGB24格式
- *参数:
- * pY: YUV422P图像数据Y的起始指针
- * pU: YUV422P图像数据U的起始指针
- * pV: YUV422P图像数据V的起始指针
- * DstPic: 转换成的RGB24图像数据的起始指针
- * width: 图像宽度
- * height: 图像高度
- *返回值:成功返回0,失败返回-1
- *注意:DstPic所指向的缓冲区必须事先分配好,其大小应该为 width*height*3
- */
- int YUV422P_To_RGB24(BYTE* pY, BYTE* pU, BYTE* pV, BYTE* DstPic, int width, int height);
实现:
- //使用整数运算(定点数运算)来代替浮点运算
- const int csY_coeff_16 = 1.164383 * (1 << 16);
- const int csU_blue_16 = 2.017232 * (1 << 16);
- const int csU_green_16 = (-0.391762) * (1 << 16);
- const int csV_green_16 = (-0.812968) * (1 << 16);
- const int csV_red_16 = 1.596027 * (1 << 16);
- //颜色查表
- static BYTE _color_table[256 * 3];
- static const BYTE* color_table = &_color_table[256];
- //查表
- static int Ym_tableEx[256];
- static int Um_blue_tableEx[256];
- static int Um_green_tableEx[256];
- static int Vm_green_tableEx[256];
- static int Vm_red_tableEx[256];
- //颜色饱和函数
- inline long border_color(long color) {
- if (color > 255)
- return 255;
- else if (color < 0)
- return 0;
- else
- return color;
- }
- //采用查找表进行计算时,必须运行的初始化函数
- void YUV422P_To_RGB24_init() {
- int i;
- for (i = 0; i < 256 * 3; ++i)
- _color_table[i] = border_color(i - 256);
- for (i = 0; i < 256; ++i) {
- Ym_tableEx[i] = (csY_coeff_16 * (i - 16)) >> 16;
- Um_blue_tableEx[i] = (csU_blue_16 * (i - 128)) >> 16;
- Um_green_tableEx[i] = (csU_green_16 * (i - 128)) >> 16;
- Vm_green_tableEx[i] = (csV_green_16 * (i - 128)) >> 16;
- Vm_red_tableEx[i] = (csV_red_16 * (i - 128)) >> 16;
- }
- }
- inline void YUVToRGB24_Table(BYTE *p, const BYTE Y0, const BYTE Y1,
- const BYTE U, const BYTE V) {
- int Ye0 = Ym_tableEx[Y0];
- int Ye1 = Ym_tableEx[Y1];
- int Ue_blue = Um_blue_tableEx[U];
- int Ue_green = Um_green_tableEx[U];
- int Ve_green = Vm_green_tableEx[V];
- int Ve_red = Vm_red_tableEx[V];
- int UeVe_green = Ue_green + Ve_green;
- *p = color_table[(Ye0 + Ve_red)];
- *(p + 1) = color_table[(Ye0 + UeVe_green)];
- *(p + 2) = color_table[(Ye0 + Ue_blue)];
- *(p + 3) = color_table[(Ye1 + Ve_red)];
- *(p + 4) = color_table[(Ye1 + UeVe_green)];
- *(p + 5) = color_table[(Ye1 + Ue_blue)];
- }
- int YUV420P_To_RGB24(BYTE* pY, BYTE* pU, BYTE* pV, BYTE* DstPic, int width,
- int height) {
- int y, x, x_uv;
- BYTE* pDstLine = DstPic;
- if ((width % 2) != 0 || (height % 2) != 0)
- return (-1);
- for (y = 0; y < height; ++y) {
- //DECODE_PlanarYUV211_Common_line(pDstLine, pY, pU, pV,width);
- for (x = 0; x < width; x += 2) {
- x_uv = x >> 1;
- YUVToRGB24_Table(&pDstLine[x * 3], pY[x], pY[x + 1], pU[x_uv],
- pV[x_uv]);
- }
- pDstLine += width * 3; //RGB888
- pY += width; //YUV422
- if (y % 2 == 1) {
- pU += width / 2;
- pV += width / 2;
- }
- }
- return 0;
- }
经测试发现,在hi3512(arm 926ej-s,267MHz)平台上运行时,该yuv转rgb模块的速度不是很快,大概20帧/秒。为了提高效率,核心解码模块我采用了arm汇编,重写了YUVToRGB24_Table模块。
YUV420P_To_RGB24_asm.c代码:
- extern int YUVToRGB24_Assemble(unsigned char *pDstLine, unsigned char **yuv, int width);
- //使用整数运算(定点数运算)来代替浮点运算
- const int csY_coeff_16 = 1.164383 * (1 << 16);
- const int csU_blue_16 = 2.017232 * (1 << 16);
- const int csU_green_16 = (-0.391762) * (1 << 16);
- const int csV_green_16 = (-0.812968) * (1 << 16);
- const int csV_red_16 = 1.596027 * (1 << 16);
- //查表
- int Ym_tableEx[256];
- int Um_blue_tableEx[256];
- int Um_green_tableEx[256];
- int Vm_green_tableEx[256];
- int Vm_red_tableEx[256];
- //采用查找表进行计算时,必须运行的初始化函数
- void YUV422P_To_RGB24_init()
- {
- int i;
- for (i = 0; i < 256; ++i)
- {
- Ym_tableEx[i]=(csY_coeff_16 * (i - 16) )>>16;
- Um_blue_tableEx[i]=(csU_blue_16 * (i - 128) )>>16;
- Um_green_tableEx[i]=(csU_green_16 * (i - 128) )>>16;
- Vm_green_tableEx[i]=(csV_green_16 * (i - 128) )>>16;
- Vm_red_tableEx[i]=(csV_red_16 * (i - 128) )>>16;
- }
- }
- int YUV420P_To_RGB24(BYTE* pY, BYTE* pU, BYTE* pV, BYTE* DstPic, int width, int height)
- {
- int y;
- BYTE* pDstLine = DstPic;
- BYTE* yuv[3];
- if ((width % 8)!=0)
- return(-1);
- yuv[0] = pY;
- yuv[1] = pU;
- yuv[2] = pV;
- for (y = height; y > 0; --y)
- {
- YUVToRGB24_Assemble(pDstLine, yuv, width); //decoder a line with asm function in YUVToRGB24_Assemble.s
- pDstLine += width * 3; //RGB888
- yuv[0] += width; //YUV422
- if(y % 2 == 1) {
- yuv[1] += width >> 1;
- yuv[2] += width >> 1;
- }
- }
- return 0;
- }