diff options
Diffstat (limited to 'src/video_out/yuv2rgb.c')
-rw-r--r-- | src/video_out/yuv2rgb.c | 144 |
1 files changed, 127 insertions, 17 deletions
diff --git a/src/video_out/yuv2rgb.c b/src/video_out/yuv2rgb.c index b237bfafa..5f972217b 100644 --- a/src/video_out/yuv2rgb.c +++ b/src/video_out/yuv2rgb.c @@ -31,6 +31,12 @@ #include <string.h> #include <inttypes.h> +#ifdef HAVE_FFMPEG_AVUTIL_H +# include <mem.h> +#else +# include <libavutil/mem.h> +#endif + #include "yuv2rgb.h" #define LOG_MODULE "yuv2rgb" @@ -39,7 +45,7 @@ #define LOG */ -#include "xineutils.h" +#include <xine/xineutils.h> static int prof_scale_line = -1; @@ -1242,6 +1248,88 @@ static void scale_line_1_2 (uint8_t *source, uint8_t *dest, xine_profiler_stop_count(prof_scale_line); } +/* Interpolate 4 output pixels from 5 source pixels (1280x720 -> 1024x576). */ +/* * * * * * */ +/* * * * * */ + +static void scale_line_5_4 (uint8_t *source, uint8_t *dest, int width, int step) { + int p1, p2, p3, p4, p5; + + xine_profiler_start_count(prof_scale_line); + + while ((width -= 4) >= 0) { + *dest++ = *source++; + p1 = *source++; + p2 = *source++; + *dest++ = p1 + ((p2 - p1) >> 2); + p3 = *source++; + p4 = *source++; + /* the middle pixel loses most sharpness, so do that one cubic */ + p5 = (9 * (p2 + p3) - p1 - p4) >> 4; + *dest++ = p5 & 0x100 ? ~(p5 >> 9) : p5; + *dest++ = p4 + ((p3 - p4) >> 2); + } + + if ((width += 4) <= 0) goto done; + *dest++ = *source++; + if (--width <= 0) goto done; + p1 = *source++; + p2 = *source++; + *dest++ = p1 + ((p2 - p1) >> 2); + if (--width <= 0) goto done; + p1 = *source; + *dest++ = (p1 + p2) >> 1; + done: + + xine_profiler_stop_count(prof_scale_line); +} + + +/* Interpolate 3 output pixels from 2 source pixels (1280x720 -> 1920x1080). */ +/* * * * */ +/* * * * * */ +static void scale_line_2_3 (uint8_t *source, uint8_t *dest, int width, int step) { + int p1, p2, p3, p4, p5; + + xine_profiler_start_count(prof_scale_line); + + p4 = p1 = *source++; + p2 = *source; + + while ((width -= 6) >= 0) { + *dest++ = p1; + p3 = *source++; + p5 = (5 * p1 + 12 * p2 - p3) >> 4; + *dest++ = p5 & 0x100 ? ~(p5 >> 9) : p5; + p4 = *source++; + p5 = (12 * p2 + 5 * p3 - p1) >> 4; + *dest++ = p5 & 0x100 ? ~(p5 >> 9) : p5; + *dest++ = p3; + p1 = *source++; + p5 = (5 * p3 + 12 * p4 - p1) >> 4; + *dest++ = p5 & 0x100 ? ~(p5 >> 9) : p5; + p2 = *source++; + p5 = (12 * p4 + 5 * p1 - p3) >> 4; + *dest++ = p5 & 0x100 ? ~(p5 >> 9) : p5; + } + + if ((width += 6) <= 0) goto done; + *dest++ = p1; + if (--width <= 0) goto done; + *dest++ = (11 * p1 + 21 * p2) >> 5; + if (--width <= 0) goto done; + p3 = *source++; + *dest++ = (21 * p2 + 11 * p3) >> 5; + if (--width <= 0) goto done; + *dest++ = p3; + if (--width <= 0) goto done; + p4 = *source++; + *dest++ = (11 * p3 + 21 * p4) >> 5; + done: + + xine_profiler_stop_count(prof_scale_line); +} + /* * Scale line with no horizontal scaling. For NTSC mpeg2 dvd input in @@ -1261,7 +1349,7 @@ static scale_line_func_t find_scale_line_func(int step) { int src_step; int dest_step; scale_line_func_t func; - char *desc; + const char *desc; /* FIXME: consider moving this to a char[] to avoid reloc */ } scale_line[] = { { 15, 16, scale_line_15_16, "dvd 4:3(pal)" }, { 45, 64, scale_line_45_64, "dvd 16:9(pal), fullscreen(1024x768)" }, @@ -1273,6 +1361,8 @@ static scale_line_func_t find_scale_line_func(int step) { { 3, 4, scale_line_3_4, "svcd 4:3(ntsc)" }, { 1, 2, scale_line_1_2, "2*zoom" }, { 1, 1, scale_line_1_1, "non-scaled" }, + { 5, 4, scale_line_5_4, "hd720p, fullscreen(1024x576)" }, + { 2, 3, scale_line_2_3, "hd720p, fullscreen(1920x1080)" } }; size_t i; #ifdef LOG @@ -2246,7 +2336,7 @@ static int div_round (int dividend, int divisor) } static void yuv2rgb_set_csc_levels (yuv2rgb_factory_t *this, - int brightness, int contrast, int saturation) + int brightness, int contrast, int saturation, int colormatrix) { int i; uint8_t table_Y[1024]; @@ -2257,18 +2347,40 @@ static void yuv2rgb_set_csc_levels (yuv2rgb_factory_t *this, void *table_r = 0, *table_g = 0, *table_b = 0; int shift_r = 0, shift_g = 0, shift_b = 0; - int crv = Inverse_Table_6_9[this->matrix_coefficients][0]; - int cbu = Inverse_Table_6_9[this->matrix_coefficients][1]; - int cgu = -Inverse_Table_6_9[this->matrix_coefficients][2]; - int cgv = -Inverse_Table_6_9[this->matrix_coefficients][3]; + int yoffset = -16; + int ygain = (1 << 16) * 255 / 219; + + int cm = (colormatrix >> 1) & 7; + int crv = Inverse_Table_6_9[cm][0]; + int cbu = Inverse_Table_6_9[cm][1]; + int cgu = -Inverse_Table_6_9[cm][2]; + int cgv = -Inverse_Table_6_9[cm][3]; int mode = this->mode; int swapped = this->swapped; + /* nasty workaround for xine-ui not sending exact defaults */ + if (brightness == -1) brightness = 0; + if (contrast == 127) contrast = 128; + if (saturation == 127) saturation = 128; + + /* full range mode */ + if (colormatrix & 1) { + yoffset = 0; + ygain = (1 << 16); + + crv = (crv * 112 + 63) / 127; + cbu = (cbu * 112 + 63) / 127; + cgu = (cgu * 112 + 63) / 127; + cgv = (cgv * 112 + 63) / 127; + } + + yoffset += brightness; + for (i = 0; i < 1024; i++) { int j; - j = (76309 * (i - 384 - 16 + brightness) + 32768) >> 16; + j = (ygain * (i - 384 + yoffset) + 32768) >> 16; j = (j < 0) ? 0 : ((j > 255) ? 255 : j); table_Y[i] = j; } @@ -2427,16 +2539,16 @@ static void yuv2rgb_set_csc_levels (yuv2rgb_factory_t *this, for (i = 0; i < 256; i++) { this->table_rV[i] = (((uint8_t *) table_r) + - entry_size * div_round (crv * (i-128), 76309)); + entry_size * div_round (crv * (i-128), ygain)); this->table_gU[i] = (((uint8_t *) table_g) + - entry_size * div_round (cgu * (i-128), 76309)); - this->table_gV[i] = entry_size * div_round (cgv * (i-128), 76309); + entry_size * div_round (cgu * (i-128), ygain)); + this->table_gV[i] = entry_size * div_round (cgv * (i-128), ygain); this->table_bU[i] = (((uint8_t *)table_b) + - entry_size * div_round (cbu * (i-128), 76309)); + entry_size * div_round (cbu * (i-128), ygain)); } #if defined(ARCH_X86) || defined(ARCH_X86_64) - mmx_yuv2rgb_set_csc_levels (this, brightness, contrast, saturation); + mmx_yuv2rgb_set_csc_levels (this, brightness, contrast, saturation, colormatrix); #endif } @@ -3182,7 +3294,7 @@ static yuv2rgb_t *yuv2rgb_create_converter (yuv2rgb_factory_t *factory) { static void yuv2rgb_factory_dispose (yuv2rgb_factory_t *this) { free (this->table_base); - free (this->table_mmx_base); + av_free(this->table_mmx); free (this); } @@ -3200,13 +3312,11 @@ yuv2rgb_factory_t* yuv2rgb_factory_init (int mode, int swapped, this->create_converter = yuv2rgb_create_converter; this->set_csc_levels = yuv2rgb_set_csc_levels; this->dispose = yuv2rgb_factory_dispose; - this->matrix_coefficients = 6; this->table_base = NULL; this->table_mmx = NULL; - this->table_mmx_base = NULL; - yuv2rgb_set_csc_levels (this, 0, 128, 128); + yuv2rgb_set_csc_levels (this, 0, 128, 128, CM_DEFAULT); /* * auto-probe for the best yuv2rgb function |