diff options
author | Benjamin Otte <otte@gnome.org> | 2009-09-17 18:43:24 +0200 |
---|---|---|
committer | Benjamin Otte <otte@gnome.org> | 2009-11-02 12:59:52 +0100 |
commit | f4ac4409a94aadf64beb49ec8bd7541b9a98f015 (patch) | |
tree | 54de220748d37e8c019207bf8991324c000bfbb8 | |
parent | 67bf739187cd43b5fff754b25693f76bb788d1fa (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.c | 160 | ||||
-rw-r--r-- | pixman/pixman.c | 7 | ||||
-rw-r--r-- | pixman/pixman.h | 35 | ||||
-rw-r--r-- | test/fetch-test.c | 2 |
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]); |