From 35dc28d69a954213eb37829b5c55caac535c5705 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 14 Oct 2009 13:08:47 +0200 Subject: avidemux: add GstIndex support --- gst/avi/gstavidemux.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++ gst/avi/gstavidemux.h | 7 +++ 2 files changed, 127 insertions(+) diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 9d47f9ee..844d0caf 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -97,6 +97,8 @@ static gboolean gst_avi_demux_sink_activate_pull (GstPad * sinkpad, static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active); static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstBuffer * buf); +static void gst_avi_demux_set_index (GstElement * element, GstIndex * index); +static GstIndex *gst_avi_demux_get_index (GstElement * element); static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element, GstStateChange transition); @@ -180,6 +182,9 @@ gst_avi_demux_class_init (GstAviDemuxClass * klass) gobject_class->finalize = gst_avi_demux_finalize; gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_avi_demux_change_state); + + gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_avi_demux_set_index); + gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_avi_demux_get_index); } static void @@ -261,6 +266,10 @@ gst_avi_demux_reset (GstAviDemux * avi) g_free (avi->avih); avi->avih = NULL; + if (avi->element_index) + gst_object_unref (avi->element_index); + avi->element_index = NULL; + if (avi->seek_event) { gst_event_unref (avi->seek_event); avi->seek_event = NULL; @@ -272,6 +281,7 @@ gst_avi_demux_reset (GstAviDemux * avi) avi->got_tags = TRUE; /* we always want to push global tags */ avi->have_eos = FALSE; + avi->seekable = TRUE; gst_adapter_clear (avi->adapter); @@ -1847,6 +1857,10 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert)); #endif + if (avi->element_index) + gst_index_get_writer_id (avi->element_index, GST_OBJECT (stream->pad), + &stream->index_id); + stream->num = avi->num_streams; stream->start_entry = 0; @@ -2582,6 +2596,49 @@ gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event) return result; } +static void +gst_avi_demux_check_seekability (GstAviDemux * avi) +{ + GstQuery *query; + gboolean seekable = FALSE; + gint64 start = -1, stop = -1; + + query = gst_query_new_seeking (GST_FORMAT_BYTES); + if (!gst_pad_peer_query (avi->sinkpad, query)) { + GST_DEBUG_OBJECT (avi, "seeking query failed"); + goto done; + } + + gst_query_parse_seeking (query, NULL, &seekable, &start, &stop); + + /* try harder to query upstream size if we didn't get it the first time */ + if (seekable && stop == -1) { + GstFormat fmt = GST_FORMAT_BYTES; + + GST_DEBUG_OBJECT (avi, "doing duration query to fix up unset stop"); + gst_pad_query_peer_duration (avi->sinkpad, &fmt, &stop); + } + + /* if upstream doesn't know the size, it's likely that it's not seekable in + * practice even if it technically may be seekable */ + if (seekable && (start != 0 || stop <= start)) { + GST_DEBUG_OBJECT (avi, "seekable but unknown start/stop -> disable"); + seekable = FALSE; + } + + if (!avi->element_index) { + GST_DEBUG_OBJECT (avi, "no index"); + seekable = FALSE; + } + +done: + GST_INFO_OBJECT (avi, "seekable: %d (%" G_GUINT64_FORMAT " - %" + G_GUINT64_FORMAT ")", seekable, start, stop); + avi->seekable = seekable; + + gst_query_unref (query); +} + /* * Read AVI headers when streaming */ @@ -2791,6 +2848,8 @@ skipping_done: (FALSE, avi->segment.rate, GST_FORMAT_TIME, avi->segment.start, stop, avi->segment.time); + gst_avi_demux_check_seekability (avi); + /* at this point we know all the streams and we can signal the no more * pads signal */ GST_DEBUG_OBJECT (avi, "signaling no more pads"); @@ -3502,6 +3561,25 @@ gst_avi_demux_invert (GstAviStream * stream, GstBuffer * buf) return buf; } +static void +gst_avi_demux_add_assoc (GstAviDemux * avi, GstAviStream * stream, + GstClockTime timestamp, guint64 offset, gboolean keyframe) +{ + /* do not add indefinitely for open-ended streaming */ + if (G_UNLIKELY (avi->element_index && avi->seekable)) { + GST_LOG_OBJECT (avi, "adding association %" GST_TIME_FORMAT "-> %" + G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), offset); + gst_index_add_association (avi->element_index, avi->index_id, + keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE, + GST_FORMAT_TIME, timestamp, GST_FORMAT_BYTES, offset, NULL); + /* well, current_total determines TIME and entry DEFAULT (frame #) ... */ + gst_index_add_association (avi->element_index, stream->index_id, + GST_ASSOCIATION_FLAG_NONE, + GST_FORMAT_TIME, stream->current_total, GST_FORMAT_BYTES, offset, + GST_FORMAT_DEFAULT, stream->current_entry, NULL); + } +} + /* * Returns the aggregated GstFlowReturn. */ @@ -3742,6 +3820,8 @@ gst_avi_demux_loop_data (GstAviDemux * avi) stream->discont = FALSE; } + gst_avi_demux_add_assoc (avi, stream, timestamp, offset, keyframe); + gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); /* update current position in the segment */ @@ -3904,6 +3984,7 @@ gst_avi_demux_stream_data (GstAviDemux * avi) GstAviStream *stream; GstClockTime next_ts = 0; GstBuffer *buf; + guint64 offset; gst_adapter_flush (avi->adapter, 8); @@ -3911,6 +3992,7 @@ gst_avi_demux_stream_data (GstAviDemux * avi) buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size)); /* patch the size */ GST_BUFFER_SIZE (buf) = size; + offset = avi->offset; avi->offset += 8 + GST_ROUND_UP_2 (size); stream = &avi->stream[stream_nr]; @@ -3934,6 +4016,8 @@ gst_avi_demux_stream_data (GstAviDemux * avi) if (G_UNLIKELY (format != GST_FORMAT_TIME)) goto wrong_format; + gst_avi_demux_add_assoc (avi, stream, next_ts, offset, FALSE); + /* increment our positions */ stream->current_entry++; stream->current_total += size; @@ -4221,6 +4305,42 @@ gst_avi_demux_activate_push (GstPad * pad, gboolean active) return TRUE; } +static void +gst_avi_demux_set_index (GstElement * element, GstIndex * index) +{ + GstAviDemux *avi = GST_AVI_DEMUX (element); + + GST_OBJECT_LOCK (avi); + if (avi->element_index) + gst_object_unref (avi->element_index); + if (index) { + avi->element_index = gst_object_ref (index); + } else { + avi->element_index = NULL; + } + GST_OBJECT_UNLOCK (avi); + /* object lock might be taken again */ + if (index) + gst_index_get_writer_id (index, GST_OBJECT (element), &avi->index_id); + GST_DEBUG_OBJECT (avi, "Set index %" GST_PTR_FORMAT, avi->element_index); +} + +static GstIndex * +gst_avi_demux_get_index (GstElement * element) +{ + GstIndex *result = NULL; + GstAviDemux *avi = GST_AVI_DEMUX (element); + + GST_OBJECT_LOCK (avi); + if (avi->element_index) + result = gst_object_ref (avi->element_index); + GST_OBJECT_UNLOCK (avi); + + GST_DEBUG_OBJECT (avi, "Returning index %" GST_PTR_FORMAT, result); + + return result; +} + static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element, GstStateChange transition) { diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h index 66537a6d..56a55bb2 100644 --- a/gst/avi/gstavidemux.h +++ b/gst/avi/gstavidemux.h @@ -120,6 +120,8 @@ typedef struct { guint idx_max; /* max allocated size of entries */ GstTagList *taglist; + + gint index_id; } GstAviStream; typedef enum { @@ -177,6 +179,11 @@ typedef struct _GstAviDemux { GstEvent *seek_event; GstTagList *globaltags; gboolean got_tags; + + /* gst index support */ + GstIndex *element_index; + gint index_id; + gboolean seekable; } GstAviDemux; typedef struct _GstAviDemuxClass { -- cgit