ref: 27154e7406931d7e676dbf6267865c87e3b6dfbe
parent: a83a0da7e55e6f86f3d4d410b762d679d6294517
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Wed Sep 23 10:24:55 EDT 2020
a faster YUV->RGB conversion
--- a/yuv.c
+++ b/yuv.c
@@ -1,93 +1,48 @@
#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;
+ int yy1, cb1, cr1;
+ int r, g, b, go;
- u8int *rgb_ptr1=RGB+y*RGB_stride,
- *rgb_ptr2=RGB+(y+1)*RGB_stride;
+ for(y = 0; y < height-1; y += 2){
+ for(x = 0; x < width-1; x += 2){
+ cb1 = (int)*U - 0x80;
+ cr1 = (int)*V - 0x80;
+ go = 22554*cb1 - 46802*cr1;
- 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;
+#define ONE do{ \
+ yy1 = (int)*Y * 0x10101; \
+ r = yy1 + 91881*cr1; \
+ r = (r & 0xff000000) ? ~(r >> 31) : (r>>16); \
+ g = yy1 - go; \
+ g = (g & 0xff000000) ? ~(g >> 31) : (g>>16); \
+ b = yy1 + 116130*cb1; \
+ b = (b & 0xff000000) ? ~(b >> 31) : (b>>16); \
+ RGB[2] = r; \
+ RGB[1] = g; \
+ RGB[0] = b; \
+}while(0)
- //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;
+ ONE; Y += 1; RGB += 3;
+ ONE; Y += Y_stride; RGB += RGB_stride;
+ ONE; Y -= 1; RGB -= 3;
+ ONE; Y -= Y_stride; RGB -= RGB_stride;
- 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 += 2;
+ U += 1;
+ V += 1;
- 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;
+ RGB += 6;
}
+
+ Y += 2*Y_stride - x;
+ U += UV_stride - x/2;
+ V += UV_stride - x/2;
+ RGB += 2*RGB_stride - 3*x;
}
}