changeset 7964:143d730908ae

here is a somewhat generic equalizer implementation for the X11 vo drivers using the window's colormap (DirectColor). this method is using the video card's hardware gamma ramp so it involves no performance penalties at all. patch by lucho <lucho@haemimont.bg>
author arpi
date Tue, 29 Oct 2002 20:27:47 +0000
parents 0a5d69e6f2a2
children af50b41f0af8
files libvo/vo_gl2.c libvo/vo_x11.c libvo/x11_common.c libvo/x11_common.h
diffstat 4 files changed, 224 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/vo_gl2.c	Tue Oct 29 20:12:24 2002 +0000
+++ b/libvo/vo_gl2.c	Tue Oct 29 20:27:47 2002 +0000
@@ -598,6 +598,50 @@
 static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
 }
 
+static int choose_glx_visual(Display *dpy, int scr, XVisualInfo *res_vi)
+{
+	XVisualInfo template, *vi_list;
+	int vi_num, i, best_i, best_weight;
+	
+	template.screen = scr;
+	vi_list = XGetVisualInfo(dpy, VisualScreenMask, &template, &vi_num);
+	if (!vi_list) return -1;
+	best_weight = 1000000;
+	for (i = 0; i < vi_num; i++) {
+		int val, res, w = 0;
+		/* of course, the visual must support OpenGL rendering... */
+		res = glXGetConfig(dpy, vi_list + i, GLX_USE_GL, &val);
+		if (res || val == False) continue;
+		/* also it must be doublebuffered ... */
+		res = glXGetConfig(dpy, vi_list + i, GLX_DOUBLEBUFFER, &val);
+		if (res || val == False) continue;
+		/* furthermore it must be RGBA (not color indexed) ... */
+		res = glXGetConfig(dpy, vi_list + i, GLX_RGBA, &val);
+		if (res || val == False) continue;
+		/* prefer less depth buffer size, */
+		res = glXGetConfig(dpy, vi_list + i, GLX_DEPTH_SIZE, &val);
+		if (res) continue;
+		w += val*2;
+		/* stencil buffer size */
+		res = glXGetConfig(dpy, vi_list + i, GLX_STENCIL_SIZE, &val);
+		if (res) continue;
+		w += val*2;
+		/* and colorbuffer alpha size */
+		res = glXGetConfig(dpy, vi_list + i, GLX_ALPHA_SIZE, &val);
+		if (res) continue;
+		w += val;
+		/* and finally, prefer DirectColor-ed visuals to allow color corrections */
+		if (vi_list[i].class != DirectColor) w += 100;
+		if (w < best_weight) {
+			best_weight = w;
+			best_i = i;
+		}
+	}
+	if (best_weight < 1000000) *res_vi = vi_list[best_i];
+	XFree(vi_list);
+	return (best_weight < 1000000) ? 0 : -1;
+}
+
 /* connect to server, create and map window,
  * allocate colors and (shared) memory
  */
@@ -609,7 +653,7 @@
 	char *hello = (title == NULL) ? "OpenGL rulez" : title;
 //	char *name = ":0.0";
 	XSizeHints hint;
-	XVisualInfo *vinfo;
+	XVisualInfo *vinfo, vinfo_buf;
 	XEvent xev;
 
 //	XGCValues xgcv;
@@ -655,7 +699,7 @@
 //	XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &attribs);
 
 //	XMatchVisualInfo(mDisplay, screen, depth, TrueColor, &vinfo);
-  vinfo=glXChooseVisual( mDisplay,mScreen,wsGLXAttrib );
+  vinfo = choose_glx_visual(mDisplay,mScreen,&vinfo_buf) < 0 ? NULL : &vinfo_buf;
   if (vinfo == NULL)
   {
     printf("[gl2] no GLX support present\n");
@@ -664,7 +708,7 @@
 
 	xswa.background_pixel = 0;
 	xswa.border_pixel     = 1;
-	xswa.colormap         = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocNone);
+	xswa.colormap         = vo_x11_create_colormap(vinfo);
 	xswamask = CWBackPixel | CWBorderPixel | CWColormap;
 
   if ( vo_window == None ) 
