aiffparse: fix seeking in push mode

This commit is contained in:
Wim Taymans 2013-11-05 12:43:44 +01:00
parent fefda44161
commit c7e705dd13

View file

@ -281,14 +281,15 @@ gst_aiff_parse_stream_init (GstAiffParse * aiff)
* READY. * READY.
*/ */
static gboolean static gboolean
gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event) gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event,
gboolean starting)
{ {
gboolean res; gboolean res;
gdouble rate; gdouble rate;
GstFormat format; GstFormat format;
GstSeekFlags flags; GstSeekFlags flags;
GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; GstSeekType start_type = GST_SEEK_TYPE_NONE, stop_type;
gint64 cur, stop, upstream_size; gint64 start, stop, upstream_size;
gboolean flush; gboolean flush;
gboolean update; gboolean update;
GstSegment seeksegment = { 0, }; GstSegment seeksegment = { 0, };
@ -298,7 +299,7 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
GST_DEBUG_OBJECT (aiff, "doing seek with event"); GST_DEBUG_OBJECT (aiff, "doing seek with event");
gst_event_parse_seek (event, &rate, &format, &flags, gst_event_parse_seek (event, &rate, &format, &flags,
&cur_type, &cur, &stop_type, &stop); &start_type, &start, &stop_type, &stop);
/* no negative rates yet */ /* no negative rates yet */
if (rate < 0.0) if (rate < 0.0)
@ -309,10 +310,10 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
gst_format_get_name (format), gst_format_get_name (format),
gst_format_get_name (aiff->segment.format)); gst_format_get_name (aiff->segment.format));
res = TRUE; res = TRUE;
if (cur_type != GST_SEEK_TYPE_NONE) if (start_type != GST_SEEK_TYPE_NONE)
res = res =
gst_pad_query_convert (aiff->srcpad, format, cur, gst_pad_query_convert (aiff->srcpad, format, start,
aiff->segment.format, &cur); aiff->segment.format, &start);
if (res && stop_type != GST_SEEK_TYPE_NONE) if (res && stop_type != GST_SEEK_TYPE_NONE)
res = res =
gst_pad_query_convert (aiff->srcpad, format, stop, gst_pad_query_convert (aiff->srcpad, format, stop,
@ -326,13 +327,52 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
GST_DEBUG_OBJECT (aiff, "doing seek without event"); GST_DEBUG_OBJECT (aiff, "doing seek without event");
flags = 0; flags = 0;
rate = 1.0; rate = 1.0;
cur_type = GST_SEEK_TYPE_SET; start = 0;
start_type = GST_SEEK_TYPE_SET;
stop = -1;
stop_type = GST_SEEK_TYPE_SET; stop_type = GST_SEEK_TYPE_SET;
} }
/* get flush flag */ /* get flush flag */
flush = flags & GST_SEEK_FLAG_FLUSH; flush = flags & GST_SEEK_FLAG_FLUSH;
if (aiff->streaming && !starting) {
GstEvent *new_event;
/* streaming seek */
if ((start_type != GST_SEEK_TYPE_NONE)) {
/* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
* we can just copy the position. If not, we use the bps to convert TIME to
* bytes. */
if (aiff->bps > 0)
start =
gst_util_uint64_scale_ceil (start, (guint64) aiff->bps, GST_SECOND);
start -= (start % aiff->bytes_per_sample);
start += aiff->datastart;
}
if (stop_type != GST_SEEK_TYPE_NONE) {
if (aiff->bps > 0)
stop =
gst_util_uint64_scale_ceil (stop, (guint64) aiff->bps, GST_SECOND);
stop -= (stop % aiff->bytes_per_sample);
stop += aiff->datastart;
}
/* make sure filesize is not exceeded due to rounding errors or so,
* same precaution as in _stream_headers */
if (gst_pad_peer_query_duration (aiff->sinkpad, GST_FORMAT_BYTES,
&upstream_size))
stop = MIN (stop, upstream_size);
if (stop >= 0 && stop <= start)
stop = start;
new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
start_type, start, stop_type, stop);
res = gst_pad_push_event (aiff->sinkpad, new_event);
} else {
/* now we need to make sure the streaming thread is stopped. We do this by /* now we need to make sure the streaming thread is stopped. We do this by
* either sending a FLUSH_START event downstream which will cause the * either sending a FLUSH_START event downstream which will cause the
* streaming thread to stop with a FLUSHING. * streaming thread to stop with a FLUSHING.
@ -364,7 +404,7 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
if (event) { if (event) {
GST_DEBUG_OBJECT (aiff, "configuring seek"); GST_DEBUG_OBJECT (aiff, "configuring seek");
gst_segment_do_seek (&seeksegment, rate, format, flags, gst_segment_do_seek (&seeksegment, rate, format, flags,
cur_type, cur, stop_type, stop, &update); start_type, start, stop_type, stop, &update);
} }
/* figure out the last position we need to play. If it's configured (stop != /* figure out the last position we need to play. If it's configured (stop !=
@ -372,8 +412,8 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
if ((stop = seeksegment.stop) == -1) if ((stop = seeksegment.stop) == -1)
stop = seeksegment.duration; stop = seeksegment.duration;
GST_DEBUG_OBJECT (aiff, "cur_type =%d", cur_type); GST_DEBUG_OBJECT (aiff, "start_type =%d", start_type);
if ((cur_type != GST_SEEK_TYPE_NONE)) { if ((start_type != GST_SEEK_TYPE_NONE)) {
/* bring offset to bytes, if the bps is 0, we have the segment in BYTES and /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
* we can just copy the position. If not, we use the bps to convert TIME to * we can just copy the position. If not, we use the bps to convert TIME to
* bytes. */ * bytes. */
@ -421,8 +461,8 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
GST_DEBUG_OBJECT (aiff, GST_DEBUG_OBJECT (aiff,
"seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, aiff->offset, ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate,
aiff->end_offset, GST_TIME_ARGS (seeksegment.start), aiff->offset, aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
GST_TIME_ARGS (stop)); GST_TIME_ARGS (stop));
/* prepare for streaming again */ /* prepare for streaming again */
@ -453,7 +493,8 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
/* mark discont if we are going to stream from another position. */ /* mark discont if we are going to stream from another position. */
if (position != aiff->segment.position) { if (position != aiff->segment.position) {
GST_DEBUG_OBJECT (aiff, "mark DISCONT, we did a seek to another position"); GST_DEBUG_OBJECT (aiff,
"mark DISCONT, we did a seek to another position");
aiff->discont = TRUE; aiff->discont = TRUE;
} }
@ -466,7 +507,10 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
GST_PAD_STREAM_UNLOCK (aiff->sinkpad); GST_PAD_STREAM_UNLOCK (aiff->sinkpad);
return TRUE; res = TRUE;
}
return res;
/* ERRORS */ /* ERRORS */
negative_rate: negative_rate:
@ -1020,7 +1064,7 @@ gst_aiff_parse_stream_headers (GstAiffParse * aiff)
/* now we have all the info to perform a pending seek if any, if no /* now we have all the info to perform a pending seek if any, if no
* event, this will still do the right thing and it will also send * event, this will still do the right thing and it will also send
* the right segment event downstream. */ * the right segment event downstream. */
gst_aiff_parse_perform_seek (aiff, aiff->seek_event); gst_aiff_parse_perform_seek (aiff, aiff->seek_event, TRUE);
/* remove pending event */ /* remove pending event */
event_p = &aiff->seek_event; event_p = &aiff->seek_event;
gst_event_replace (event_p, NULL); gst_event_replace (event_p, NULL);
@ -1133,7 +1177,7 @@ gst_aiff_parse_send_event (GstElement * element, GstEvent * event)
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
if (aiff->state == AIFF_PARSE_DATA) { if (aiff->state == AIFF_PARSE_DATA) {
/* we can handle the seek directly when streaming data */ /* we can handle the seek directly when streaming data */
res = gst_aiff_parse_perform_seek (aiff, event); res = gst_aiff_parse_perform_seek (aiff, event, FALSE);
} else { } else {
GST_DEBUG_OBJECT (aiff, "queuing seek for later"); GST_DEBUG_OBJECT (aiff, "queuing seek for later");
@ -1596,7 +1640,7 @@ gst_aiff_parse_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
/* can only handle events when we are in the data state */ /* can only handle events when we are in the data state */
if (aiffparse->state == AIFF_PARSE_DATA) { if (aiffparse->state == AIFF_PARSE_DATA) {
res = gst_aiff_parse_perform_seek (aiffparse, event); res = gst_aiff_parse_perform_seek (aiffparse, event, FALSE);
} }
gst_event_unref (event); gst_event_unref (event);
break; break;
@ -1767,8 +1811,6 @@ gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
segment.format = aiff->segment.format; segment.format = aiff->segment.format;
segment.time = segment.position = segment.start; segment.time = segment.position = segment.start;
segment.duration = aiff->segment.duration; segment.duration = aiff->segment.duration;
segment.base = gst_segment_to_running_time (&aiff->segment,
GST_FORMAT_TIME, aiff->segment.position);
} }
gst_segment_copy_into (&segment, &aiff->segment); gst_segment_copy_into (&segment, &aiff->segment);
@ -1794,6 +1836,13 @@ gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
gst_event_unref (event); gst_event_unref (event);
break; break;
} }
case GST_EVENT_FLUSH_START:
ret = gst_pad_push_event (aiff->srcpad, event);
break;
case GST_EVENT_FLUSH_STOP:
ret = gst_pad_push_event (aiff->srcpad, event);
gst_adapter_clear (aiff->adapter);
break;
default: default:
ret = gst_pad_event_default (aiff->sinkpad, parent, event); ret = gst_pad_event_default (aiff->sinkpad, parent, event);
break; break;