changeset 7069:21e1ab99cb21

General Timing Formula algorithm from a scratch. vo_vesa.c so now adjust the timing to highest possible refresh rate using the monitor capabilities from a config file. patch by Rudolf Marek <MAREKR2@cs.felk.cvut.cz>
author arpi
date Thu, 22 Aug 2002 23:03:51 +0000
parents 6c2d746b17bf
children aaac9080b8a3
files cfg-mplayer.h libvo/Makefile libvo/gtf.c libvo/gtf.h libvo/video_out.c libvo/video_out.h libvo/vo_fbdev.c libvo/vo_vesa.c linux/vbelib.c linux/vbelib.h
diffstat 10 files changed, 552 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/cfg-mplayer.h	Thu Aug 22 21:30:31 2002 +0000
+++ b/cfg-mplayer.h	Thu Aug 22 23:03:51 2002 +0000
@@ -6,13 +6,16 @@
 
 extern int use_stdin;
 
+#if defined(HAVE_FBDEV)||defined(HAVE_VESA)
+extern char *monitor_hfreq_str;
+extern char *monitor_vfreq_str;
+extern char *monitor_dotclock_str;
+#endif
+
 #ifdef HAVE_FBDEV
 extern char *fb_dev_name;
 extern char *fb_mode_cfgfile;
 extern char *fb_mode_name;
-extern char *monitor_hfreq_str;
-extern char *monitor_vfreq_str;
-extern char *monitor_dotclock_str;
 #else
 #ifdef HAVE_DIRECTFB
 extern char *fb_dev_name;
--- a/libvo/Makefile	Thu Aug 22 21:30:31 2002 +0000
+++ b/libvo/Makefile	Thu Aug 22 23:03:51 2002 +0000
@@ -3,7 +3,7 @@
 
 LIBNAME = libvo.a
 
-SRCS=aspect.c aclib.c osd.c font_load.c spuenc.c video_out.c vo_null.c vo_pgm.c vo_md5.c vo_mpegpes.c vo_yuv4mpeg.c $(OPTIONAL_SRCS) sub.c
+SRCS=aspect.c aclib.c osd.c font_load.c gtf.c spuenc.c video_out.c vo_null.c vo_pgm.c vo_md5.c vo_mpegpes.c vo_yuv4mpeg.c $(OPTIONAL_SRCS) sub.c
 OBJS=$(SRCS:.c=.o)
 
 ifeq ($(VIDIX),yes)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvo/gtf.c	Thu Aug 22 23:03:51 2002 +0000
@@ -0,0 +1,297 @@
+/*
+ *      Copyright (C) Rudolf Marek <r.marek@sh.cvut.cz> - Aug 2002
+ *
+ *  You can redistribute this file under terms and conditions
+ *  of GNU General Public licence v2.
+ * 
+ *  GTF calculations formulas are taken from GTF_V1R1.xls
+ *  created by ANDY.MORRISH@NSC.COM
+ */
+       
+//Version 0.4
+#include <stdio.h> 
+#include <stdlib.h> 
+#include <math.h> 
+#include "gtf.h"
+
+#undef GTF_DEBUG
+
+#ifdef GTF_DEBUG
+#define DEBUG_PRINTF(a,b) printf(a,b);
+#else
+#define DEBUG_PRINTF(a,b)
+#endif
+
+static GTF_constants GTF_given_constants = { 3.0,550.0,1,8,1.8,8,40,20,128,600 };
+
+static double round(double v) 
+{ 
+        return floor(v + 0.5); 
+} 
+	
+static void GetRoundedConstants(GTF_constants *c)
+    {
+    c->Vsync_need = round(GTF_given_constants.Vsync_need);
+    c->min_Vsync_BP = GTF_given_constants.min_Vsync_BP;
+    c->min_front_porch = round(GTF_given_constants.min_front_porch);
+    c->char_cell_granularity = GTF_given_constants.char_cell_granularity;
+    c->margin_width = GTF_given_constants.margin_width;
+    c->sync_width = GTF_given_constants.sync_width;
+    c->c = ((GTF_given_constants.c - GTF_given_constants.j)*(GTF_given_constants.k / 256)) + GTF_given_constants.j;
+    c->j = GTF_given_constants.j;
+    c->k = GTF_given_constants.k;
+    c->m = (GTF_given_constants.k / 256) * GTF_given_constants.m;
+    }
+
+void GTF_calcTimings(double X,double Y,double freq, int type,  
+		     int want_margins, int want_interlace,struct VesaCRTCInfoBlock *result )
+{
+    GTF_constants   c;
+    double RR, margin_top, margin_bottom, margin_left, margin_right;
+    double estimated_H_period,sync_plus_BP,BP,interlace,V_total_lines_field;
+    double estimated_V_field_rate,actual_H_period,actual_V_field_freq;
+    double total_active_pixels, ideal_duty_cycle, blanking_time, H_total_pixels;
+    double H_freq, pixel_freq,actual_V_frame_freq;
+    double H_sync_start, H_sync_end, H_back_porch, H_front_porch, H_sync_width;
+    double V_back_porch, V_front_porch, V_sync_start, V_sync_end,V_sync_width;    
+    double ideal_H_period;
+    GetRoundedConstants(&c);
+
+    
+    pixel_freq = RR = freq;
+
+    /* DETERMINE IF 1/2 LINE INTERLACE IS PRESENT */
+    
+    interlace = 0;    
+    
+    if (want_interlace) {
+    RR = RR * 2;    
+    Y=Y/2;
+    interlace = 0.5;
+    }
+    
+    result->Flags = 0;
+    
+    if ((Y==300)||(Y==200)||(Y==240))
+    {
+    Y*=2;
+    result->Flags = VESA_CRTC_DOUBLESCAN; /* TODO: check if mode support   */
+    }			
+    
+    /* DETERMINE NUMBER OF LINES IN V MARGIN */
+    /* DETERMINE NUMBER OF PIXELS IN H MARGIN [pixels] */
+    
+    margin_left = margin_right = 0;
+    margin_top = margin_bottom = 0;
+    
+    if (want_margins) {
+	margin_top = margin_bottom = (c.margin_width / 100) * Y;
+        margin_left = round(( X* c.margin_width/100)/c.char_cell_granularity) \
+		    * c.char_cell_granularity;
+    margin_right = margin_left;
+    DEBUG_PRINTF("margin_left_right : %f\n",margin_right)
+    DEBUG_PRINTF("margin_top_bottom : %f\n",margin_top)
+    } 
+    
+    /* FIND TOTAL NUMBER OF ACTIVE PIXELS (IMAGE + MARGIN) [pixels] */        
+    
+    total_active_pixels = margin_left + margin_right + X;
+    DEBUG_PRINTF("total_active_pixels: %f\n",total_active_pixels)
+
+    if (type == GTF_PF)
+    {
+    ideal_H_period = ((c.c-100)+(sqrt(((100-c.c)*(100-c.c) )+(0.4*c.m*(total_active_pixels + margin_left + margin_right) / freq))))/2/c.m*1000; 
+    
+    DEBUG_PRINTF("ideal_H_period: %f\n",ideal_H_period)
+    
+    /* FIND IDEAL BLANKING DUTY CYCLE FROM FORMULA [%] */
+    ideal_duty_cycle = c.c - (c.m * ideal_H_period /1000);
+    DEBUG_PRINTF("ideal_duty_cycle: %f\n",ideal_duty_cycle)
+
+    /* FIND BLANKING TIME (TO NEAREST CHAR CELL) [pixels] */
+    
+    blanking_time = round(total_active_pixels * ideal_duty_cycle \
+		    / (100-ideal_duty_cycle) / (2*c.char_cell_granularity))  \
+		    * (2*c.char_cell_granularity);
+    DEBUG_PRINTF("blanking_time : %f\n",blanking_time )
+
+    /* FIND TOTAL NUMBER OF PIXELS IN A LINE [pixels] */		    
+    H_total_pixels = total_active_pixels + blanking_time ;
+    DEBUG_PRINTF("H_total_pixels: %f\n",H_total_pixels)
+    H_freq = freq / H_total_pixels * 1000;
+    DEBUG_PRINTF("H_freq: %f\n",H_freq)
+    actual_H_period = 1000 / H_freq;
+    DEBUG_PRINTF("actual_H_period: %f\n",actual_H_period)
+    sync_plus_BP = round(H_freq * c.min_Vsync_BP/1000);
+//   sync_plus_BP = round( freq / H_total_pixels * c.min_Vsync_BP);
+   
+    DEBUG_PRINTF("sync_plus_BP: %f\n",sync_plus_BP)
+
+    } else if (type == GTF_VF) 
+    {
+    
+    /* ESTIMATE HORIZ. PERIOD [us] */
+
+    estimated_H_period = (( 1/RR ) - c.min_Vsync_BP/1000000 ) /  (Y + (2 * margin_top) + c.min_front_porch + interlace) * 1000000;
+    
+    DEBUG_PRINTF("estimated_H_period: %f\n",estimated_H_period)
+
+    /* FIND NUMBER OF LINES IN (SYNC + BACK PORCH) [lines] */
+    
+    sync_plus_BP = round( c.min_Vsync_BP / estimated_H_period );
+    DEBUG_PRINTF("sync_plus_BP: %f\n",sync_plus_BP)
+
+    } else if (type == GTF_HF)
+    {
+    sync_plus_BP = round(freq * c.min_Vsync_BP/1000);
+    DEBUG_PRINTF("sync_plus_BP: %f\n",sync_plus_BP)
+    }
+    
+    
+    
+    /* FIND TOTAL NUMBER OF LINES IN VERTICAL FIELD */
+
+    V_total_lines_field = sync_plus_BP+interlace+margin_bottom+margin_top+Y+c.min_front_porch;
+    DEBUG_PRINTF("V_total_lines_field : %f\n",V_total_lines_field )
+
+    if (type == GTF_VF)
+    {
+    /* ESTIMATE VERTICAL FIELD RATE [hz] */
+    
+    estimated_V_field_rate = 1 / estimated_H_period / V_total_lines_field * 1000000;
+    DEBUG_PRINTF(" estimated_V_field_rate: %f\n", estimated_V_field_rate)
+    /* FIND ACTUAL HORIZONTAL PERIOD [us] */
+    
+    actual_H_period = estimated_H_period / (RR / estimated_V_field_rate);
+    DEBUG_PRINTF("actual_H_period: %f\n",actual_H_period)
+    /* FIND ACTUAL VERTICAL FIELD FREQUENCY [Hz] */
+
+    actual_V_field_freq = 1 / actual_H_period / V_total_lines_field * 1000000;
+    DEBUG_PRINTF("actual_V_field_freq: %f\n",actual_V_field_freq)
+
+    /* FIND IDEAL BLANKING DUTY CYCLE FROM FORMULA [%] */
+    ideal_duty_cycle = c.c - (c.m * actual_H_period /1000);
+    DEBUG_PRINTF("ideal_duty_cycle: %f\n",ideal_duty_cycle)
+    //if (type == GTF_VF)
+    //{
+    //moved
+    //}
+    } else if (type == GTF_HF)
+    {
+    /* FIND IDEAL BLANKING DUTY CYCLE FROM FORMULA [%] */
+    ideal_duty_cycle = c.c - (c.m  / freq);
+    DEBUG_PRINTF("ideal_duty_cycle: %f\n",ideal_duty_cycle)
+    }
+
+    /* FIND BLANKING TIME (TO NEAREST CHAR CELL) [pixels] */
+
+    if (!(type == GTF_PF))
+    {
+    blanking_time = round(total_active_pixels * ideal_duty_cycle \
+		    / (100-ideal_duty_cycle) / (2*c.char_cell_granularity))  \
+		    * (2*c.char_cell_granularity);
+    DEBUG_PRINTF("blanking_time : %f\n",blanking_time )
+    }
+    else
+//    if (type == GTF_PF)
+    {
+    actual_V_field_freq = H_freq / V_total_lines_field * 1000;
+    }
+
+    if (type == GTF_HF)
+    {
+    /* Hz */
+    actual_V_field_freq = freq / V_total_lines_field * 1000;
+    DEBUG_PRINTF("actual_V_field_freq: %f\n",actual_V_field_freq)    
+    }
+    
+        
+    actual_V_frame_freq = actual_V_field_freq;
+
+    /* FIND ACTUAL VERTICAL  FRAME FREQUENCY [Hz]*/
+    
+    if (want_interlace) actual_V_frame_freq = actual_V_field_freq / 2;
+    DEBUG_PRINTF("actual_V_frame_freq: %f\n",actual_V_frame_freq)
+    
+//    V_freq = actual_V_frame_freq;
+//    DEBUG_PRINTF("V_freq %f\n",V_freq)    
+
+    
+    if (!(type == GTF_PF))
+    {    
+    /* FIND TOTAL NUMBER OF PIXELS IN A LINE [pixels] */		    
+    H_total_pixels = total_active_pixels + blanking_time ;
+    DEBUG_PRINTF("H_total_pixels: %f\n",H_total_pixels)
+        if (type == GTF_VF)
+	{
+	/* FIND PIXEL FREQUENCY [Mhz] */
+	pixel_freq = H_total_pixels / actual_H_period ;
+	DEBUG_PRINTF("pixel_freq: %f\n",pixel_freq)
+	} else if (type == GTF_HF)
+	{
+	/* FIND PIXEL FREQUENCY [Mhz] */
+	pixel_freq = H_total_pixels * freq / 1000 ;
+	DEBUG_PRINTF("pixel_freq: %f\n",pixel_freq)
+	actual_H_period = 1000/freq;
+	}
+
+        /* FIND ACTUAL HORIZONTAL FREQUENCY [KHz] */
+    
+        H_freq = 1000 / actual_H_period;
+	DEBUG_PRINTF("H_freq %f\n",H_freq)
+
+    
+    }
+
+    /* FIND NUMBER OF LINES IN BACK PORCH [lines] */
+    
+    BP = sync_plus_BP - c.Vsync_need;
+    DEBUG_PRINTF("BP: %f\n",BP)
+
+/*------------------------------------------------------------------------------------------------*/
+    /* FIND H SYNC WIDTH (TO NEAREST CHAR CELL) */
+    H_sync_width = round(c.sync_width/100*H_total_pixels/c.char_cell_granularity)*c.char_cell_granularity;
+    DEBUG_PRINTF("H_sync_width %f\n",H_sync_width)
+
+    /* FIND FRONT H PORCH(TO NEAREST CHAR CELL) */
+    H_front_porch = (blanking_time/2) - H_sync_width;
+    DEBUG_PRINTF("H_front_porch %f\n",H_front_porch)    
+    /* FIND BACK H PORCH(TO NEAREST CHAR CELL) */
+    H_back_porch = H_sync_width + H_front_porch;
+    DEBUG_PRINTF("H_back_porch%f\n",H_back_porch)  
+
+    H_sync_start = H_total_pixels  - (H_sync_width + H_back_porch);
+    DEBUG_PRINTF("H_sync_start %f\n",H_sync_start)
+    H_sync_end = H_total_pixels  - H_back_porch;
+    DEBUG_PRINTF("H_sync_end %f\n",H_sync_end) 
+    
+    V_back_porch = interlace + BP;
+    DEBUG_PRINTF("V_back_porch%f\n",V_back_porch)
+    V_front_porch = interlace + c.min_front_porch;
+    DEBUG_PRINTF("V_front_porch%f\n",V_front_porch)   
+    
+    V_sync_width = c.Vsync_need;
+    V_sync_start = V_total_lines_field  - (V_sync_width + V_back_porch);
+    DEBUG_PRINTF("V_sync_start %f\n",V_sync_start)    
+    V_sync_end = V_total_lines_field  - V_back_porch;
+    DEBUG_PRINTF("V_sync_end %f\n",V_sync_end) 
+    
+    result->hTotal = H_total_pixels;
+    result-> hSyncStart  = H_sync_start;  /* Horizontal sync start in pixels */
+    result-> hSyncEnd = H_sync_end;   /* Horizontal sync end in pixels */
+    result-> vTotal= V_total_lines_field;     /* Vertical total in lines */
+    result-> vSyncStart = V_sync_start; /* Vertical sync start in lines */
+    result-> vSyncEnd = V_sync_end;   /* Vertical sync end in lines */
+    result->  Flags = (result->Flags)|VESA_CRTC_HSYNC_NEG;      /* Flags (Interlaced, Double Scan etc) */
+    
+    if (want_interlace) 
+    {
+    result->Flags = (result->Flags) | VESA_CRTC_INTERLACED;
+    }
+   
+    result->  PixelClock = pixel_freq*1000000; /* Pixel clock in units of Hz */
+    result-> RefreshRate = actual_V_frame_freq*100;/* Refresh rate in units of 0.01 Hz*/
+					
+    }
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvo/gtf.h	Thu Aug 22 23:03:51 2002 +0000
@@ -0,0 +1,48 @@
+#ifndef __GTF_H
+#define __GTF_H
+
+#include "linux/vbelib.h"
+
+#define GTF_VF 0 
+#define GTF_HF 1 
+#define GTF_PF 2
+
+		     
+typedef struct {
+    double	Vsync_need;	   /* Number of lines for vert sync (default 3) */
+    double	min_Vsync_BP;	   /* Minimum vertical sync + back porch (us) (default 550)*/
+    double	min_front_porch;   /* Minimum front porch in lines (default 1)	*/
+    double	char_cell_granularity;  /* Character cell granularity in pixels (default 8) */
+    double	margin_width;	   /* Top/ bottom MARGIN size as % of height (%) (default 1.8) */
+    double	sync_width;	  /* Sync width percent of line period ( default 8) */
+    double  c;		/* Blanking formula offset (default 40)*/
+    double  j;		/* Blanking formula scaling factor weight (default 20)*/
+    double  k;		/* Blanking formula scaling factor (default 128)*/
+    double  m;		/* Blanking formula gradient (default 600)*/
+    } GTF_constants;
+
+//#ifndef __VESA_VBELIB_INCLUDED__ 
+//    struct VesaCRTCInfoBlock {
+//    unsigned short hTotal;     /* Horizontal total in pixels */
+//    unsigned short hSyncStart; /* Horizontal sync start in pixels */
+//    unsigned short hSyncEnd;   /* Horizontal sync end in pixels */
+//    unsigned short vTotal;     /* Vertical total in lines */
+//    unsigned short vSyncStart; /* Vertical sync start in lines */
+//    unsigned short vSyncEnd;   /* Vertical sync end in lines */
+//    unsigned char  Flags;      /* Flags (Interlaced, Double Scan etc) */
+//    unsigned long  PixelClock; /* Pixel clock in units of Hz */
+//    unsigned short RefreshRate;/* Refresh rate in units of 0.01 Hz*/
+//    unsigned char  Reserved[40];/* remainder of CRTCInfoBlock*/
+//}__attribute__ ((packed));		    
+
+//#define VESA_CRTC_DOUBLESCAN 0x01
+//#define VESA_CRTC_INTERLACED 0x02
+//#define VESA_CRTC_HSYNC_NEG  0x04
+//#define VESA_CRTC_VSYNC_NEG  0x08
+
+//#endif
+
+void GTF_calcTimings(double X,double Y,double freq, int type,
+                     int want_margins, int want_interlace,struct VesaCRTCInfoBlock *result);
+
+#endif
--- a/libvo/video_out.c	Thu Aug 22 21:30:31 2002 +0000
+++ b/libvo/video_out.c	Thu Aug 22 23:03:51 2002 +0000
@@ -201,3 +201,85 @@
   vo_dxr2_register_options(cfg);
 #endif
 }
