From 1dfcc3227ce3e6e8b6175cb5a732f9f76e38c4fc Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 26 Feb 2010 21:29:49 +0100 Subject: [PATCH] flvdemux: conduct index scan in task thread ... rather than in seeking thread, which might then occupy mainloop for some time with possible unresponsive side-effects. --- gst/flv/gstflvdemux.c | 86 +++++++++++++++++++++++++++++++++++++++++---------- gst/flv/gstflvdemux.h | 1 + 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 70a00b8..7f3fe99 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -71,6 +71,8 @@ GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT); static gboolean flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event); +static gboolean gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, + GstEvent * event, gboolean seeking); static void gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont) @@ -585,7 +587,7 @@ gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event) return ret; } -static void +static GstFlowReturn gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts) { gint64 size; @@ -594,10 +596,11 @@ gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts) guint64 old_offset; GstBuffer *buffer; GstClockTime tag_time; + GstFlowReturn ret = GST_FLOW_OK; if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) || fmt != GST_FORMAT_BYTES)) - return; + return GST_FLOW_OK; GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts)); @@ -605,8 +608,8 @@ gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts) old_offset = demux->offset; demux->offset = pos; - while (gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12, - &buffer) == GST_FLOW_OK) { + while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, + 12, &buffer)) == GST_FLOW_OK) { tag_time = gst_flv_parse_tag_timestamp (demux, TRUE, buffer, &tag_size); gst_buffer_unref (buffer); @@ -617,11 +620,16 @@ gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts) demux->offset += tag_size; } - /* file ran out, so mark we have complete index */ - demux->indexed = TRUE; + if (ret == GST_FLOW_UNEXPECTED) { + /* file ran out, so mark we have complete index */ + demux->indexed = TRUE; + ret = GST_FLOW_OK; + } exit: demux->offset = old_offset; + + return ret; } static gint64 @@ -708,6 +716,20 @@ gst_flv_demux_loop (GstPad * pad) case FLV_STATE_DONE: ret = GST_FLOW_UNEXPECTED; break; + case FLV_STATE_SEEK: + /* seek issued with insufficient index; + * scan for index in task thread from current maximum offset to + * desired time and then perform seek */ + /* TODO maybe some buffering message or so to indicate scan progress */ + ret = gst_flv_demux_create_index (demux, demux->index_max_pos, + demux->seek_time); + if (ret != GST_FLOW_OK) + goto pause; + /* position and state arranged by seek, + * also unrefs event */ + gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE); + demux->seek_event = NULL; + break; default: ret = gst_flv_demux_pull_header (pad, demux); /* index scans start after header */ @@ -1002,7 +1024,8 @@ gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event) } static gboolean -gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event) +gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event, + gboolean seeking) { GstFormat format; GstSeekFlags flags; @@ -1015,11 +1038,15 @@ gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event) gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, &stop_type, &stop); - gst_event_unref (event); - if (format != GST_FORMAT_TIME) goto wrong_format; + /* mark seeking thread entering flushing/pausing */ + GST_OBJECT_LOCK (demux); + if (seeking) + demux->seeking = seeking; + GST_OBJECT_UNLOCK (demux); + flush = !!(flags & GST_SEEK_FLAG_FLUSH); /* FIXME : the keyframe flag is never used */ keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); @@ -1058,12 +1085,22 @@ gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event) if (flush || seeksegment.last_stop != demux->segment.last_stop) { /* Do the actual seeking */ /* index is reliable if it is complete or we do not go to far ahead */ - if (!demux->indexed && + if (seeking && !demux->indexed && seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) { - /* scan and build index from current maximum offset to desired time */ - /* NOTE this will _pull_range from seeking thread, but should be ok ... */ - gst_flv_demux_create_index (demux, demux->index_max_pos, - seeksegment.last_stop); + GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; " + " index only up to %" GST_TIME_FORMAT, + GST_TIME_ARGS (demux->index_max_time)); + /* stop flushing for now */ + if (flush) + gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ()); + /* delegate scanning and index building to task thread to avoid + * occupying main (UI) loop */ + if (demux->seek_event) + gst_event_unref (demux->seek_event); + demux->seek_event = gst_event_ref (event); + demux->seek_time = seeksegment.last_stop; + demux->state = FLV_STATE_SEEK; + goto exit; } /* now index should be as reliable as it can be for current purpose */ demux->offset = gst_flv_demux_find_offset (demux, &seeksegment); @@ -1136,17 +1173,32 @@ gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event) } } - gst_pad_start_task (demux->sinkpad, - (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad); +exit: + GST_OBJECT_LOCK (demux); + seeking = demux->seeking && !seeking; + demux->seeking = FALSE; + GST_OBJECT_UNLOCK (demux); + + /* if we detect an external seek having started (and possibly already having + * flushed), do not restart task to give it a chance. + * Otherwise external one's flushing will take care to pause task */ + if (seeking) { + gst_pad_pause_task (demux->sinkpad); + } else { + gst_pad_start_task (demux->sinkpad, + (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad); + } GST_PAD_STREAM_UNLOCK (demux->sinkpad); + gst_event_unref (event); return ret; /* ERRORS */ wrong_format: { GST_WARNING_OBJECT (demux, "we only support seeking in TIME format"); + gst_event_unref (event); return FALSE; } } @@ -1290,7 +1342,7 @@ gst_flv_demux_src_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: if (demux->random_access) { - ret = gst_flv_demux_handle_seek_pull (demux, event); + ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE); } else { ret = gst_flv_demux_handle_seek_push (demux, event); } diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index 8027c6b..31da16b 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -125,6 +125,7 @@ struct _GstFLVDemux gboolean indexed; /* TRUE if index is completely built */ gint64 file_size; GstEvent *seek_event; + gint64 seek_time; GstClockTime index_max_time; gint64 index_max_pos; -- 2.7.4