| From 46d3e0faa922643094a5e46a32e4f82f774ae772 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Enrique=20Oca=C3=B1a=20Gonz=C3=A1lez?= <eocanha@igalia.com> |
| Date: Tue, 10 Nov 2015 13:09:00 +0100 |
| Subject: [PATCH] Use the tfdt decode time when it's significantly different |
| than the time in the last sample if always-honor-tfdt is enabled |
| |
| https://bugzilla.gnome.org/show_bug.cgi?id=754230 |
| --- |
| gst/isomp4/qtdemux.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| gst/isomp4/qtdemux.h | 1 + |
| 2 files changed, 73 insertions(+) |
| |
| diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c |
| index 880595e..d8b54f0 100644 |
| --- a/gst/isomp4/qtdemux.c |
| +++ b/gst/isomp4/qtdemux.c |
| @@ -535,6 +535,11 @@ static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux, |
| const gchar * id); |
| static void qtdemux_gst_structure_free (GstStructure * gststructure); |
| |
| +static void gst_qtdemux_set_property (GObject * object, guint prop_id, |
| + const GValue * value, GParamSpec * spec); |
| +static void gst_qtdemux_get_property (GObject * object, guint prop_id, |
| + GValue * value, GParamSpec * spec); |
| + |
| static void |
| gst_qtdemux_class_init (GstQTDemuxClass * klass) |
| { |
| @@ -546,8 +551,21 @@ gst_qtdemux_class_init (GstQTDemuxClass * klass) |
| |
| parent_class = g_type_class_peek_parent (klass); |
| |
| + gobject_class->set_property = gst_qtdemux_set_property; |
| + gobject_class->get_property = gst_qtdemux_get_property; |
| + |
| gobject_class->dispose = gst_qtdemux_dispose; |
| |
| + /** |
| + * GstQtDemux::always-honor-tfdt: |
| + * |
| + * Requests the demuxer to respect what the TFDT atom says in order to produce presentation timestamps. Defaults to FALSE. |
| + */ |
| + g_object_class_install_property (gobject_class, PROP_ALWAYS_HONOR_TFDT, |
| + g_param_spec_boolean ("always-honor-tfdt", "Always honor TFDT", |
| + "When enabled, TFDT atom will always be respected in order to produce presentation timestamps", |
| + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
| + |
| gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state); |
| #if 0 |
| gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index); |
| @@ -611,6 +629,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux) |
| qtdemux->cenc_aux_info_sizes = NULL; |
| qtdemux->cenc_aux_sample_count = 0; |
| qtdemux->protection_system_ids = NULL; |
| + qtdemux->always_honor_tfdt = FALSE; |
| g_queue_init (&qtdemux->protection_event_queue); |
| gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); |
| qtdemux->flowcombiner = gst_flow_combiner_new (); |
| @@ -639,6 +658,42 @@ gst_qtdemux_dispose (GObject * object) |
| } |
| |
| static void |
| +gst_qtdemux_set_property (GObject * object, guint prop_id, |
| + const GValue * value, GParamSpec * pspec) |
| +{ |
| + GstQTDemux *qtdemux = GST_QTDEMUX (object); |
| + |
| + switch (prop_id) { |
| + case PROP_ALWAYS_HONOR_TFDT: |
| + GST_OBJECT_LOCK (qtdemux); |
| + qtdemux->always_honor_tfdt = g_value_get_boolean (value); |
| + GST_OBJECT_UNLOCK (qtdemux); |
| + break; |
| + default: |
| + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| + break; |
| + } |
| +} |
| + |
| +static void |
| +gst_qtdemux_get_property (GObject * object, guint prop_id, GValue * value, |
| + GParamSpec * pspec) |
| +{ |
| + GstQTDemux *qtdemux = GST_QTDEMUX (object); |
| + |
| + switch (prop_id) { |
| + case PROP_ALWAYS_HONOR_TFDT: |
| + GST_OBJECT_LOCK (qtdemux); |
| + g_value_set_boolean (value, qtdemux->always_honor_tfdt); |
| + GST_OBJECT_UNLOCK (qtdemux); |
| + break; |
| + default: |
| + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
| + break; |
| + } |
| +} |
| + |
| +static void |
| gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux) |
| { |
| if (qtdemux->posted_redirect) { |
| @@ -2995,6 +3050,16 @@ qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun, |
| stream->samples[stream->n_samples - 1].timestamp + |
| stream->samples[stream->n_samples - 1].duration; |
| |
| + /* If we're always honoring TFDT and there's a significative difference |
| + * between the decode_ts and the timestamp, prefer decode_ts */ |
| + if (qtdemux->always_honor_tfdt == TRUE |
| + && abs (decode_ts - timestamp) > |
| + stream->samples[stream->n_samples - 1].duration) { |
| + GST_INFO_OBJECT (qtdemux, |
| + "decode_ts is significantly different from timestamp, using decode_ts"); |
| + timestamp = decode_ts; |
| + } |
| + |
| gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp); |
| GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT |
| " (extends previous samples)", GST_TIME_ARGS (gst_ts)); |
| diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h |
| index 53bd071..ecf0c63 100644 |
| --- a/gst/isomp4/qtdemux.h |
| +++ b/gst/isomp4/qtdemux.h |
| @@ -154,12 +154,20 @@ struct _GstQTDemux { |
| guint8 *cenc_aux_info_sizes; |
| guint32 cenc_aux_sample_count; |
| |
| + gboolean always_honor_tfdt; |
| }; |
| |
| struct _GstQTDemuxClass { |
| GstElementClass parent_class; |
| }; |
| |
| +/* props */ |
| +enum |
| +{ |
| + PROP_0, |
| + PROP_ALWAYS_HONOR_TFDT |
| +}; |
| + |
| GType gst_qtdemux_get_type (void); |
| |
| G_END_DECLS |
| -- |
| 2.6.1 |
| |