+#if defined(HAVE_FBDEV)||defined(HAVE_VESA)  
+/* Borrowed from vo_fbdev.c 
+Monitor ranges related functions*/
+
+char *monitor_hfreq_str = NULL;
+char *monitor_vfreq_str = NULL;
+char *monitor_dotclock_str = NULL;
+
+float range_max(range_t *r)
+{
+float max = 0;
+
+	for (/* NOTHING */; (r->min != -1 && r->max != -1); r++)
+		if (max < r->max) max = r->max;
+	return max;
+}
+
+
+int in_range(range_t *r, float f)
+{
+	for (/* NOTHING */; (r->min != -1 && r->max != -1); r++)
+		if (f >= r->min && f <= r->max)
+			return 1;
+	return 0;
+}
+
+range_t *str2range(char *s)
+{
+	float tmp_min, tmp_max;
+	char *endptr = s;	// to start the loop
+	range_t *r = NULL;
+	int i;
+
+	if (!s)
+		return NULL;
+	for (i = 0; *endptr; i++) {
+		if (*s == ',')
+			goto out_err;
+		if (!(r = (range_t *) realloc(r, sizeof(*r) * (i + 2)))) {
+			printf("can't realloc 'r'\n");
+			return NULL;
+		}
+		tmp_min = strtod(s, &endptr);
+		if (*endptr == 'k' || *endptr == 'K') {
+			tmp_min *= 1000.0;
+			endptr++;
+		} else if (*endptr == 'm' || *endptr == 'M') {
+			tmp_min *= 1000000.0;
+			endptr++;
+		}
+		if (*endptr == '-') {
+			tmp_max = strtod(endptr + 1, &endptr);
+			if (*endptr == 'k' || *endptr == 'K') {
+				tmp_max *= 1000.0;
+				endptr++;
+			} else if (*endptr == 'm' || *endptr == 'M') {
+				tmp_max *= 1000000.0;
+				endptr++;
+			}
+			if (*endptr != ',' && *endptr)
+				goto out_err;
+		} else if (*endptr == ',' || !*endptr) {
+			tmp_max = tmp_min;
+		} else
+			goto out_err;
+		r[i].min = tmp_min;
+		r[i].max = tmp_max;
+		if (r[i].min < 0 || r[i].max < 0)
+			goto out_err;
+		s = endptr + 1;
+	}
+	r[i].min = r[i].max = -1;
+	return r;
+out_err:
+	if (r)
+		free(r);
+	return NULL;
+}
+
+/* Borrowed from vo_fbdev.c END */
+#endif
+
--- a/libvo/video_out.h	Thu Aug 22 21:30:31 2002 +0000
+++ b/libvo/video_out.h	Thu Aug 22 23:03:51 2002 +0000
@@ -241,4 +241,20 @@
 
 extern char *vo_subdevice;
 
+#if defined(HAVE_FBDEV)||defined(HAVE_VESA) 
+
+typedef struct {
+        float min;
+	float max;
+	} range_t;
+
+extern float range_max(range_t *r);
+extern int in_range(range_t *r, float f);
+extern range_t *str2range(char *s);
+extern char *monitor_hfreq_str;
+extern char *monitor_vfreq_str;
+extern char *monitor_dotclock_str;
+
+#endif 
+		
 #endif
--- a/libvo/vo_fbdev.c	Thu Aug 22 21:30:31 2002 +0000
+++ b/libvo/vo_fbdev.c	Thu Aug 22 23:03:51 2002 +0000
@@ -57,6 +57,14 @@
 *	fb.modes support      *
 ******************************/
 
+extern char *monitor_hfreq_str;
+extern char *monitor_vfreq_str;
+extern char *monitor_dotclock_str;
+
+static range_t *monitor_hfreq = NULL;
+static range_t *monitor_vfreq = NULL;
+static range_t *monitor_dotclock = NULL;
+
 typedef struct {
 	char *name;
 	uint32_t xres, yres, vxres, vyres, depth;
@@ -396,18 +404,6 @@
 	return hsf(m) / vtotal;
 }
 
-typedef struct {
-	float min;
-	float max;
-} range_t;
-
-static int in_range(range_t *r, float f)
-{
-	for (/* NOTHING */; (r->min != -1 && r->max != -1); r++)
-		if (f >= r->min && f <= r->max)
-			return 1;
-	return 0;
-}
 
 static int mode_works(fb_mode_t *m, range_t *hfreq, range_t *vfreq,
 		range_t *dotclock)
@@ -558,58 +554,6 @@
 	v->vmode = m->vmode;
 }
 
-static range_t *str2range(char *s)
-{
-	float tmp_min, tmp_max;
-	char *endptr = s;	// to start the loop
-	range_t *r = NULL;
-	int i;
-
-	if (!s)
-		return NULL;
-	for (i = 0; *endptr; i++) {
-		if (*s == ',')
-			goto out_err;
-		if (!(r = (range_t *) realloc(r, sizeof(*r) * (i + 2)))) {
-			printf("can't realloc 'r'\n");
-			return NULL;
-		}
-		tmp_min = strtod(s, &endptr);
-		if (*endptr == 'k' || *endptr == 'K') {
-			tmp_min *= 1000.0;
-			endptr++;
-		} else if (*endptr == 'm' || *endptr == 'M') {
-			tmp_min *= 1000000.0;
-			endptr++;
-		}
-		if (*endptr == '-') {
-			tmp_max = strtod(endptr + 1, &endptr);
-			if (*endptr == 'k' || *endptr == 'K') {
-				tmp_max *= 1000.0;
-				endptr++;
-			} else if (*endptr == 'm' || *endptr == 'M') {
-				tmp_max *= 1000000.0;
-				endptr++;
-			}
-			if (*endptr != ',' && *endptr)
-				goto out_err;
-		} else if (*endptr == ',' || !*endptr) {
-			tmp_max = tmp_min;
-		} else
-			goto out_err;
-		r[i].min = tmp_min;
-		r[i].max = tmp_max;
-		if (r[i].min < 0 || r[i].max < 0)
-			goto out_err;
-		s = endptr + 1;
-	}
-	r[i].min = r[i].max = -1;
-	return r;
-out_err:
-	if (r)
-		free(r);
-	return NULL;
-}
 
 /******************************
 *	    vo_fbdev	      *
@@ -619,14 +563,7 @@
 char *fb_dev_name = NULL;
 char *fb_mode_cfgfile = "/etc/fb.modes";
 char *fb_mode_name = NULL;
-char *monitor_hfreq_str = NULL;
-char *monitor_vfreq_str = NULL;
-char *monitor_dotclock_str = NULL;
 
-/* fb.modes related variables */
-static range_t *monitor_hfreq = NULL;
-static range_t *monitor_vfreq = NULL;
-static range_t *monitor_dotclock = NULL;
 static fb_mode_t *fb_mode = NULL;
 
 /* vt related variables */
--- a/libvo/vo_vesa.c	Thu Aug 22 21:30:31 2002 +0000
+++ b/libvo/vo_vesa.c	Thu Aug 22 23:03:51 2002 +0000
@@ -16,7 +16,7 @@
   - refresh rate support (need additional info from mplayer)
 */
 #include "config.h"
-
+#include "gtf.h"
 #include <stdio.h>
 #ifdef HAVE_MALLOC_H
 #include <malloc.h>
@@ -54,6 +54,10 @@
 
 extern int verbose;
 
+extern char *monitor_hfreq_str;
+extern char *monitor_vfreq_str;
+extern char *monitor_dotclock_str;
+
 #define MAX_BUFFERS 3
 
 #ifndef max
@@ -523,18 +527,69 @@
   return i;
 }
 
+static int set_refresh(unsigned x, unsigned y, unsigned mode,struct VesaCRTCInfoBlock *crtc_pass)
+{
+    unsigned pixclk;
+    float H_freq;
+    
+    range_t *monitor_hfreq = NULL;
+    range_t *monitor_vfreq = NULL;
+    range_t *monitor_dotclock = NULL;
 
+    monitor_hfreq = str2range(monitor_hfreq_str);
+    monitor_vfreq = str2range(monitor_vfreq_str);
+    monitor_dotclock = str2range(monitor_dotclock_str);
+    
+		if (!monitor_hfreq || !monitor_vfreq || !monitor_dotclock) {
+			printf("vo_vesa: you have to specify the capabilities of"
+					" the monitor. Not changing refresh rate.\n");
+			return 0;
+		}
+
+    H_freq = range_max(monitor_hfreq)/1000;
+    
+//    printf("H_freq MAX %f\n",H_freq);
+    
+    do
+    {
+    H_freq -= 0.1;
+    GTF_calcTimings(x,y,H_freq,GTF_HF,0, 0,crtc_pass);		      
+//    printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);    
+    }
+    while (!in_range(monitor_vfreq,crtc_pass->RefreshRate/100));
+    
+    pixclk = crtc_pass->PixelClock;
+//    printf("PIXclk before %d\n",pixclk);
+    vbeGetPixelClock(&mode,&pixclk); 
+//    printf("PIXclk after %d\n",pixclk);
+    GTF_calcTimings(x,y,pixclk/1000000,GTF_PF,0,0,crtc_pass);
+//    printf("Flags: %x\n",(unsigned) crtc_pass->Flags);
+/*    
+    printf("hTotal %d\n",crtc_pass->hTotal);
+    printf("hSyncStart %d\n",crtc_pass->hSyncStart);
+    printf("hSyncEnd %d\n",crtc_pass->hSyncEnd);
+    
+    printf("vTotal %d\n",crtc_pass->vTotal);
+    printf("vSyncStart %d\n",crtc_pass->vSyncStart);
+    printf("vSyncEnd %d\n",crtc_pass->vSyncEnd);
+    
+    printf("RR %d\n",crtc_pass->RefreshRate);
+    printf("PixelCLK %d\n",(unsigned)crtc_pass->PixelClock);*/
+    return 1;
+}
 /* fullscreen:
  * bit 0 (0x01) means fullscreen (-fs)
  * bit 1 (0x02) means mode switching (-vm)
  * bit 2 (0x04) enables software scaling (-zoom)
  * bit 3 (0x08) enables flipping (-flip) (NK: and for what?)
  */
+
 static uint32_t
 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format,const vo_tune_info_t *info)
 {
-  struct VbeInfoBlock vib;
+  struct VbeInfoBlock vib;  
   struct VesaModeInfoBlock vmib;
+  struct VesaCRTCInfoBlock crtc_pass;
   size_t i,num_modes;
   uint32_t w,h;
   unsigned short *mode_ptr,win_seg;
@@ -831,11 +886,26 @@
 			PRINT_VBE_ERR("vbeSaveState",err);
 			return -1;
 		}
-		if((err=vbeSetMode(video_mode,NULL)) != VBE_OK)
+		/* TODO: check for VBE 3, monitor limitation
+		         user might pass refresh value
+			 GTF constants might be read from monitor
+			 for best results
+		*/
+		if (((int)(vib.VESAVersion >> 8) & 0xff) > 2) {
+		
+		if (set_refresh(dstW,dstH,video_mode,&crtc_pass))
+		video_mode = video_mode | 0x800;
+		
+		}
+		
+		;
+		
+		if ((err=vbeSetMode(video_mode,&crtc_pass)) != VBE_OK)
 		{
 			PRINT_VBE_ERR("vbeSetMode",err);
 			return -1;
 		}
+		
 		/* Now we are in video mode!!!*/
 		/* Below 'return -1' is impossible */
 		if(verbose)
