[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xine-devel
Subject:    Re: [xine-devel] OpenGL 2.0 vo driver
From:       "Torsten Jager" <t.jager () gmx ! de>
Date:       2012-06-28 17:51:42
Message-ID: 20120628175142.247470 () gmx ! net
[Download RAW message or body]

Hi Christophe!

I'm a big fan of your work :-)
And it takes a big fan to deal with that overheating GPU...
No, honestly.

I recently bought a LG IPS235 flatscreen, because of its almost
perfect factory calibrated colors. Unfortunatly, switching desktop
to 1920x1080 kind of overloads my system, so I tried your product.

It compiled OK, then quickly freezed xine-ui. According to gdb,
both ui and libGL tried to lock X display at the same time.
See opengl2_freeze_fix.diff for my solution.

Then, very nice bicubic scaling but completely unusable performance
on my nvidia 7025 onboard chip. So I bought a nvidia 210 based
card, and hey! what a fun...

Slightly wrong colors though (red and blue clipping at ~90%).
So I rewrote matrix coeff generation once again (did such stuff
so many times I think I can sing the formulae by now).
Also fixes a problem with xine-ui using rather short sliders
for brightness etc., being unable to exactly reproduce fine grain
values. I think nobody actually needs 1000% contrast anyway.
See opengl2_color_fix.diff.

Just in case you wander about thos #ifdef's - they hit when my
colorspace manager is present. After half a year, I kind of lost
faith that will ever be accepted by xine project official makers.
Try cspm_base.diff if you like.

Torsten


-- 
Empfehlen Sie GMX DSL Ihren Freunden und Bekannten und wir
belohnen Sie mit bis zu 50,- Euro! https://freundschaftswerbung.gmx.de

["opengl2_freeze_fix.diff" (application/octet-stream)]

--- a/src/video_out/video_out_opengl2.c	2012-05-10 14:14:18.000000000 +0200
+++ b/src/video_out/video_out_opengl2.c	2012-06-27 22:45:01.000000000 +0200
@@ -1221,9 +1246,11 @@ static void opengl2_display_frame( vo_dr
 
   opengl2_redraw_needed( this_gen );
 
+  XLockDisplay (this->display);
   pthread_mutex_lock(&this->drawable_lock); /* protect drawable from being changed */
   opengl2_draw( this, frame );
   pthread_mutex_unlock(&this->drawable_lock); /* allow changing drawable again */
+  XUnlockDisplay (this->display);
 
   frame->vo_frame.free( &frame->vo_frame );
 }

["opengl2_color_fix.diff" (application/octet-stream)]

--- a/src/video_out/video_out_opengl2.c	2012-05-10 14:14:18.000000000 +0200
+++ b/src/video_out/video_out_opengl2.c	2012-06-27 22:45:01.000000000 +0200
@@ -159,8 +159,17 @@ typedef struct {
 
   int		            zoom_x;
   int		            zoom_y;
+
+#ifdef VO_CAP_COLOR_MATRIX
+  int                cm_state;
+#endif
 } opengl2_driver_t;
 
+#ifdef VO_CAP_COLOR_MATRIX
+  /* import common color matrix stuff */
+  #define CM_DRIVER_T opengl2_driver_t
+  #include "color_matrix.c"
+#endif
 
 
 typedef struct {
@@ -344,24 +353,6 @@ static const char *yuv422_frag=
 
 
 
-float yuv_601[] = {
-    1.16438,  0.00000,  1.59603, -0.87420,
-    1.16438, -0.39176, -0.81297,  0.53167,
-    1.16438,  2.01723,  0.00000, -1.08563
-};
-
-float yuv_709[] = {
-    1.16438,  0.00000,  1.79274, -0.97295,
-    1.16438, -0.21325, -0.53291,  0.30148,
-    1.16438,  2.11240,  0.00000, -1.13340
-};
-
-float yuv_240[] = {
-    1.16438,  0.00000,  1.79411, -0.97363,
-    1.16438, -0.25798, -0.54258,  0.32879,
-    1.16438,  2.07871,  0.00000, -1.11649
-};
-
 static void load_csc_matrix( GLuint prog, float *cf )
 {
     glUniform4f( glGetUniformLocationARB( prog, "r_coefs" ), cf[0], cf[1], cf[2], \
cf[3] ); @@ -766,39 +757,73 @@ static int opengl2_redraw_needed( vo_dri
 
 
 
-static void opengl2_update_csc_matrix( opengl2_driver_t *that, opengl2_frame_t \
                *frame )
-{
-  float *color_standard = (frame->height > 576) ? yuv_709 : yuv_601;
+static void opengl2_update_csc_matrix (opengl2_driver_t *that, opengl2_frame_t \
*frame) { +  int color_standard;
+
+#ifdef VO_CAP_COLOR_MATRIX
+  color_standard = cm_from_frame (&frame->vo_frame);
+#else
+  color_standard = (frame->height - frame->vo_frame.crop_top - \
frame->vo_frame.crop_bottom >= 720) ? +    2 : 10;
+#endif
 
   if ( that->update_csc || that->color_standard != color_standard ) {
-    float hue = that->hue/100.0;
-    float saturation = that->saturation/100.0;
-    float contrast = that->contrast/100.0;
-    float brightness = that->brightness/100.0;
+    float hue = (float)that->hue * 3.14159265359 / 128.0;
+    float saturation = (float)that->saturation / 128.0;
+    float contrast = (float)that->contrast / 128.0;
+    float brightness = that->brightness;
     float uvcos = saturation * cos( hue );
     float uvsin = saturation * sin( hue );
-    float uc, vc;
+    float kb, kr;
+    float vr, vg, ug, ub;
+    float ygain, yoffset;
     int i;
 
-    for (i=0; i<3; ++i ) {
-      that->csc_matrix[(i * 4) + 0] = color_standard[(i * 4) + 0];
-      uc = color_standard[(i * 4) + 1];
-      vc = color_standard[(i * 4) + 2];
-
-      that->csc_matrix[(i * 4) + 3] = brightness - (16.0/219.0);
-      that->csc_matrix[(i * 4) + 1] = (uvcos * uc) + (uvsin * vc);
-      that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvcos * uc) - ((128.0 / \
                255.0) * uvsin * vc);
-      that->csc_matrix[(i * 4) + 2] = (uvsin * uc) + (uvcos * vc);
-      that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvsin * uc) - ((128.0 / \
                255.0) * uvcos * vc);
-
-      that->csc_matrix[(i * 4) + 0] *= contrast;
-      that->csc_matrix[(i * 4) + 1] *= contrast;
-      that->csc_matrix[(i * 4) + 2] *= contrast;
-      that->csc_matrix[(i * 4) + 3] *= contrast;
+    switch (color_standard >> 1) {
+      case 1:  kb = 0.0722; kr = 0.2126; break; /* ITU-R 709 */
+      case 4:  kb = 0.1100; kr = 0.3000; break; /* FCC */
+      case 7:  kb = 0.0870; kr = 0.2120; break; /* SMPTE 240 */
+      default: kb = 0.1140; kr = 0.2990;        /* ITU-R 601 */
+    }
+    vr = 2.0 * (1.0 - kr);
+    vg = -2.0 * kr * (1.0 - kr) / (1.0 - kb - kr);
+    ug = -2.0 * kb * (1.0 - kb) / (1.0 - kb - kr);
+    ub = 2.0 * (1.0 - kb);
+
+    if (color_standard & 1) {
+      /* fullrange mode */
+      yoffset = brightness;
+      ygain = contrast;
+      uvcos *= contrast * 255.0 / 254.0;
+      uvsin *= contrast * 255.0 / 254.0;
+    } else {
+      /* mpeg range */
+      yoffset = brightness - 16.0;
+      ygain = contrast * 255.0 / 219.0;
+      uvcos *= contrast * 255.0 / 224.0;
+      uvsin *= contrast * 255.0 / 224.0;
+    }
+
+    /* csc_matrix[rgb][yuv1] */
+    that->csc_matrix[1] = -uvsin * vr;
+    that->csc_matrix[2] = uvcos * vr;
+    that->csc_matrix[5] = uvcos * ug - uvsin * vg;
+    that->csc_matrix[6] = uvcos * vg + uvsin * ug;
+    that->csc_matrix[9] = uvcos * ub;
+    that->csc_matrix[10] = uvsin * ub;
+    for (i = 0; i < 12; i += 4) {
+      that->csc_matrix[i] = ygain;
+      that->csc_matrix[i + 3] = (yoffset * ygain
+        - 128.0 * (that->csc_matrix[i + 1] + that->csc_matrix[i + 2])) / 255.0;
     }
 
     that->color_standard = color_standard;
     that->update_csc = 0;
+
+#ifdef VO_CAP_COLOR_MATRIX
+    xprintf (that->xine, XINE_VERBOSITY_LOG,"video_out_opengl2: b %d c %d s %d h %d \
[%s]\n", +      that->brightness, that->contrast, that->saturation, that->hue, \
cm_names[color_standard]); +#endif
   }
 }
 
@@ -1317,13 +1344,13 @@ static void opengl2_get_property_min_max
 {
   switch ( property ) {
     case VO_PROP_HUE:
-      *max = 314; *min = -314; break;
+      *max = 127; *min = -128; break;
     case VO_PROP_SATURATION:
-      *max = 1000; *min = 0; break;
+      *max = 255; *min = 0; break;
     case VO_PROP_CONTRAST:
-      *max = 1000; *min = 0; break;
+      *max = 255; *min = 0; break;
     case VO_PROP_BRIGHTNESS:
-      *max = 100; *min = -100; break;
+      *max = 127; *min = -128; break;
     case VO_PROP_SHARPNESS:
       *max = 100; *min = -100; break;
     default:
@@ -1401,6 +1428,10 @@ static void opengl2_dispose( vo_driver_t
 {
   opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
 
+#ifdef VO_CAP_COLOR_MATRIX
+  cm_close (this);
+#endif
+
   pthread_mutex_destroy(&this->drawable_lock);
 
   glXMakeCurrent( this->display, this->drawable, this->context );
@@ -1542,20 +1573,28 @@ static vo_driver_t *opengl2_open_plugin(
 
   this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | \
VO_CAP_UNSCALED_OVERLAY | VO_CAP_CUSTOM_EXTENT_OVERLAY;// | VO_CAP_ARGB_LAYER_OVERLAY \
| VO_CAP_VIDEO_WINDOW_OVERLAY;  
+#ifdef VO_CAP_COLOR_MATRIX
+  this->capabilities |= VO_CAP_COLOR_MATRIX | VO_CAP_FULLRANGE;
+#endif
+
   this->capabilities |= VO_CAP_HUE;
   this->capabilities |= VO_CAP_SATURATION;
   this->capabilities |= VO_CAP_CONTRAST;
   this->capabilities |= VO_CAP_BRIGHTNESS;
 
   this->update_csc = 1;
-  this->color_standard = yuv_601;
+  this->color_standard = 10;
   this->hue = 0;
-  this->saturation = 100;
-  this->contrast = 100;
+  this->saturation = 128;
+  this->contrast = 128;
   this->brightness = 0;
   this->sharpness = 0;
   this->sharpness_program.compiled = 0;
 
+#ifdef VO_CAP_COLOR_MATRIX
+  cm_init (this);
+#endif
+
   this->bicubic_pass1_program.compiled = 0;
   this->bicubic_pass2_program.compiled = 0;
   this->bicubic_lut_texture = 0;


["cspm_base.diff" (application/octet-stream)]

--- xine-lib-1.2-20120609/include/xine/video_out.h	2012-06-09 19:58:05.000000000 +0200
+++ xine-lib-1.2-20120609/include/xine/video_out.h	2012-06-16 01:58:05.000000000 +0200
@@ -291,6 +291,11 @@ struct xine_video_port_s {
 #define VO_CHROMA_422        32 /* used by VDPAU, default is chroma_420 */
 #define VO_STILL_IMAGE       64
 
+/* ((mpeg_color_matrix << 1) | color_range) inside frame.flags bits 11-8 */
+#define VO_FULLRANGE 0x100
+#define VO_GET_FLAGS_CM(flags) ((flags >> 8) & 15)
+#define VO_SET_FLAGS_CM(cm,flags) flags = ((flags) & ~0xf00) | (((cm) & 15) << 8)
+
 /* video driver capabilities */
 #define VO_CAP_YV12                   0x00000001 /* driver can handle YUV 4:2:0 pictures */
 #define VO_CAP_YUY2                   0x00000002 /* driver can handle YUY2 pictures */
@@ -303,6 +308,8 @@ struct xine_video_port_s {
 #define VO_CAP_VDPAU_MPEG12           0x00000100 /* driver can use VDPAU for mpeg1/2 */
 #define VO_CAP_VDPAU_VC1              0x00000200 /* driver can use VDPAU for VC1 */
 #define VO_CAP_VDPAU_MPEG4            0x00000400 /* driver can use VDPAU for mpeg4-part2 */
+#define VO_CAP_COLOR_MATRIX           0x00004000 /* driver can use alternative yuv->rgb matrices */
+#define VO_CAP_FULLRANGE              0x00008000 /* driver handles fullrange yuv */
 #define VO_CAP_HUE                    0x00010000
 #define VO_CAP_SATURATION             0x00020000
 #define VO_CAP_CONTRAST               0x00040000
--- xine-lib-1.2-20120609/src/combined/ffmpeg/ff_video_decoder.c	2012-06-09 19:58:05.000000000 +0200
+++ xine-lib-1.2-20120609/src/combined/ffmpeg/ff_video_decoder.c	2012-06-18 02:39:36.000000000 +0200
@@ -140,8 +140,11 @@ struct ff_video_decoder_s {
 #endif
 };
 
+/* import color matrix names */
+#include "../../video_out/color_matrix.c"
+
 static void ff_check_colorspace (ff_video_decoder_t *this) {
-  int i, cm;
+  int i, cm, caps;
 
 #ifdef AVCODEC_HAS_COLORSPACE
   cm = this->context->colorspace << 1;
@@ -162,17 +165,27 @@ static void ff_check_colorspace (ff_vide
   if (cm != this->color_matrix) {
     this->color_matrix = cm;
     xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
-      "ffmpeg_video_dec: color matrix #%d\n", cm >> 1);
+      "ffmpeg_video_dec: color matrix #%d [%s]\n", cm >> 1, cm_names[cm & 15]);
+
+    caps = this->stream->video_out->get_capabilities (this->stream->video_out);
+
+    if (!(caps & VO_CAP_COLOR_MATRIX)) {
+      xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
+        "ffmpeg_video_dec: video out plugin does not support color matrix switching\n");
+      cm &= 1;
+    }
 
     this->full2mpeg = 0;
-    if (cm & 1) {
+    if ((cm & 1) && !(caps & VO_CAP_FULLRANGE)) {
       /* sigh. fall back to manual conversion */
+      cm &= ~1;
       this->full2mpeg = 1;
       for (i = 0; i < 256; i++) {
         this->ytab[i] = (219 * i + 127) / 255 + 16;
         this->ctab[i] = 112 * (i - 128) / 127 + 128;
       }
     }
+    VO_SET_FLAGS_CM (cm, this->frame_flags);
   }
 }
 
--- xine-lib-1.2-20120609/src/video_out/color_matrix.c	1970-01-01 01:00:00.000000000 +0100
+++ xine-lib-1.2-20120609/src/video_out/color_matrix.c	2012-06-16 11:58:26.000000000 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ */
+
+
+/*
+  TJ. the output color matrix selection feature.
+
+  This file must be included after declaration of xxxx_driver_t,
+  and #define'ing CM_DRIVER_T to it.
+  That struct must contain the integer value cm_state.
+
+  cm_from_frame () returns current (color_matrix << 1) | color_range control value.
+  Having only 1 var simplifies change event handling and avoids unecessary vo
+  reconfiguration. In the libyuv2rgb case, they are even handled by same code.
+
+  In theory, HD video uses a different YUV->RGB matrix than the rest.
+  It shall come closer to the human eye's brightness feel, and give
+  more shades of green even without higher bit depth.
+
+  I discussed this topic with local TV engineers earlier.
+  They say their studio equipment throws around uncompressed YUV with no
+  extra info attached to it. Anything smaller than 720p is assumed to be
+  ITU-R 601, otherwise ITU-R 709. A rematrix filter applies whenever
+  video is scaled across the above mentioned HD threshold.
+
+  However, the weak point of their argumentation is potentially non-standard
+  input material. Those machines obviously dont verify input data, and
+  ocasionally they dont even respect stream info (tested by comparing TV
+  against retail DVD version of same movie).
+
+  Consumer TV sets handle this fairly inconsistent - stream info, video size,
+  hard-wired matrix, user choice or so-called intelligent picture enhancers
+  that effectively go way off standards.
+  So I decided to provide functionality, and let the user decide if and how
+  to actually use it.
+
+  BTW. VDPAU already has its own matrix switch based on stream info.
+  Rumour has it that proprietory ATI drivers auto switch their xv ports
+  based on video size. Both not user configurable, and both not tested...
+*/
+
+/* eveybody gets these */
+
+/* user configuration settings */
+#define CM_CONFIG_NAME   "video.output.color_matrix"
+#define CM_CONFIG_SIGNAL 0
+#define CM_CONFIG_SIZE   1
+#define CM_CONFIG_SD     2
+#define CM_CONFIG_HD     3
+
+#define CR_CONFIG_NAME   "video.output.color_range"
+#define CR_CONFIG_AUTO   0
+#define CR_CONFIG_MPEG   1
+#define CR_CONFIG_FULL   2
+
+static const char * cm_names[] = {
+  "RGB",
+  "RGB",
+  "ITU-R 709 / HDTV",
+  "full range ITU-R 709 / HDTV",
+  "undefined",
+  "full range, undefined",
+  "ITU-R 470 BG / SDTV",
+  "full range ITU-R 470 BG / SDTV",
+  "FCC",
+  "full range FCC",
+  "ITU-R 470 BG / SDTV",
+  "full range ITU-R 470 BG / SDTV",
+  "SMPTE 170M",
+  "full range SMPTE 170M",
+  "SMPTE 240M",
+  "full range SMPTE 240M"
+};
+
+#ifdef CM_DRIVER_T
+
+/* this is for vo plugins only */
+
+/* the option names */
+static const char * const cm_conf_labels[] = {
+  "Signal", "Signal+Size", "SD", "HD", NULL
+};
+
+static const char * const cr_conf_labels[] = {
+  "Auto", "MPEG", "FULL", NULL
+};
+
+/* callback when user changes them */
+static void cm_cb_config (void *this, xine_cfg_entry_t *entry) {
+  *((int *)this) = (*((int *)this) & 3) | (entry->num_value << 2);
+}
+
+static void cr_cb_config (void *this, xine_cfg_entry_t *entry) {
+  *((int *)this) = (*((int *)this) & 0x1c) | entry->num_value;
+}
+
+static void cm_init (CM_DRIVER_T *this) {
+  /* register configuration */
+  this->cm_state = this->xine->config->register_enum (
+    this->xine->config,
+    CM_CONFIG_NAME,
+    CM_CONFIG_SD,
+    (char **)cm_conf_labels,
+    _("Output color matrix"),
+    _("Tell how output colors should be calculated.\n\n"
+      "Signal: Do as current stream suggests.\n"
+      "        This may be wrong sometimes.\n\n"
+      "Signal+Size: Same as above,\n"
+      "        but assume HD color for unmarked HD streams.\n\n"
+      "SD:     Force SD video standard ITU-R 470/601.\n"
+      "        Try this if you get too little green.\n\n"
+      "HD:     Force HD video standard ITU-R 709.\n"
+      "        Try when there is too much green coming out.\n\n"),
+    10,
+    cm_cb_config,
+    &this->cm_state
+  ) << 2;
+  this->cm_state |= this->xine->config->register_enum (
+    this->xine->config,
+    CR_CONFIG_NAME,
+    CR_CONFIG_AUTO,
+    (char **)cr_conf_labels,
+    _("Output color range"),
+    _("Tell how output colors should be ranged.\n\n"
+      "Auto: Do as current stream suggests.\n"
+      "      This may be wrong sometimes.\n\n"
+      "MPEG: Force MPEG color range (16..235) / studio swing / video mode.\n"
+      "      Try if image looks dull (no real black or white in it).\n\n"
+      "FULL: Force FULL color range (0..255) / full swing / PC mode.\n"
+      "      Try when flat black and white spots appear.\n\n"),
+    10,
+    cr_cb_config,
+    &this->cm_state
+  );
+}
+
+static uint8_t cm_m[] = {
+  5, 1, 5, 3, 4, 5, 6, 7, /* SIGNAL */
+  5, 1, 5, 3, 4, 5, 6, 7, /* SIZE */
+  5, 5, 5, 5, 5, 5, 5, 5, /* SD */
+  5, 1, 1, 1, 1, 1, 1, 1  /* HD */
+};
+
+static uint8_t cm_r[] = {0, 0, 1, 0}; /* AUTO, MPEG, FULL, safety */
+
+static int cm_from_frame (vo_frame_t *frame) {
+  CM_DRIVER_T *this = (CM_DRIVER_T *)frame->driver;
+  int cm = VO_GET_FLAGS_CM (frame->flags);
+  int cf = this->cm_state;
+
+  cm_m[10] = (frame->height - frame->crop_top - frame->crop_bottom) >= 720 ? 1 : 5;
+  cm_r[0] = cm & 1;
+  return ((cm_m[((cf >> 2) << 3) | (cm >> 1)] << 1) | cm_r[cf & 2]);
+}
+
+static void cm_close (CM_DRIVER_T *this) {
+  /* dont know whether this is really necessary */
+  this->xine->config->unregister_callback (this->xine->config, CR_CONFIG_NAME);
+  this->xine->config->unregister_callback (this->xine->config, CM_CONFIG_NAME);
+}
+
+#endif /* defined CM_DRIVER_T */


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/

_______________________________________________
xine-devel mailing list
xine-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/xine-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic