diff --git a/gst/aiff/aiffparse.c b/gst/aiff/aiffparse.c index eaa1b819e9..7d799b3eeb 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); + + /* save current position */ + position = aiff->segment.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)); + + /* 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, "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); + } + + /* 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)); + } + + /* now we did the seek and can activate the new segment values */ + memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment)); + + /* 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)); + } + + /* now create the segment */ + GST_DEBUG_OBJECT (aiff, "Creating segment from %" G_GINT64_FORMAT + " to %" G_GINT64_FORMAT, aiff->segment.position, stop); + + /* 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); + + /* 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; + } + + /* 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; } - /* 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; - - 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)); - - /* 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); - } - - /* 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); - } - - 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)); - } - - /* now we did the seek and can activate the new segment values */ - memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment)); - - /* 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)); - } - - /* now create the segment */ - GST_DEBUG_OBJECT (aiff, "Creating segment from %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, aiff->segment.position, stop); - - /* 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); - - /* 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; - } - - /* 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); - - return 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;