--- a/linux/vbelib.c	Thu Aug 22 21:30:31 2002 +0000
+++ b/linux/vbelib.c	Thu Aug 22 23:03:51 2002 +0000
@@ -376,6 +376,26 @@
   return retval;
 }
 
+int vbeGetPixelClock(unsigned *mode,unsigned *pixel_clock) // in Hz
+{
+  struct LRMI_regs r;
+  int retval;
+  memset(&r,0,sizeof(struct LRMI_regs));
+  r.eax = 0x4f0b;
+  r.ebx = 0;
+  r.edx = *mode;
+  r.ecx = *pixel_clock;
+  if(!VBE_LRMI_int(0x10,&r)) return VBE_VM86_FAIL;
+  retval = r.eax & 0xffff;
+  if(retval == 0x4f)
+  {
+    *pixel_clock = r.ecx;
+    retval = VBE_OK;
+  }
+  return retval;
+}
+
+
 int vbeSaveState(void **data)
 {
   struct LRMI_regs r;
--- a/linux/vbelib.h	Thu Aug 22 21:30:31 2002 +0000
+++ b/linux/vbelib.h	Thu Aug 22 23:03:51 2002 +0000
@@ -199,6 +199,7 @@
 extern int vbeGetModeInfo(unsigned mode,struct VesaModeInfoBlock *);
 extern int vbeSetMode(unsigned mode,struct VesaCRTCInfoBlock *);
 extern int vbeGetMode(unsigned *mode);
+extern int vbeGetPixelClock(unsigned *mode,unsigned *pixel_clock);
 extern int vbeSaveState(void **data); /* note never copy this data */
 extern int vbeRestoreState(void *data);
 extern int vbeGetWindow(unsigned *win_num); /* win_A=0 or win_B=1 */