ref: 8c8e7fad46c62082cb46d0e394239259b9baa1a0
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;
}
}
}