mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 07:28:53 +00:00
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.
This commit is contained in:
parent
f23fb39bc7
commit
1dfcc3227c
2 changed files with 70 additions and 17 deletions
|
@ -71,6 +71,8 @@ GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
static gboolean flv_demux_handle_seek_push (GstFLVDemux * demux,
|
static gboolean flv_demux_handle_seek_push (GstFLVDemux * demux,
|
||||||
GstEvent * event);
|
GstEvent * event);
|
||||||
|
static gboolean gst_flv_demux_handle_seek_pull (GstFLVDemux * demux,
|
||||||
|
GstEvent * event, gboolean seeking);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
|
gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
|
||||||
|
@ -585,7 +587,7 @@ gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static GstFlowReturn
|
||||||
gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts)
|
gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts)
|
||||||
{
|
{
|
||||||
gint64 size;
|
gint64 size;
|
||||||
|
@ -594,10 +596,11 @@ gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts)
|
||||||
guint64 old_offset;
|
guint64 old_offset;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
GstClockTime tag_time;
|
GstClockTime tag_time;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
|
if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
|
||||||
fmt != GST_FORMAT_BYTES))
|
fmt != GST_FORMAT_BYTES))
|
||||||
return;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
|
GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
|
||||||
" looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
|
" 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;
|
old_offset = demux->offset;
|
||||||
demux->offset = pos;
|
demux->offset = pos;
|
||||||
|
|
||||||
while (gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12,
|
while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
|
||||||
&buffer) == GST_FLOW_OK) {
|
12, &buffer)) == GST_FLOW_OK) {
|
||||||
tag_time = gst_flv_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
|
tag_time = gst_flv_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
|
||||||
|
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
@ -617,11 +620,16 @@ gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts)
|
||||||
demux->offset += tag_size;
|
demux->offset += tag_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* file ran out, so mark we have complete index */
|
if (ret == GST_FLOW_UNEXPECTED) {
|
||||||
demux->indexed = TRUE;
|
/* file ran out, so mark we have complete index */
|
||||||
|
demux->indexed = TRUE;
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
demux->offset = old_offset;
|
demux->offset = old_offset;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint64
|
static gint64
|
||||||
|
@ -708,6 +716,20 @@ gst_flv_demux_loop (GstPad * pad)
|
||||||
case FLV_STATE_DONE:
|
case FLV_STATE_DONE:
|
||||||
ret = GST_FLOW_UNEXPECTED;
|
ret = GST_FLOW_UNEXPECTED;
|
||||||
break;
|
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:
|
default:
|
||||||
ret = gst_flv_demux_pull_header (pad, demux);
|
ret = gst_flv_demux_pull_header (pad, demux);
|
||||||
/* index scans start after header */
|
/* index scans start after header */
|
||||||
|
@ -1002,7 +1024,8 @@ gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
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;
|
GstFormat format;
|
||||||
GstSeekFlags flags;
|
GstSeekFlags flags;
|
||||||
|
@ -1015,11 +1038,15 @@ gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event)
|
||||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
&start_type, &start, &stop_type, &stop);
|
&start_type, &start, &stop_type, &stop);
|
||||||
|
|
||||||
gst_event_unref (event);
|
|
||||||
|
|
||||||
if (format != GST_FORMAT_TIME)
|
if (format != GST_FORMAT_TIME)
|
||||||
goto wrong_format;
|
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);
|
flush = !!(flags & GST_SEEK_FLAG_FLUSH);
|
||||||
/* FIXME : the keyframe flag is never used */
|
/* FIXME : the keyframe flag is never used */
|
||||||
keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
|
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) {
|
if (flush || seeksegment.last_stop != demux->segment.last_stop) {
|
||||||
/* Do the actual seeking */
|
/* Do the actual seeking */
|
||||||
/* index is reliable if it is complete or we do not go to far ahead */
|
/* 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) {
|
seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) {
|
||||||
/* scan and build index from current maximum offset to desired time */
|
GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
|
||||||
/* NOTE this will _pull_range from seeking thread, but should be ok ... */
|
" index only up to %" GST_TIME_FORMAT,
|
||||||
gst_flv_demux_create_index (demux, demux->index_max_pos,
|
GST_TIME_ARGS (demux->index_max_time));
|
||||||
seeksegment.last_stop);
|
/* 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 */
|
/* now index should be as reliable as it can be for current purpose */
|
||||||
demux->offset = gst_flv_demux_find_offset (demux, &seeksegment);
|
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,
|
exit:
|
||||||
(GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
|
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_PAD_STREAM_UNLOCK (demux->sinkpad);
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
wrong_format:
|
wrong_format:
|
||||||
{
|
{
|
||||||
GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
|
GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
|
||||||
|
gst_event_unref (event);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1290,7 +1342,7 @@ gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
if (demux->random_access) {
|
if (demux->random_access) {
|
||||||
ret = gst_flv_demux_handle_seek_pull (demux, event);
|
ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
|
||||||
} else {
|
} else {
|
||||||
ret = gst_flv_demux_handle_seek_push (demux, event);
|
ret = gst_flv_demux_handle_seek_push (demux, event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@ struct _GstFLVDemux
|
||||||
gboolean indexed; /* TRUE if index is completely built */
|
gboolean indexed; /* TRUE if index is completely built */
|
||||||
gint64 file_size;
|
gint64 file_size;
|
||||||
GstEvent *seek_event;
|
GstEvent *seek_event;
|
||||||
|
gint64 seek_time;
|
||||||
|
|
||||||
GstClockTime index_max_time;
|
GstClockTime index_max_time;
|
||||||
gint64 index_max_pos;
|
gint64 index_max_pos;
|
||||||
|
|
Loading…
Reference in a new issue