video: Add gst_video_guess_framerate() function
authorJan Schmidt <jan@centricular.com>
Thu, 14 Aug 2014 13:53:16 +0000 (23:53 +1000)
committerJan Schmidt <jan@centricular.com>
Thu, 14 Aug 2014 15:08:22 +0000 (01:08 +1000)
Takes a nominal frame duration and returns a standard
FPS if it matches closely enough (< 0.1%), or else
calculates a framerate that'll do.

docs/libs/gst-plugins-base-libs-sections.txt
gst-libs/gst/video/video.c
gst-libs/gst/video/video.h

index fb34761..65a8b3f 100644 (file)
@@ -2202,6 +2202,7 @@ GstEncodingTargetClass
 #video.h
 <SUBSECTION>
 gst_video_calculate_display_ratio
+gst_video_guess_framerate
 GstVideoConvertSampleCallback
 gst_video_convert_sample
 gst_video_convert_sample_async
index 2812a11..745dac3 100644 (file)
@@ -99,6 +99,95 @@ error_overflow:
 }
 
 /**
+ * gst_video_guess_framerate:
+ * @duration: Nominal duration of one frame
+ * @dest_n: (out) (allow-none): Numerator of the calculated framerate
+ * @dest_d: (out) (allow-none): Denominator of the calculated framerate
+ *
+ * Given the nominal duration of one video frame,
+ * this function will check some standard framerates for
+ * a close match (within 0.1%) and return one if possible,
+ *
+ * It will calculate an arbitrary framerate if no close
+ * match was found, and return %FALSE.
+ *
+ * It returns %FALSE if a duration of 0 is passed.
+ *
+ * Returns: %TRUE if a close "standard" framerate was
+ * recognised, and %FALSE otherwise.
+ *
+ * Since: 1.6
+ */
+gboolean
+gst_video_guess_framerate (GstClockTime duration, gint * dest_n, gint * dest_d)
+{
+  const int common_den[] = { 1, 2, 3, 4, 1001 };
+  int best_n, best_d, gcd;
+  guint64 best_error = G_MAXUINT64;
+  guint64 a;
+  int i;
+
+  if (G_UNLIKELY (duration == 0))
+    return FALSE;
+
+  /* Use a limited precision conversion by default for more sensible results,
+   * unless the frame duration is absurdly small (high speed cameras?) */
+  if (duration > 100000) {
+    best_n = 10000;
+    best_d = duration / 100000;
+  } else {
+    best_n = GST_SECOND;
+    best_d = duration;
+  }
+
+  for (i = 0; i < G_N_ELEMENTS (common_den); i++) {
+    gint d = common_den[i];
+    gint n = gst_util_uint64_scale_round (d, GST_SECOND, duration);
+
+    /* For NTSC framerates, round to the nearest 1000 fps */
+    if (d == 1001) {
+      n += 500;
+      n -= (n % 1000);
+    }
+
+    if (n > 0) {
+      /* See what duration the given framerate should be */
+      a = gst_util_uint64_scale_int (GST_SECOND, d, n);
+      /* Compute absolute error */
+      a = (a < duration) ? (duration - a) : (a - duration);
+      if (a < 2) {
+        /* Really precise - take this option */
+        if (dest_n)
+          *dest_n = n;
+        if (dest_d)
+          *dest_d = d;
+        return TRUE;
+      }
+      /* If within 0.1%, remember this denominator */
+      if (a * 1000 < duration && a < best_error) {
+        best_error = a;
+        best_n = n;
+        best_d = d;
+      }
+    }
+  }
+
+  /* set results */
+  gcd = gst_util_greatest_common_divisor (best_n, best_d);
+  if (gcd) {
+    best_n /= gcd;
+    best_d /= gcd;
+  }
+  if (dest_n)
+    *dest_n = best_n;
+  if (dest_d)
+    *dest_d = best_d;
+
+  return (best_error != G_MAXUINT64);
+}
+
+
+/**
  * gst_video_alignment_reset:
  * @align: a #GstVideoAlignment
  *
index 4f8f8c7..0158be0 100644 (file)
@@ -100,6 +100,9 @@ gboolean       gst_video_calculate_display_ratio (guint * dar_n,
                                                   guint   display_par_n,
                                                   guint   display_par_d);
 
+gboolean       gst_video_guess_framerate (GstClockTime duration,
+                                          gint * dest_n, gint * dest_d);
+
 /* convert/encode video sample from one format to another */
 
 typedef void (*GstVideoConvertSampleCallback) (GstSample * sample, GError *error, gpointer user_data);