summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2013-11-05 12:43:44 +0100
committerWim Taymans <wim.taymans@collabora.co.uk>2013-11-05 12:43:44 +0100
commit83a9e28536275ec426bbc777ade1be03b71b7edf (patch)
tree6e56f2cd463f3c82bdd04980d8f4252ce5f4573b
parent03420d1e2adb7305971a4b8c696dc3c2f57b3a95 (diff)
aiffparse: fix seeking in push modesa
-rw-r--r--gst/aiff/aiffparse.c309
1 files changed, 179 insertions, 130 deletions
diff --git a/gst/aiff/aiffparse.c b/gst/aiff/aiffparse.c
index eaa1b819e..7d799b3ee 100644
--- a/gst/aiff/aiffparse.c
+++ b/gst/aiff/aiffparse.c
@@ -281,14 +281,15 @@ gst_aiff_parse_stream_init (GstAiffParse * aiff)
* READY.
*/
static gboolean
-gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
+gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event,
+ gboolean starting)
{
gboolean res;
gdouble rate;
GstFormat format;
GstSeekFlags flags;
- GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
- gint64 cur, stop, upstream_size;
+ GstSeekType start_type = GST_SEEK_TYPE_NONE, stop_type;
+ gint64 start, stop, upstream_size;
gboolean flush;
gboolean update;
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_event_parse_seek (event, &rate, &format, &flags,
- &cur_type, &cur, &stop_type, &stop);
+ &start_type, &start, &stop_type, &stop);
/* no negative rates yet */
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 (aiff->segment.format));
res = TRUE;
- if (cur_type != GST_SEEK_TYPE_NONE)
+ if (start_type != GST_SEEK_TYPE_NONE)
res =
- gst_pad_query_convert (aiff->srcpad, format, cur,
- aiff->segment.format, &cur);
+ gst_pad_query_convert (aiff->srcpad, format, start,
+ aiff->segment.format, &start);
if (res && stop_type != GST_SEEK_TYPE_NONE)
res =
gst_pad_query_convert (aiff->srcpad, format, stop,
@@ -326,147 +327,190 @@ gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event)
GST_DEBUG_OBJECT (aiff, "doing seek without event");
flags = 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;
}
/* get flush flag */
flush = flags & GST_SEEK_FLAG_FLUSH;
- /* 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
- * streaming thread to stop with a FLUSHING.
- * For a non-flushing seek we simply pause the task, which will happen as soon
- * as it completes one iteration (and thus might block when the sink is
- * blocking in preroll). */
- if (flush) {
- GST_DEBUG_OBJECT (aiff, "sending flush start");
- gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ());
+ 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 {
- gst_pad_pause_task (aiff->sinkpad);
- }
+ /* 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
+ * streaming thread to stop with a FLUSHING.
+ * For a non-flushing seek we simply pause the task, which will happen as soon
+ * as it completes one iteration (and thus might block when the sink is
+ * blocking in preroll). */
+ if (flush) {
+ GST_DEBUG_OBJECT (aiff, "sending flush start");
+ gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ());
+ } else {
+ gst_pad_pause_task (aiff->sinkpad);
+ }
- /* we should now be able to grab the streaming thread because we stopped it
- * with the above flush/pause code */
- GST_PAD_STREAM_LOCK (aiff->sinkpad);
+ /* we should now be able to grab the streaming thread because we stopped it
+ * with the above flush/pause code */
+ GST_PAD_STREAM_LOCK (aiff->sinkpad);
- /* save current position */
- position = aiff->segment.position;
+ /* save current position */
+ position = aiff->segment.position;
- GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, position);
+ GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, position);
- /* copy segment, we need this because we still need the old
- * segment when we close the current segment. */
- memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment));
+ /* copy segment, we need this because we still need the old
+ * segment when we close the current segment. */
+ memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment));
- /* configure the seek parameters in the seeksegment. We will then have the
- * right values in the segment to perform the seek */
- if (event) {
- GST_DEBUG_OBJECT (aiff, "configuring seek");
- gst_segment_do_seek (&seeksegment, rate, format, flags,
- cur_type, cur, stop_type, stop, &update);
- }
+ /* configure the seek parameters in the seeksegment. We will then have the
+ * right values in the segment to perform the seek */
+ if (event) {
+ GST_DEBUG_OBJECT (aiff, "configuring seek");
+ gst_segment_do_seek (&seeksegment, rate, format, flags,
+ start_type, start, stop_type, stop, &update);
+ }
- /* figure out the last position we need to play. If it's configured (stop !=
- * -1), use that, else we play until the total duration of the file */
- if ((stop = seeksegment.stop) == -1)
- stop = seeksegment.duration;
-
- GST_DEBUG_OBJECT (aiff, "cur_type =%d", cur_type);
- if ((cur_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)
- aiff->offset =
- gst_util_uint64_scale_ceil (seeksegment.position,
- (guint64) aiff->bps, GST_SECOND);
- else
- aiff->offset = seeksegment.position;
- GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
- aiff->offset -= (aiff->offset % aiff->bytes_per_sample);
- GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
- aiff->offset += aiff->datastart;
- GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
- } else {
- GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT,
- aiff->offset);
- }
+ /* figure out the last position we need to play. If it's configured (stop !=
+ * -1), use that, else we play until the total duration of the file */
+ if ((stop = seeksegment.stop) == -1)
+ stop = seeksegment.duration;
+
+ GST_DEBUG_OBJECT (aiff, "start_type =%d", start_type);
+ 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)
+ aiff->offset =
+ gst_util_uint64_scale_ceil (seeksegment.position,
+ (guint64) aiff->bps, GST_SECOND);
+ else
+ aiff->offset = seeksegment.position;
+ GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
+ aiff->offset -= (aiff->offset % aiff->bytes_per_sample);
+ GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
+ aiff->offset += aiff->datastart;
+ GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
+ } else {
+ GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT,
+ aiff->offset);
+ }
- if (stop_type != GST_SEEK_TYPE_NONE) {
- if (aiff->bps > 0)
- aiff->end_offset =
- gst_util_uint64_scale_ceil (stop, (guint64) aiff->bps, GST_SECOND);
- else
- aiff->end_offset = stop;
- GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
- aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample);
- GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
- aiff->end_offset += aiff->datastart;
- GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
- } else {
- GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT,
- aiff->end_offset);
- }
+ if (stop_type != GST_SEEK_TYPE_NONE) {
+ if (aiff->bps > 0)
+ aiff->end_offset =
+ gst_util_uint64_scale_ceil (stop, (guint64) aiff->bps, GST_SECOND);
+ else
+ aiff->end_offset = stop;
+ GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
+ aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample);
+ GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
+ aiff->end_offset += aiff->datastart;
+ GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
+ } else {
+ GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT,
+ aiff->end_offset);
+ }
- /* 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))
- aiff->end_offset = MIN (aiff->end_offset, upstream_size);
-
- /* this is the range of bytes we will use for playback */
- aiff->offset = MIN (aiff->offset, aiff->end_offset);
- aiff->dataleft = aiff->end_offset - aiff->offset;
-
- GST_DEBUG_OBJECT (aiff,
- "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
- ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, aiff->offset,
- aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
- GST_TIME_ARGS (stop));
-
- /* prepare for streaming again */
- if (flush) {
- /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
- GST_DEBUG_OBJECT (aiff, "sending flush stop");
- gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop (TRUE));
- }
+ /* 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))
+ aiff->end_offset = MIN (aiff->end_offset, upstream_size);
- /* now we did the seek and can activate the new segment values */
- memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment));
+ /* this is the range of bytes we will use for playback */
+ aiff->offset = MIN (aiff->offset, aiff->end_offset);
+ aiff->dataleft = aiff->end_offset - aiff->offset;
- /* if we're doing a segment seek, post a SEGMENT_START message */
- if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- gst_element_post_message (GST_ELEMENT_CAST (aiff),
- gst_message_new_segment_start (GST_OBJECT_CAST (aiff),
- aiff->segment.format, aiff->segment.position));
- }
+ GST_DEBUG_OBJECT (aiff,
+ "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
+ ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate,
+ aiff->offset, aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
+ GST_TIME_ARGS (stop));
+
+ /* prepare for streaming again */
+ if (flush) {
+ /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
+ GST_DEBUG_OBJECT (aiff, "sending flush stop");
+ gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop (TRUE));
+ }
- /* now create the segment */
- GST_DEBUG_OBJECT (aiff, "Creating segment from %" G_GINT64_FORMAT
- " to %" G_GINT64_FORMAT, aiff->segment.position, stop);
+ /* now we did the seek and can activate the new segment values */
+ memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment));
- /* store the segment event so it can be sent from the streaming thread. */
- if (aiff->start_segment)
- gst_event_unref (aiff->start_segment);
- aiff->start_segment = gst_event_new_segment (&aiff->segment);
+ /* if we're doing a segment seek, post a SEGMENT_START message */
+ if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ gst_element_post_message (GST_ELEMENT_CAST (aiff),
+ gst_message_new_segment_start (GST_OBJECT_CAST (aiff),
+ aiff->segment.format, aiff->segment.position));
+ }
- /* mark discont if we are going to stream from another position. */
- if (position != aiff->segment.position) {
- GST_DEBUG_OBJECT (aiff, "mark DISCONT, we did a seek to another position");
- aiff->discont = TRUE;
- }
+ /* now create the segment */
+ GST_DEBUG_OBJECT (aiff, "Creating segment from %" G_GINT64_FORMAT
+ " to %" G_GINT64_FORMAT, aiff->segment.position, stop);
- /* and start the streaming task again */
- aiff->segment_running = TRUE;
- if (!aiff->streaming) {
- gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
- aiff->sinkpad, NULL);
- }
+ /* store the segment event so it can be sent from the streaming thread. */
+ if (aiff->start_segment)
+ gst_event_unref (aiff->start_segment);
+ aiff->start_segment = gst_event_new_segment (&aiff->segment);
- GST_PAD_STREAM_UNLOCK (aiff->sinkpad);
+ /* mark discont if we are going to stream from another position. */
+ if (position != aiff->segment.position) {
+ GST_DEBUG_OBJECT (aiff,
+ "mark DISCONT, we did a seek to another position");
+ aiff->discont = TRUE;
+ }
- return TRUE;
+ /* and start the streaming task again */
+ aiff->segment_running = TRUE;
+ if (!aiff->streaming) {
+ gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
+ aiff->sinkpad, NULL);
+ }
+
+ GST_PAD_STREAM_UNLOCK (aiff->sinkpad);
+
+ res = TRUE;
+ }
+
+ return res;
/* ERRORS */
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
* event, this will still do the right thing and it will also send
* 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 */
event_p = &aiff->seek_event;
gst_event_replace (event_p, NULL);
@@ -1133,7 +1177,7 @@ gst_aiff_parse_send_event (GstElement * element, GstEvent * event)
case GST_EVENT_SEEK:
if (aiff->state == AIFF_PARSE_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 {
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:
/* can only handle events when we are in the data state */
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);
break;
@@ -1767,8 +1811,6 @@ gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
segment.format = aiff->segment.format;
segment.time = segment.position = segment.start;
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);
@@ -1794,6 +1836,13 @@ gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
gst_event_unref (event);
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:
ret = gst_pad_event_default (aiff->sinkpad, parent, event);
break;