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.
This commit is contained in:
Jan Schmidt 2014-08-14 23:53:16 +10:00
parent 2a37534129
commit c98f051548
3 changed files with 93 additions and 0 deletions

View 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

View file

@ -98,6 +98,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

View 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);