libs/gst/base/gstbasesrc.c: Don't update the last_stop position in do_seek, that...
authorWim Taymans <wim.taymans@gmail.com>
Mon, 7 Jan 2008 11:23:00 +0000 (11:23 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 7 Jan 2008 11:23:00 +0000 (11:23 +0000)
Original commit message from CVS:
* 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.

ChangeLog
libs/gst/base/gstbasesrc.c
tests/check/elements/filesrc.c

index 9b3b4da..a5fc46a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+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>
index d113e35..3cc0520 100644 (file)
@@ -895,11 +895,9 @@ gst_base_src_default_do_seek (GstBaseSrc * src, GstSegment * segment)
 
   /* 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
@@ -1973,6 +1971,7 @@ gst_base_src_loop (GstPad * pad)
   GstFlowReturn ret;
   gint64 position;
   gboolean eos;
+  gulong blocksize;
 
   eos = FALSE;
 
@@ -1988,13 +1987,26 @@ gst_base_src_loop (GstPad * pad)
 
   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));
@@ -2018,8 +2030,14 @@ gst_base_src_loop (GstPad * pad)
   /* 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;
@@ -2032,23 +2050,44 @@ gst_base_src_loop (GstPad * pad)
       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);
   }
index 0f6549b..1c8c1a1 100644 (file)
 
 #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,
@@ -37,14 +39,31 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("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 *
@@ -57,6 +76,10 @@ setup_filesrc ()
   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;
 }
 
@@ -66,6 +89,9 @@ cleanup_filesrc (GstElement * 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)
@@ -101,6 +127,41 @@ 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;
@@ -323,6 +384,7 @@ filesrc_suite (void)
 
   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);