summaryrefslogtreecommitdiff
path: root/src/video_out/yuv2rgb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/yuv2rgb.c')
-rw-r--r--src/video_out/yuv2rgb.c144
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