ref: 85a8a51370eb0b8a4061fc601c705d43cc73b119
dir: /yuv.c/
#include <u.h> /* yuv→rgb by Adrien Descamps */ #define clamp(v) ((v)<0?0 : ((v)>255?255:v)) #define FIXED_POINT_VALUE(value, precision) ((int)(((value)*(1<<precision))+0.5)) typedef struct { u8int cb_factor; // [(255*CbNorm)/CbRange] u8int cr_factor; // [(255*CrNorm)/CrRange] u8int g_cb_factor; // [Bf/Gf*(255*CbNorm)/CbRange] u8int g_cr_factor; // [Rf/Gf*(255*CrNorm)/CrRange] u8int y_factor; // [(YMax-YMin)/255] u8int y_offset; // YMin } YUV2RGBParam; #define YUV2RGB_PARAM(Rf, Bf, YMin, YMax, CbCrRange) \ {.cb_factor=FIXED_POINT_VALUE(255.0*(2.0*(1-Bf))/CbCrRange, 6), \ .cr_factor=FIXED_POINT_VALUE(255.0*(2.0*(1-Rf))/CbCrRange, 6), \ .g_cb_factor=FIXED_POINT_VALUE(Bf/(1.0-Bf-Rf)*255.0*(2.0*(1-Bf))/CbCrRange, 7), \ .g_cr_factor=FIXED_POINT_VALUE(Rf/(1.0-Bf-Rf)*255.0*(2.0*(1-Rf))/CbCrRange, 7), \ .y_factor=FIXED_POINT_VALUE(255.0/(YMax-YMin), 7), \ .y_offset=YMin} static const YUV2RGBParam YUV2RGB[3] = { // ITU-T T.871 (JPEG) YUV2RGB_PARAM(0.299, 0.114, 0.0, 255.0, 255.0), // ITU-R BT.601-7 YUV2RGB_PARAM(0.299, 0.114, 16.0, 235.0, 224.0), // ITU-R BT.709-6 YUV2RGB_PARAM(0.2126, 0.0722, 16.0, 235.0, 224.0) }; void yuv420_rgb24( u32int width, u32int height, const u8int *Y, const u8int *U, const u8int *V, u32int Y_stride, u32int UV_stride, u8int *RGB, u32int RGB_stride) { const YUV2RGBParam *const param = &(YUV2RGB[0]); u32int x, y; for(y=0; y<(height-1); y+=2) { const u8int *y_ptr1=Y+y*Y_stride, *y_ptr2=Y+(y+1)*Y_stride, *u_ptr=U+(y/2)*UV_stride, *v_ptr=V+(y/2)*UV_stride; u8int *rgb_ptr1=RGB+y*RGB_stride, *rgb_ptr2=RGB+(y+1)*RGB_stride; for(x=0; x<(width-1); x+=2) { s8int u_tmp, v_tmp; u_tmp = u_ptr[0]-128; v_tmp = v_ptr[0]-128; //compute Cb Cr color offsets, common to four pixels s16int b_cb_offset, r_cr_offset, g_cbcr_offset; b_cb_offset = (param->cb_factor*u_tmp)>>6; r_cr_offset = (param->cr_factor*v_tmp)>>6; g_cbcr_offset = (param->g_cb_factor*u_tmp + param->g_cr_factor*v_tmp)>>7; s16int y_tmp; y_tmp = (param->y_factor*(y_ptr1[0]-param->y_offset))>>7; rgb_ptr1[2] = clamp(y_tmp + r_cr_offset); rgb_ptr1[1] = clamp(y_tmp - g_cbcr_offset); rgb_ptr1[0] = clamp(y_tmp + b_cb_offset); y_tmp = (param->y_factor*(y_ptr1[1]-param->y_offset))>>7; rgb_ptr1[5] = clamp(y_tmp + r_cr_offset); rgb_ptr1[4] = clamp(y_tmp - g_cbcr_offset); rgb_ptr1[3] = clamp(y_tmp + b_cb_offset); y_tmp = (param->y_factor*(y_ptr2[0]-param->y_offset))>>7; rgb_ptr2[2] = clamp(y_tmp + r_cr_offset); rgb_ptr2[1] = clamp(y_tmp - g_cbcr_offset); rgb_ptr2[0] = clamp(y_tmp + b_cb_offset); y_tmp = (param->y_factor*(y_ptr2[1]-param->y_offset))>>7; rgb_ptr2[5] = clamp(y_tmp + r_cr_offset); rgb_ptr2[4] = clamp(y_tmp - g_cbcr_offset); rgb_ptr2[3] = clamp(y_tmp + b_cb_offset); rgb_ptr1 += 6; rgb_ptr2 += 6; y_ptr1 += 2; y_ptr2 += 2; u_ptr += 1; v_ptr += 1; } } }