diff -ru --exclude CVS mplayer.orig/libmpcodecs/vf_framestep.c mplayer/libmpcodecs/vf_framestep.c --- mplayer.orig/libmpcodecs/vf_framestep.c 2003-11-28 14:05:01.000000000 +0100 +++ mplayer/libmpcodecs/vf_framestep.c 2003-11-28 13:20:09.000000000 +0100 @@ -45,6 +45,17 @@ * As usual it depends on what you're doing. * * Daniele Forghieri ( guru@digitalfantasy.it ) + * + * patch by errror@gmx.de: + * + * you can specify a "keep"-ratio by giving 2 instead of only one + * integer parameters. This gives a ratio of frames, that should be + * kept, e.g. if you use framestep=3:4, you get three quarters of the + * total number of frames, meaning the framerate is reduced to tree + * quartes of it. This is particular useful for converting NTSC + * material to mpeg: use framestep=2500/2997 to get a framerate of + * 25.0 out of material with a framerate of 29.97! + * */ #include @@ -64,12 +75,56 @@ /* Uncomment if you want to print some info on the format */ // #define DUMP_FORMAT_DATA +/* rational numbers */ +static int64_t greatest_common_divisor(int64_t a, int64_t b) { + if(a == 0 || b == 0) return 0; // gcd(0, x) = gcd(x, 0) = 0 + + if(a < 0) { // make sure that the two integers are non-negative + a = -a; + } + + if(b < 0) { + b = -b; + } + + int64_t t = 1; // and perform Euklid's algorithm + while(t != 0) { + t = a % b; + a = b; + b = t; + } + + return a; +} + +static void rat_reduce(int64_t* num, int64_t* denom) { + if(*num == 0) { + *denom = 1; + return; + } + + int64_t gcd = greatest_common_divisor(*num, *denom); + *num /= gcd; + *denom /= gcd; +} + +static void rat_add_to(int64_t* s_num, int64_t* s_denom, + int64_t a_num, int64_t a_denom, + int64_t b_num, int64_t b_denom) { + *s_num = a_num * b_denom + b_num * a_denom; + *s_denom = a_denom * b_denom; + rat_reduce(s_num, s_denom); +} + /* Private data */ struct vf_priv_s { /* Current frame */ int frame_cur; /* Frame output step, 0 = all */ - int frame_step; + int64_t frame_step; + int64_t frame_step_denom; + int64_t ratio_count; + int64_t ratio_count_denom; /* Only I-Frame (2), print on I-Frame (1) */ int dump_iframe; }; @@ -98,11 +153,28 @@ skip = mpi->pict_type == 1 ? 0 : 1; } else { + if (priv->frame_step_denom == 1) { /* Only 1 every frame_step */ skip = 0; if ((priv->frame_step != 0) && ((priv->frame_cur % priv->frame_step) != 0)) { skip = 1; } + } else { + /* keep drop_ratio (rational) frames */ + int64_t old_int = 0; + int64_t new_int = 0; + + old_int = priv->ratio_count / priv->ratio_count_denom; + rat_add_to(&priv->ratio_count, &priv->ratio_count_denom, + priv->ratio_count, priv->ratio_count_denom, + priv->frame_step, priv->frame_step_denom); + new_int = priv->ratio_count / priv->ratio_count_denom; + if (old_int < new_int) { + skip = 0; + } else { + skip = 1; + } + } } /* Increment current frame */ ++priv->frame_cur; @@ -170,11 +242,19 @@ } if (*args != '\0') { - p->frame_step = atoi(args); - if (p->frame_step <= 0) { - printf("Error parsing argument\n"); - return(0); - } + int64_t num = 0; + int64_t denom = 1; + int scaned = sscanf(args, "%d:%d", &num, &denom); + if ((scaned == 0) || /* no args scaned */ + (num <= 0)) { /* drop every -4th frame? */ + printf("Error parsing arguments: scaned=%d, num=%d, denom=%d\n", scaned, num, denom); + return(0); + } + rat_reduce(&num, &denom); + p->frame_step = num; + p->frame_step_denom = denom; + p->ratio_count = 0; + p->ratio_count_denom = 1; } } }