summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2009-09-17 18:43:24 +0200
committerBenjamin Otte <otte@gnome.org>2009-11-02 12:59:52 +0100
commitf4ac4409a94aadf64beb49ec8bd7541b9a98f015 (patch)
tree54de220748d37e8c019207bf8991324c000bfbb8
parent67bf739187cd43b5fff754b25693f76bb788d1fa (diff)
First step at adding YUV support:
1) remove old supported YUV formats 2) add list of YUV formats to support 3) introduce differentiation between packed and planar formats 4) implement AYUV
-rw-r--r--pixman/pixman-access.c160
-rw-r--r--pixman/pixman.c7
-rw-r--r--pixman/pixman.h35
-rw-r--r--test/fetch-test.c2
4 files changed, 193 insertions, 11 deletions
diff --git a/pixman/pixman-access.c b/pixman/pixman-access.c
index 389cf2a..b864b37 100644
--- a/pixman/pixman-access.c
+++ b/pixman/pixman-access.c
@@ -1067,6 +1067,85 @@ fetch_scanline_g1 (pixman_image_t *image,
}
}
+/* R = 1.164(Y - 16) + 1.596(V - 128)
+ * G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
+ * B = 1.164(Y - 16) + 2.018(U - 128)
+ */
+/* 0x8000 is for rounding */
+#define YUV2RGB_CHROMA(r,g,b,u,v) \
+ do \
+ { \
+ u -= 128; \
+ v -= 128; \
+ r = 0x8000 + 0x019a2e * v; \
+ g = 0x8000 - 0x00d0f2 * v - 0x00647e * u; \
+ b = 0x8000 + 0x0206a2 * u; \
+ } while (0)
+
+#define YUV2RGB_ADD(r,g,b,y) \
+ do \
+ { \
+ y = (y - 16) * 0x012b27; \
+ r += y; \
+ g += y; \
+ b += y; \
+ } while (0)
+
+/* FIXME: ffmpeg uses a table for clamping, is that faster? */
+#define YUV2RGB_STORE_ALPHA(pixel,a,r,g,b) \
+ do \
+ { \
+ r = (r >= 0 ? r < 0x1000000 ? r : 0xffffff : 0) * a; \
+ g = (g >= 0 ? g < 0x1000000 ? g : 0xffffff : 0) * a; \
+ b = (b >= 0 ? b < 0x1000000 ? b : 0xffffff : 0) * a; \
+ \
+ pixel = 0xff000000 | \
+ ((r >> 8) & 0xff0000) | \
+ ((g >> 16) & 0x00ff00) | \
+ ((b >> 24) & 0x0000ff); \
+ } while (0)
+
+#define YUV2RGB_STORE(pixel,r,g,b) \
+ do \
+ { \
+ pixel = 0xff000000 | \
+ (r >= 0 ? r < 0x1000000 ? r & 0xff0000 : 0xff0000 : 0) | \
+ (g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) | \
+ (b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0); \
+ } while (0)
+
+static void
+fetch_scanline_ayuv (pixman_image_t *image,
+ int x,
+ int line,
+ int width,
+ uint32_t * buffer,
+ const uint32_t *mask,
+ uint32_t mask_bits)
+{
+ const uint8_t *bits = (const uint8_t *)
+ (image->bits.bits + image->bits.rowstride * line + x);
+ int i;
+
+ for (i = 0; i < width; i++)
+ {
+ int32_t a, y, u, v, r, g, b;
+
+ a = bits[0];
+ y = bits[1];
+ u = bits[2];
+ v = bits[3];
+
+ YUV2RGB_CHROMA (r, g, b, u, v);
+ YUV2RGB_ADD (r, g, b, y);
+ YUV2RGB_STORE_ALPHA (*buffer, a, r, g, b);
+
+ buffer++;
+ bits += 4;
+ }
+}
+
+#if 0
static void
fetch_scanline_yuy2 (pixman_image_t *image,
int x,
@@ -1139,6 +1218,7 @@ fetch_scanline_yv12 (pixman_image_t *image,
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
}
+#endif
/**************************** Pixel wise fetching *****************************/
@@ -1763,6 +1843,30 @@ fetch_pixel_g1 (bits_image_t *image,
}
static uint32_t
+fetch_pixel_ayuv (bits_image_t *image,
+ int offset,
+ int line)
+{
+ const uint8_t *bits = (const uint8_t *)
+ (image->bits + image->rowstride * line + offset);
+
+ int32_t a, y, u, v, r, g, b;
+ uint32_t pixel;
+
+ a = bits[0];
+ y = bits[1];
+ u = bits[2];
+ v = bits[3];
+
+ YUV2RGB_CHROMA (r, g, b, u, v);
+ YUV2RGB_ADD (r, g, b, y);
+ YUV2RGB_STORE_ALPHA (pixel, a, r, g, b);
+
+ return pixel;
+}
+
+#if 0
+static uint32_t
fetch_pixel_yuy2 (bits_image_t *image,
int offset,
int line)
@@ -1816,6 +1920,7 @@ fetch_pixel_yv12 (bits_image_t *image,
(g >= 0 ? g < 0x1000000 ? (g >> 8) & 0x00ff00 : 0x00ff00 : 0) |
(b >= 0 ? b < 0x1000000 ? (b >> 16) & 0x0000ff : 0x0000ff : 0);
}
+#endif
/*********************************** Store ************************************/
@@ -2640,6 +2745,58 @@ store_scanline_g1 (bits_image_t * image,
}
}
+#define UNPREMULTIPLY(r, g, b, a) \
+ do \
+ { \
+ if (a == 0) \
+ r = g = b = 0; \
+ else if (a != 255) \
+ { \
+ r = (r * 255 + a / 2) / a; \
+ g = (g * 255 + a / 2) / a; \
+ b = (b * 255 + a / 2) / a; \
+ } \
+ } while (0)
+
+/* Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
+ * U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
+ * V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
+ */
+
+#define RGB2Y(r,g,b) (0x108000 + 0x41bd * (r) + 0x810f * (g) + 0x1910 * (b))
+#define RGB2U(r,g,b) (0x808000 - 0x25f2 * (r) - 0x4a7e * (g) + 0x7070 * (b))
+#define RGB2V(r,g,b) (0x808000 + 0x7070 * (r) - 0x5e28 * (g) - 0x1249 * (b))
+
+static void
+store_scanline_ayuv (bits_image_t * image,
+ int x,
+ int y,
+ int width,
+ const uint32_t *values)
+{
+ uint8_t *bits = (uint8_t *) (image->bits + image->rowstride * y + x);
+ int i;
+
+ for (i = 0; i < width; i++)
+ {
+ int32_t a, r, g, b;
+
+ a = values[i] >> 24;
+ r = (values[i] >> 16) & 0xff;
+ g = (values[i] >> 8 ) & 0xff;
+ b = values[i] & 0xff;
+
+ UNPREMULTIPLY (r, g, b, a);
+
+ bits[0] = a;
+ bits[1] = RGB2Y (r, g, b) >> 16;
+ bits[2] = RGB2U (r, g, b) >> 16;
+ bits[3] = RGB2V (r, g, b) >> 16;
+
+ bits += 4;
+ }
+}
+
/*
* Contracts a 64bpp image to 32bpp and then stores it using a regular 32-bit
* store proc. Despite the type, this function expects a uint64_t buffer.
@@ -2836,6 +2993,8 @@ static const format_info_t accessors[] =
NULL, store_scanline_x2b10g10r10 },
/* YUV formats */
+ FORMAT_INFO (ayuv),
+#if 0
{ PIXMAN_yuy2,
fetch_scanline_yuy2, fetch_scanline_generic_64,
fetch_pixel_yuy2, fetch_pixel_generic_64,
@@ -2845,6 +3004,7 @@ static const format_info_t accessors[] =
fetch_scanline_yv12, fetch_scanline_generic_64,
fetch_pixel_yv12, fetch_pixel_generic_64,
NULL, NULL },
+#endif
{ PIXMAN_null },
};
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 0edd967..4c58421 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -511,8 +511,7 @@ pixman_format_supported_source (pixman_format_code_t format)
case PIXMAN_a1:
case PIXMAN_g1:
/* YUV formats */
- case PIXMAN_yuy2:
- case PIXMAN_yv12:
+ case PIXMAN_ayuv:
return TRUE;
default:
@@ -534,10 +533,6 @@ pixman_format_supported_source (pixman_format_code_t format)
PIXMAN_EXPORT pixman_bool_t
pixman_format_supported_destination (pixman_format_code_t format)
{
- /* YUV formats cannot be written to at the moment */
- if (format == PIXMAN_yuy2 || format == PIXMAN_yv12)
- return FALSE;
-
return pixman_format_supported_source (format);
}
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 2ce8c72..88d73b7 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -615,10 +615,14 @@ struct pixman_indexed
#define PIXMAN_TYPE_ABGR 3
#define PIXMAN_TYPE_COLOR 4
#define PIXMAN_TYPE_GRAY 5
-#define PIXMAN_TYPE_YUY2 6
-#define PIXMAN_TYPE_YV12 7
+#define PIXMAN_TYPE_YUV_PACKED 6
+#define PIXMAN_TYPE_YUV_PLANAR 7
#define PIXMAN_TYPE_BGRA 8
+/* deprecated (and broken) */
+#define PIXMAN_TYPE_YUY2 PIXMAN_TYPE_YUV_PACKED
+#define PIXMAN_TYPE_YV12 PIXMAN_TYPE_YUV_PLANAR
+
#define PIXMAN_FORMAT_COLOR(f) \
(PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ARGB || \
PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ABGR || \
@@ -685,8 +689,31 @@ typedef enum {
PIXMAN_g1 = PIXMAN_FORMAT(1,PIXMAN_TYPE_GRAY,0,0,0,0),
/* YUV formats */
- PIXMAN_yuy2 = PIXMAN_FORMAT(16,PIXMAN_TYPE_YUY2,0,0,0,0),
- PIXMAN_yv12 = PIXMAN_FORMAT(12,PIXMAN_TYPE_YV12,0,0,0,0)
+ PIXMAN_ayuv = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,8,8,8,8)
+// PIXMAN_i420 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_iyu1 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_iyu2 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_iyuv = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_ntsc = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_nv12 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_nv21 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_uynv = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_uyvy = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_v210 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_v216 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_v308 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_v410 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y41b = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y41p = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y422 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y42b = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y444 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_y800 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_yuv9 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_yuy2 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_yv12 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_yvu9 = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
+// PIXMAN_yvyu = PIXMAN_FORMAT(32,PIXMAN_TYPE_YUV_PACKED,0,0,0,0)
} pixman_format_code_t;
/* Querying supported format values. */
diff --git a/test/fetch-test.c b/test/fetch-test.c
index 6306a4c..4c51074 100644
--- a/test/fetch-test.c
+++ b/test/fetch-test.c
@@ -56,7 +56,6 @@ testcase_t testcases[] = {
.dst = { 0x00010101, 0x00232323, 0x00454545, 0x00676767,
0x00898989, 0x00ababab, 0x00cdcdcd, 0x00efefef, },
},
-#endif
/* FIXME: make this work on big endian */
{
.format = PIXMAN_yv12,
@@ -82,6 +81,7 @@ testcase_t testcases[] = {
0xffffffff, 0xff000000, 0xff4affff, 0xff0023ee,
},
},
+#endif
};
const int ntestcases = sizeof(testcases)/sizeof(testcases[0]);