mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
tagdemux: Properly implement seeking if tagdemux is driving the pipeline
https://bugzilla.gnome.org/show_bug.cgi?id=705062
This commit is contained in:
parent
31763d3c20
commit
bb870b8b7b
1 changed files with 201 additions and 55 deletions
|
@ -136,6 +136,8 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_STATIC_CAPS ("ANY")
|
GST_STATIC_CAPS ("ANY")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static void gst_tag_demux_element_loop (GstTagDemux * demux);
|
||||||
|
|
||||||
static void gst_tag_demux_dispose (GObject * object);
|
static void gst_tag_demux_dispose (GObject * object);
|
||||||
|
|
||||||
static GstFlowReturn gst_tag_demux_chain (GstPad * pad, GstObject * parent,
|
static GstFlowReturn gst_tag_demux_chain (GstPad * pad, GstObject * parent,
|
||||||
|
@ -777,6 +779,190 @@ gst_tag_demux_get_upstream_size (GstTagDemux * tagdemux)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_tag_demux_seek_pull (GstTagDemux * tagdemux, GstEvent * event)
|
||||||
|
{
|
||||||
|
GstSeekFlags flags;
|
||||||
|
GstSeekType start_type, stop_type;
|
||||||
|
GstFormat format;
|
||||||
|
gboolean flush;
|
||||||
|
gdouble rate;
|
||||||
|
gint64 start, stop;
|
||||||
|
GstSegment seeksegment = { 0, };
|
||||||
|
|
||||||
|
gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
|
||||||
|
&stop_type, &stop);
|
||||||
|
|
||||||
|
/* we can only seek on bytes */
|
||||||
|
if (format != GST_FORMAT_BYTES) {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Can only seek on BYTES");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagdemux->priv->state != GST_TAG_DEMUX_STREAMING) {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Can only seek if streaming already");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (start_type) {
|
||||||
|
case GST_SEEK_TYPE_SET:
|
||||||
|
if (start == -1)
|
||||||
|
start = 0;
|
||||||
|
start += tagdemux->priv->strip_start;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_END:
|
||||||
|
/* Adjust the seek to be relative to the start of any end tag
|
||||||
|
* (note: 10 bytes before end is represented by stop=-10) */
|
||||||
|
if (start > 0)
|
||||||
|
start = 0;
|
||||||
|
start -= tagdemux->priv->strip_end;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (stop_type) {
|
||||||
|
case GST_SEEK_TYPE_SET:
|
||||||
|
if (stop != -1) {
|
||||||
|
/* -1 means the end of the file, pass it upstream intact */
|
||||||
|
stop += tagdemux->priv->strip_start;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_END:
|
||||||
|
/* Adjust the seek to be relative to the start of any end tag
|
||||||
|
* (note: 10 bytes before end is represented by stop=-10) */
|
||||||
|
if (stop > 0)
|
||||||
|
stop = 0;
|
||||||
|
stop -= tagdemux->priv->strip_end;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy segment, we need this because we still need the old
|
||||||
|
* segment when we close the current segment. */
|
||||||
|
memcpy (&seeksegment, &tagdemux->priv->segment, sizeof (GstSegment));
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "configuring seek");
|
||||||
|
gst_segment_do_seek (&seeksegment, rate, format, flags,
|
||||||
|
start_type, start, stop_type, stop, NULL);
|
||||||
|
|
||||||
|
flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);
|
||||||
|
|
||||||
|
if (flush) {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Starting flush");
|
||||||
|
gst_pad_push_event (tagdemux->priv->sinkpad, gst_event_new_flush_start ());
|
||||||
|
gst_pad_push_event (tagdemux->priv->srcpad, gst_event_new_flush_start ());
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Non-flushing seek, pausing task");
|
||||||
|
gst_pad_pause_task (tagdemux->priv->sinkpad);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now grab the stream lock so that streaming cannot continue, for
|
||||||
|
* non flushing seeks when the element is in PAUSED this could block
|
||||||
|
* forever. */
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Waiting for streaming to stop");
|
||||||
|
GST_PAD_STREAM_LOCK (tagdemux->priv->sinkpad);
|
||||||
|
|
||||||
|
if (flush) {
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Stopping flush");
|
||||||
|
gst_pad_push_event (tagdemux->priv->sinkpad,
|
||||||
|
gst_event_new_flush_stop (TRUE));
|
||||||
|
gst_pad_push_event (tagdemux->priv->srcpad,
|
||||||
|
gst_event_new_flush_stop (TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now update the real segment info */
|
||||||
|
GST_DEBUG_OBJECT (tagdemux, "Committing new seek segment");
|
||||||
|
memcpy (&tagdemux->priv->segment, &seeksegment, sizeof (GstSegment));
|
||||||
|
tagdemux->priv->offset = tagdemux->priv->segment.start;
|
||||||
|
|
||||||
|
/* notify start of new segment */
|
||||||
|
if (tagdemux->priv->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
|
||||||
|
GstMessage *msg;
|
||||||
|
|
||||||
|
msg = gst_message_new_segment_start (GST_OBJECT (tagdemux),
|
||||||
|
GST_FORMAT_BYTES, tagdemux->priv->segment.start);
|
||||||
|
gst_element_post_message (GST_ELEMENT (tagdemux), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
tagdemux->priv->need_newseg = TRUE;
|
||||||
|
|
||||||
|
/* restart our task since it might have been stopped when we did the
|
||||||
|
* flush. */
|
||||||
|
gst_pad_start_task (tagdemux->priv->sinkpad,
|
||||||
|
(GstTaskFunction) gst_tag_demux_element_loop, tagdemux, NULL);
|
||||||
|
|
||||||
|
/* streaming can continue now */
|
||||||
|
GST_PAD_STREAM_UNLOCK (tagdemux->priv->sinkpad);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_tag_demux_seek_push (GstTagDemux * tagdemux, GstEvent * event)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
gdouble rate;
|
||||||
|
GstFormat format;
|
||||||
|
GstSeekType start_type, stop_type;
|
||||||
|
GstSeekFlags flags;
|
||||||
|
gint64 start, stop;
|
||||||
|
|
||||||
|
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||||
|
&start_type, &start, &stop_type, &stop);
|
||||||
|
|
||||||
|
if (format == GST_FORMAT_BYTES &&
|
||||||
|
tagdemux->priv->state == GST_TAG_DEMUX_STREAMING &&
|
||||||
|
gst_pad_is_linked (tagdemux->priv->sinkpad)) {
|
||||||
|
GstEvent *upstream;
|
||||||
|
|
||||||
|
switch (start_type) {
|
||||||
|
case GST_SEEK_TYPE_SET:
|
||||||
|
if (start == -1)
|
||||||
|
start = 0;
|
||||||
|
start += tagdemux->priv->strip_start;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_END:
|
||||||
|
/* Adjust the seek to be relative to the start of any end tag
|
||||||
|
* (note: 10 bytes before end is represented by stop=-10) */
|
||||||
|
if (start > 0)
|
||||||
|
start = 0;
|
||||||
|
start -= tagdemux->priv->strip_end;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (stop_type) {
|
||||||
|
case GST_SEEK_TYPE_SET:
|
||||||
|
if (stop != -1) {
|
||||||
|
/* -1 means the end of the file, pass it upstream intact */
|
||||||
|
stop += tagdemux->priv->strip_start;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_END:
|
||||||
|
/* Adjust the seek to be relative to the start of any end tag
|
||||||
|
* (note: 10 bytes before end is represented by stop=-10) */
|
||||||
|
if (stop > 0)
|
||||||
|
stop = 0;
|
||||||
|
stop -= tagdemux->priv->strip_end;
|
||||||
|
break;
|
||||||
|
case GST_SEEK_TYPE_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
upstream = gst_event_new_seek (rate, format, flags,
|
||||||
|
start_type, start, stop_type, stop);
|
||||||
|
res = gst_pad_push_event (tagdemux->priv->sinkpad, upstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_tag_demux_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
gst_tag_demux_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
{
|
{
|
||||||
|
@ -790,59 +976,10 @@ gst_tag_demux_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_SEEK:
|
case GST_EVENT_SEEK:
|
||||||
{
|
{
|
||||||
gdouble rate;
|
if (GST_PAD_MODE (tagdemux->priv->sinkpad) == GST_PAD_MODE_PUSH)
|
||||||
GstFormat format;
|
res = gst_tag_demux_seek_push (tagdemux, event);
|
||||||
GstSeekType start_type, stop_type;
|
else
|
||||||
GstSeekFlags flags;
|
res = gst_tag_demux_seek_pull (tagdemux, event);
|
||||||
gint64 start, stop;
|
|
||||||
|
|
||||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
|
||||||
&start_type, &start, &stop_type, &stop);
|
|
||||||
|
|
||||||
if (format == GST_FORMAT_BYTES &&
|
|
||||||
tagdemux->priv->state == GST_TAG_DEMUX_STREAMING &&
|
|
||||||
gst_pad_is_linked (tagdemux->priv->sinkpad)) {
|
|
||||||
GstEvent *upstream;
|
|
||||||
|
|
||||||
switch (start_type) {
|
|
||||||
case GST_SEEK_TYPE_SET:
|
|
||||||
if (start == -1)
|
|
||||||
start = 0;
|
|
||||||
start += tagdemux->priv->strip_start;
|
|
||||||
break;
|
|
||||||
case GST_SEEK_TYPE_END:
|
|
||||||
/* Adjust the seek to be relative to the start of any end tag
|
|
||||||
* (note: 10 bytes before end is represented by stop=-10) */
|
|
||||||
if (start > 0)
|
|
||||||
start = 0;
|
|
||||||
start -= tagdemux->priv->strip_end;
|
|
||||||
break;
|
|
||||||
case GST_SEEK_TYPE_NONE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
switch (stop_type) {
|
|
||||||
case GST_SEEK_TYPE_SET:
|
|
||||||
if (stop != -1) {
|
|
||||||
/* -1 means the end of the file, pass it upstream intact */
|
|
||||||
stop += tagdemux->priv->strip_start;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GST_SEEK_TYPE_END:
|
|
||||||
/* Adjust the seek to be relative to the start of any end tag
|
|
||||||
* (note: 10 bytes before end is represented by stop=-10) */
|
|
||||||
if (stop > 0)
|
|
||||||
stop = 0;
|
|
||||||
stop -= tagdemux->priv->strip_end;
|
|
||||||
break;
|
|
||||||
case GST_SEEK_TYPE_NONE:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
upstream = gst_event_new_seek (rate, format, flags,
|
|
||||||
start_type, start, stop_type, stop);
|
|
||||||
res = gst_pad_push_event (tagdemux->priv->sinkpad, upstream);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1202,6 +1339,7 @@ skip_typefinding:
|
||||||
|
|
||||||
/* set it again, in case we skipped typefinding */
|
/* set it again, in case we skipped typefinding */
|
||||||
demux->priv->state = GST_TAG_DEMUX_STREAMING;
|
demux->priv->state = GST_TAG_DEMUX_STREAMING;
|
||||||
|
demux->priv->offset += demux->priv->strip_start;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1274,7 +1412,11 @@ gst_tag_demux_element_loop (GstTagDemux * demux)
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
GST_BUFFER_OFFSET (outbuf) =
|
||||||
|
demux->priv->offset - demux->priv->strip_start;
|
||||||
demux->priv->offset += gst_buffer_get_size (outbuf);
|
demux->priv->offset += gst_buffer_get_size (outbuf);
|
||||||
|
GST_BUFFER_OFFSET_END (outbuf) =
|
||||||
|
demux->priv->offset - demux->priv->strip_start;
|
||||||
|
|
||||||
ret = gst_pad_push (demux->priv->srcpad, outbuf);
|
ret = gst_pad_push (demux->priv->srcpad, outbuf);
|
||||||
break;
|
break;
|
||||||
|
@ -1336,14 +1478,18 @@ static gboolean
|
||||||
gst_tag_demux_sink_activate_mode (GstPad * pad, GstObject * parent,
|
gst_tag_demux_sink_activate_mode (GstPad * pad, GstObject * parent,
|
||||||
GstPadMode mode, gboolean active)
|
GstPadMode mode, gboolean active)
|
||||||
{
|
{
|
||||||
|
GstTagDemux *demux = GST_TAG_DEMUX (parent);
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case GST_PAD_MODE_PULL:
|
case GST_PAD_MODE_PULL:
|
||||||
if (active)
|
if (active) {
|
||||||
|
demux->priv->need_newseg = TRUE;
|
||||||
|
demux->priv->offset = 0;
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
else
|
} else {
|
||||||
res = gst_pad_stop_task (pad);
|
res = gst_pad_stop_task (pad);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
|
Loading…
Reference in a new issue