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-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.