mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-03 15:06:34 +00:00
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.
This commit is contained in:
parent
ce1d4d9f21
commit
ca068865c3
2 changed files with 31 additions and 41 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue