From ca068865c391e87932b1268d0c675be233dd2ffe Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 15 Aug 2014 01:12:20 +1000 Subject: [PATCH] qtdemux: Improve framerate calculation/guessing Change the way the output framerate is calculated to ignore the first sample (which is sometimes truncated in my testing) and use the new gst_video_guess_framerate() function to recognise common standard framerates better. Remove the code that was sorting the first 20 sample durations and then ignoring the result. --- gst/isomp4/Makefile.am | 2 +- gst/isomp4/qtdemux.c | 70 ++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/gst/isomp4/Makefile.am b/gst/isomp4/Makefile.am index 84dbbfcfc0..2755ee8b01 100644 --- a/gst/isomp4/Makefile.am +++ b/gst/isomp4/Makefile.am @@ -10,7 +10,7 @@ libgstisomp4_la_LIBADD = \ -lgstrtp-@GST_API_VERSION@ \ -lgsttag-@GST_API_VERSION@ \ -lgstpbutils-@GST_API_VERSION@ \ - $(GST_BASE_LIBS) $(GST_LIBS) $(ZLIB_LIBS) $(LIBM) + $(GST_BASE_LIBS) $(GST_LIBS) $(ZLIB_LIBS) libgstisomp4_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS} libgstisomp4_la_SOURCES = isomp4-plugin.c gstrtpxqtdepay.c \ qtdemux.c qtdemux_types.c qtdemux_dump.c qtdemux_lang.c \ diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c index 3f5565f513..e9fed02639 100644 --- a/gst/isomp4/qtdemux.c +++ b/gst/isomp4/qtdemux.c @@ -233,7 +233,7 @@ struct _QtDemuxStream guint32 n_samples; QtDemuxSample *samples; gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ - guint32 min_duration; /* duration in timescale of first sample, used for figuring out + guint32 first_duration; /* duration in timescale of first sample, used for figuring out the framerate, in timescale units */ guint32 offset_in_sample; guint32 max_buffer_size; @@ -5815,26 +5815,37 @@ static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream) { if (stream->subtype == FOURCC_vide) { - /* fps is calculated base on the duration of the first frames since + /* fps is calculated base on the duration of the average framerate since * qt does not have a fixed framerate. */ - if ((stream->n_samples == 1) && (stream->min_duration == 0)) { + if ((stream->n_samples == 1) && (stream->first_duration == 0)) { /* still frame */ stream->fps_n = 0; stream->fps_d = 1; } else { - /* we might need to scale the timescale to get precise framerate */ - const int required_scale = rint (log (10000) / 2.303); /* divide to get log10 */ - int current_scale = rint (log (stream->timescale) / 2.303); - int factor = pow (10.0, MAX (0, required_scale - current_scale)); + if (stream->duration == 0 || stream->n_samples < 2) { + stream->fps_n = stream->timescale; + stream->fps_d = 1; + } else { + /* Calculate a framerate, ignoring the first sample which is sometimes truncated */ + /* stream->duration is guint64, timescale, n_samples are guint32 */ + GstClockTime avg_duration = + gst_util_uint64_scale_round (stream->duration - + stream->first_duration, GST_SECOND, + (guint64) (stream->timescale) * (stream->n_samples - 1)); - stream->fps_n = stream->timescale * factor; + GST_LOG_OBJECT (qtdemux, + "Calculating avg sample duration based on stream duration %" + G_GUINT64_FORMAT + " minus first sample %u, leaving %d samples gives %" + GST_TIME_FORMAT, stream->duration, stream->first_duration, + stream->n_samples - 1, GST_TIME_ARGS (avg_duration)); - if (stream->duration == 0 || stream->n_samples == 0) - stream->fps_d = factor; - else - stream->fps_d = - gst_util_uint64_scale_int_round (stream->duration, factor, - stream->n_samples); + gst_video_guess_framerate (avg_duration, &stream->fps_n, + &stream->fps_d); + } + GST_DEBUG_OBJECT (qtdemux, + "Calculating framerate, timescale %u gave fps_n %d fps_d %d", + stream->timescale, stream->fps_n, stream->fps_d); } if (stream->caps) { @@ -7091,14 +7102,6 @@ qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf) return uri; } -static gint -less_than (gconstpointer a, gconstpointer b) -{ - const guint32 *av = a, *bv = b; - - return *av - *bv; -} - #define AMR_NB_ALL_MODES 0x81ff #define AMR_WB_ALL_MODES 0x83ff static guint @@ -9019,8 +9022,6 @@ qtdemux_prepare_streams (GstQTDemux * qtdemux) for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) { QtDemuxStream *stream = qtdemux->streams[i]; guint32 sample_num = 0; - guint samples = 20; - GArray *durations; GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT, i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc)); @@ -9051,26 +9052,15 @@ qtdemux_prepare_streams (GstQTDemux * qtdemux) continue; } - /* parse number of initial sample to set frame rate cap */ - while (sample_num < stream->n_samples && sample_num < samples) { + /* parse the initial sample for use in setting the frame rate cap */ + while (sample_num == 0) { if (!qtdemux_parse_samples (qtdemux, stream, sample_num)) break; ++sample_num; } - /* collect and sort durations */ - samples = MIN (stream->stbl_index + 1, samples); - GST_DEBUG_OBJECT (qtdemux, "%d samples for framerate", samples); - if (samples) { - durations = g_array_sized_new (FALSE, FALSE, sizeof (guint32), samples); - sample_num = 0; - while (sample_num < samples) { - g_array_append_val (durations, stream->samples[sample_num].duration); - sample_num++; - } - g_array_sort (durations, less_than); - stream->min_duration = g_array_index (durations, guint32, samples / 2); - g_array_free (durations, TRUE); - } + stream->first_duration = stream->samples[0].duration; + GST_LOG_OBJECT (qtdemux, "stream %d first duration %u", + stream->track_id, stream->first_duration); } return ret;