framerate conversion using framestep filter
Patrick Cernko <[email protected]>
| Newsgroups | gmane.comp.video.mplayer.user.dvb,gmane.comp.video.mplayer.devel |
|---|---|
| Organization | Universitaet des Saarlandes, Fachbereich Informatik |
| Message-ID | <[email protected]> |
Hi list, the appended patch against the current cvs enhances the framestep filter to not only drop every nth frame, but to be able to set a "keep"-ratio, a fraction, how many frames should (not) be droped. With this enhancement, it is possible to do easy framerate conversion (only dowmwards) by specifying a fraction of new and original framerate. For example to convert NTSC material to PAL framerate, use: ... -vf framestep=2500:2997 ... I have to use this for outputing NTSC material to my DVB-card. My card of course also could decode NTSC material, by my TV set is unable to present it in color (a really loosy one! :-( ). As I did not find a way to use any other filter (mencoder's -ofps option is not usable when preseting with mplayer), I patched the one, which already had most of the stuff. I only _added_ a new feature. I hope I did not overlook any case, so no old features should be broken. The implementation uses int64_t-based rationals to have highest precision. Although a int32_t-based implementation would have been enough for easy cases like 3/4 or 15/16, the above example of conversion from 29.97 to 25.0 requires 64Bit-precision to avoid computational overflows. Using the rational-implementation, you get the most even drop distribution. I hope this patch can make it in future versions of mplayer. P.S.: @mplayer-dev-eng: As I have not subscribed your list, I would be happy, if someone could send me a little note, if my patch made it into cvs or was rejected. -- Patrick Cernko | mailto:[email protected] | http://www.errror.de Quote of the Week: "/vmlinuz does not exist. Installing from scratch, eh?" (Debian Kernel Installation) _______________________________________________ Mplayer-dvb mailing list [email protected] http://mplayerhq.hu/mailman/listinfo/mplayer-dvb
mplayer-framestep-rational.diff
(text/plain, 4.1 KB)
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 ( [email protected] ) + * + * patch by [email protected]: + * + * 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 <stdio.h> @@ -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; } } }
signature.asc
(application/pgp-signature, 252 B)
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.3 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQE/x1bTB6g1EUxThvcRAt4sAKCP4T7NnWgKb67q6+hY0lK/6wtkqgCeJOTR 9NjoQ9Wi+XAxzoxiCbintFU= =uOHj -----END PGP SIGNATURE-----