@@ -1115,6 +1159,26 @@
   switch (request) {
   case VOCTRL_QUERY_FORMAT:
     return query_format(*((uint32_t*)data));
+  case VOCTRL_SET_EQUALIZER:
+    {
+      va_list ap;
+      int value;
+    
+      va_start(ap, data);
+      value = va_arg(ap, int);
+      va_end(ap);
+      return vo_x11_set_equalizer(data, value);
+	}
+  case VOCTRL_GET_EQUALIZER:
+    {
+      va_list ap;
+      int *value;
+    
+      va_start(ap, data);
+      value = va_arg(ap, int *);
+      va_end(ap);
+      return vo_x11_get_equalizer(data, value);
+    }
   }
   return VO_NOTIMPL;
 }
--- a/libvo/vo_x11.c	Tue Oct 29 20:12:24 2002 +0000
+++ b/libvo/vo_x11.c	Tue Oct 29 20:27:47 2002 +0000
@@ -260,7 +260,8 @@
    Visual *visual;
    depth = vo_find_depth_from_visuals(mDisplay, mScreen, &visual);
  }
- XMatchVisualInfo( mDisplay,mScreen,depth,TrueColor,&vinfo );
+ if ( !XMatchVisualInfo( mDisplay,mScreen,depth,DirectColor,&vinfo ))
+   XMatchVisualInfo( mDisplay,mScreen,depth,TrueColor,&vinfo );
 
  /* set image size (which is indeed neither the input nor output size), 
     if zoom is on it will be changed during draw_slice anyway so we dont dupplicate the aspect code here 
@@ -292,7 +293,7 @@
     bg=WhitePixel( mDisplay,mScreen );
     fg=BlackPixel( mDisplay,mScreen );
 
-    theCmap=XCreateColormap( mDisplay,mRootWin,vinfo.visual,AllocNone );
+    theCmap=vo_x11_create_colormap(&vinfo);
 
     xswa.background_pixel=0;
     xswa.border_pixel=0;
@@ -633,6 +634,24 @@
     return VO_TRUE;
   case VOCTRL_GET_IMAGE:
     return get_image(data);
+  case VOCTRL_SET_EQUALIZER:
+    {
+      va_list ap;
+      int value;
+      va_start(ap, data);
+      value = va_arg(ap, int);
+      va_end(ap);
+      return vo_x11_set_equalizer(data, value);
+	}
+  case VOCTRL_GET_EQUALIZER:
+    {
+      va_list ap;
+      int *value;
+      va_start(ap, data);
+      value = va_arg(ap, int *);
+      va_end(ap);
+      return vo_x11_get_equalizer(data, value);
+    }
   case VOCTRL_FULLSCREEN:
     vo_x11_fullscreen();
     return VO_TRUE;
--- a/libvo/x11_common.c	Tue Oct 29 20:12:24 2002 +0000
+++ b/libvo/x11_common.c	Tue Oct 29 20:27:47 2002 +0000
@@ -1,6 +1,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <math.h>
 #include <inttypes.h>
 
 #include "config.h"
@@ -969,3 +970,135 @@
   return bestvisual_depth;
 }
 
+
+static Colormap cmap = None;
+static XColor cols[256];
+static int cm_size, red_mask, green_mask, blue_mask;
+
+
+Colormap vo_x11_create_colormap(XVisualInfo *vinfo)
+{
+	unsigned k, r, g, b, ru, gu, bu, m, rv, gv, bv, rvu, gvu, bvu;
+
+	if (vinfo->class != DirectColor)
+	 return XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocNone);
+
+	/* can this function get called twice or more? */
+	if (cmap) return cmap;
+	cm_size = vinfo->colormap_size;
+	red_mask = vinfo->red_mask;
+	green_mask = vinfo->green_mask;
+	blue_mask = vinfo->blue_mask;
+	ru = (red_mask&(red_mask-1))^red_mask;
+	gu = (green_mask&(green_mask-1))^green_mask;
+	bu = (blue_mask&(blue_mask-1))^blue_mask;
+	rvu = 65536ull*ru/(red_mask + ru);
+	gvu = 65536ull*gu/(green_mask + gu);
+	bvu = 65536ull*bu/(blue_mask + bu);
+	r = g = b = 0;
+	rv = gv = bv = 0;
+	m = DoRed|DoGreen|DoBlue;
+	for (k = 0; k < cm_size; k++) {
+		int t;
+		cols[k].pixel = r|g|b;
+		cols[k].red = rv;
+		cols[k].green = gv;
+		cols[k].blue = bv;
+		cols[k].flags = m;
+		t = (r + ru) & red_mask; if (t < r) m &= ~DoRed; r = t;
+		t = (g + gu) & green_mask; if (t < g) m &= ~DoGreen; g = t;
+		t = (b + bu) & blue_mask; if (t < b) m &= ~DoBlue; b = t;
+		rv += rvu;
+		gv += gvu;
+		bv += bvu;
+	}
+	cmap = XCreateColormap(mDisplay, mRootWin, vinfo->visual, AllocAll);
+	XStoreColors(mDisplay, cmap, cols, cm_size);
+	return cmap;
+}
+
+/*
+ * Via colormaps/gamma ramps we can do gamma, brightness, contrast,
+ * hue and red/green/blue intensity, but we cannot do saturation.
+ * Currently only gamma, brightness and contrast are implemented.
+ * Is there sufficient interest for hue and/or red/green/blue intensity?
+ */
+/* these values have range [-100,100] and are initially 0 */
+static int vo_gamma = 0;
+static int vo_brightness = 0;
+static int vo_contrast = 0;
+
+
+uint32_t vo_x11_set_equalizer(char *name, int value)
+{
+	float gamma, brightness, contrast;
+	float rf, gf, bf;
+	int k;
+
+	/*
+	 * IMPLEMENTME: consider using XF86VidModeSetGammaRamp in the case
+	 * of TrueColor-ed window but be careful:
+	 * unlike the colormaps, which are private for the X client
+	 * who created them and thus automatically destroyed on client
+	 * disconnect, this gamma ramp is a system-wide (X-server-wide)
+	 * setting and _must_ be restored before the process exit.
+	 * Unforunately when the process crashes (or get killed
+	 * for some reason) it is impossible to restore the setting,
+	 * and such behaviour could be rather annoying for the users.
+	 */
+	if (cmap == None) return VO_NOTAVAIL;
+
+	if (!strcasecmp(name, "brightness")) vo_brightness = value;
+	else if (!strcasecmp(name, "contrast")) vo_contrast = value;
+	else if (!strcasecmp(name, "gamma")) vo_gamma = value;
+	else return VO_NOTIMPL;
+	
+	brightness = 0.01*vo_brightness;
+	contrast = tan(0.0095*(vo_contrast+100)*M_PI/4);
+	gamma = pow(2, -0.02*vo_gamma);
+
+	rf = (float)((red_mask & (red_mask - 1)) ^ red_mask)/red_mask;
+	gf = (float)((green_mask & (green_mask - 1)) ^ green_mask)/green_mask;
+	bf = (float)((blue_mask & (blue_mask - 1)) ^ blue_mask)/blue_mask;
+
+	/* now recalculate the colormap using the newly set value */
+	for (k = 0; k < cm_size; k++) {
+		float s;
+
+		s = pow(rf*k, gamma);
+		s = (s - 0.5)*contrast + 0.5;
+		s += brightness;
+		if (s < 0) s = 0;
+		if (s > 1) s = 1;
+		cols[k].red = (unsigned short)(s * 65535);
+
+		s = pow(gf*k, gamma);
+		s = (s - 0.5)*contrast + 0.5;
+		s += brightness;
+		if (s < 0) s = 0;
+		if (s > 1) s = 1;
+		cols[k].green = (unsigned short)(s * 65535);
+
+		s = pow(bf*k, gamma);
+		s = (s - 0.5)*contrast + 0.5;
+		s += brightness;
+		if (s < 0) s = 0;
+		if (s > 1) s = 1;
+		cols[k].blue = (unsigned short)(s * 65535);
+	}
+		
+	XStoreColors(mDisplay, cmap, cols, cm_size);
+	XFlush(mDisplay);
+	return VO_TRUE;
+}
+
+uint32_t vo_x11_get_equalizer(char *name, int *value)
+{
+	if (cmap == None) return VO_NOTAVAIL;
+	if (!strcasecmp(name, "brightness")) *value = vo_brightness;
+	else if (!strcasecmp(name, "contrast")) *value = vo_contrast;
+	else if (!strcasecmp(name, "gamma")) *value = vo_gamma;
+	else return VO_NOTIMPL;
+}
+
+
--- a/libvo/x11_common.h	Tue Oct 29 20:12:24 2002 +0000
+++ b/libvo/x11_common.h	Tue Oct 29 20:27:47 2002 +0000
@@ -36,6 +36,9 @@
 extern void vo_x11_selectinput_witherr(Display *display, Window w, long event_mask);
 extern void vo_x11_fullscreen( void );
 extern void vo_x11_uninit();
+extern Colormap vo_x11_create_colormap(XVisualInfo *vinfo);
+extern uint32_t vo_x11_set_equalizer(char *name, int value);
+extern uint32_t vo_x11_get_equalizer(char *name, int *value);
 
 #endif