+2008-01-07 Wim Taymans <wim.taymans@collabora.co.uk>
+
+ * libs/gst/base/gstbasesrc.c: (gst_base_src_default_do_seek),
+ (gst_base_src_loop):
+ Don't update the last_stop position in do_seek, that's the position we
+ did a seek to.
+ Read backwards when we have a negative rate.
+
+ * tests/check/elements/filesrc.c: (event_func), (wait_eos),
+ (setup_filesrc), (cleanup_filesrc), (GST_START_TEST),
+ (filesrc_suite):
+ Add check for reverse reading.
+
2008-01-07 Tim-Philipp Müller <tim at centricular dot net>
Patch by: Alexis Ballier <aballier at gentoo org>
/* update our offset if the start/stop position was updated */
if (segment->format == GST_FORMAT_BYTES) {
- segment->last_stop = segment->start;
segment->time = segment->start;
} else if (segment->start == 0) {
/* seek to start, we can implement a default for this. */
- segment->last_stop = 0;
segment->time = 0;
res = TRUE;
} else
GstFlowReturn ret;
gint64 position;
gboolean eos;
+ gulong blocksize;
eos = FALSE;
src->priv->last_sent_eos = FALSE;
+ blocksize = src->blocksize;
+
/* if we operate in bytes, we can calculate an offset */
- if (src->segment.format == GST_FORMAT_BYTES)
+ if (src->segment.format == GST_FORMAT_BYTES) {
position = src->segment.last_stop;
- else
+ /* for negative rates, start with subtracting the blocksize */
+ if (src->segment.rate < 0.0) {
+ /* we cannot go below segment.start */
+ if (position > src->segment.start + blocksize)
+ position -= blocksize;
+ else {
+ /* last block, remainder up to segment.start */
+ blocksize = position - src->segment.start;
+ position = src->segment.start;
+ }
+ }
+ } else
position = -1;
- ret = gst_base_src_get_range (src, position, src->blocksize, &buf);
+ ret = gst_base_src_get_range (src, position, blocksize, &buf);
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
GST_INFO_OBJECT (src, "pausing after gst_base_src_get_range() = %s",
gst_flow_get_name (ret));
/* figure out the new position */
switch (src->segment.format) {
case GST_FORMAT_BYTES:
- position += GST_BUFFER_SIZE (buf);
+ {
+ guint bufsize = GST_BUFFER_SIZE (buf);
+
+ /* we subtracted above for negative rates */
+ if (src->segment.rate >= 0.0)
+ position += bufsize;
break;
+ }
case GST_FORMAT_TIME:
{
GstClockTime start, duration;
else
position = src->segment.last_stop;
- if (GST_CLOCK_TIME_IS_VALID (duration))
- position += duration;
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
+ if (src->segment.rate >= 0.0)
+ position += duration;
+ else if (position > duration)
+ position -= duration;
+ else
+ position = 0;
+ }
break;
}
case GST_FORMAT_DEFAULT:
- position = GST_BUFFER_OFFSET_END (buf);
+ if (src->segment.rate >= 0.0)
+ position = GST_BUFFER_OFFSET_END (buf);
+ else
+ position = GST_BUFFER_OFFSET (buf);
break;
default:
position = -1;
break;
}
if (position != -1) {
- if (src->segment.stop != -1) {
- if (position >= src->segment.stop) {
+ if (src->segment.rate >= 0.0) {
+ /* positive rate, check if we reached the stop */
+ if (src->segment.stop != -1) {
+ if (position >= src->segment.stop) {
+ eos = TRUE;
+ position = src->segment.stop;
+ }
+ }
+ } else {
+ /* negative rate, check if we reached the start. start is always set to
+ * something different from -1 */
+ if (position <= src->segment.start) {
eos = TRUE;
- position = src->segment.stop;
+ position = src->segment.start;
}
+ /* when going reverse, all buffers are DISCONT */
+ src->priv->discont = TRUE;
}
gst_segment_set_last_stop (&src->segment, src->segment.format, position);
}
#include <gst/check/gstcheck.h>
-gboolean have_eos = FALSE;
+static gboolean have_eos = FALSE;
+static GCond *eos_cond;
+static GMutex *event_mutex;
-GstPad *mysinkpad;
+static GstPad *mysinkpad;
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
gboolean
event_func (GstPad * pad, GstEvent * event)
{
+ gboolean res = TRUE;
+
+ g_mutex_lock (event_mutex);
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
have_eos = TRUE;
- gst_event_unref (event);
- return TRUE;
+ GST_DEBUG ("signal EOS");
+ g_cond_broadcast (eos_cond);
}
+ g_mutex_unlock (event_mutex);
gst_event_unref (event);
- return FALSE;
+
+ return res;
+}
+
+void
+wait_eos (void)
+{
+ g_mutex_lock (event_mutex);
+ GST_DEBUG ("waiting for EOS");
+ while (!have_eos) {
+ g_cond_wait (eos_cond, event_mutex);
+ }
+ GST_DEBUG ("received EOS");
+ g_mutex_unlock (event_mutex);
}
GstElement *
mysinkpad = gst_check_setup_sink_pad (filesrc, &sinktemplate, NULL);
gst_pad_set_event_function (mysinkpad, event_func);
gst_pad_set_active (mysinkpad, TRUE);
+
+ eos_cond = g_cond_new ();
+ event_mutex = g_mutex_new ();
+
return filesrc;
}
gst_pad_set_active (mysinkpad, FALSE);
gst_check_teardown_sink_pad (filesrc);
gst_check_teardown_element (filesrc);
+
+ g_cond_free (eos_cond);
+ g_mutex_free (event_mutex);
}
GST_START_TEST (test_seeking)
GST_END_TEST;
+GST_START_TEST (test_reverse)
+{
+ GstElement *src;
+
+#ifndef TESTFILE
+#error TESTFILE not defined
+#endif
+ src = setup_filesrc ();
+
+ g_object_set (G_OBJECT (src), "location", TESTFILE, NULL);
+ /* we're going to perform the seek in ready */
+ fail_unless (gst_element_set_state (src,
+ GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to ready");
+
+ /* reverse seek from end to start */
+ gst_element_seek (src, -1.0, GST_FORMAT_BYTES, 0, GST_SEEK_TYPE_SET, 100,
+ GST_SEEK_TYPE_SET, -1);
+
+ fail_unless (gst_element_set_state (src,
+ GST_STATE_PAUSED) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to paused");
+
+ /* wait for EOS */
+ wait_eos ();
+
+ fail_unless (gst_element_set_state (src,
+ GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+
+ /* cleanup */
+ cleanup_filesrc (src);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_pull)
{
GstElement *src;
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_seeking);
+ tcase_add_test (tc_chain, test_reverse);
tcase_add_test (tc_chain, test_pull);
tcase_add_test (tc_chain, test_coverage);
tcase_add_test (tc_chain, test_uri_interface);