shithub: treason

Download patch

ref: 27154e7406931d7e676dbf6267865c87e3b6dfbe
parent: a83a0da7e55e6f86f3d4d410b762d679d6294517
author: Sigrid Haflínudóttir <[email protected]>
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;
 	}
 }