From c98f051548fc394abb098aa5bba4a4a63e75cb40 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 14 Aug 2014 23:53:16 +1000 Subject: [PATCH] video: Add gst_video_guess_framerate() function 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 | 1 + gst-libs/gst/video/video.c | 89 ++++++++++++++++++++++++++++ gst-libs/gst/video/video.h | 3 + 3 files changed, 93 insertions(+) diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index fb34761..65a8b3f 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -2202,6 +2202,7 @@ GstEncodingTargetClass #video.h gst_video_calculate_display_ratio +gst_video_guess_framerate GstVideoConvertSampleCallback gst_video_convert_sample gst_video_convert_sample_async diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index 2812a11..745dac3 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -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 * diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index 4f8f8c7..0158be0 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -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); -- 2.7.4