[pitivi: 1/2] Add pitivi.utils.Seeker. Make ruler and viewer use



commit b4ac961512044d3929d08277f00648039cc878e5
Author: Alessandro Decina <alessandro decina collabora co uk>
Date:   Tue Mar 3 13:18:43 2009 +0100

    Add pitivi.utils.Seeker. Make ruler and viewer use it.
---
 pitivi/ui/ruler.py   |   32 +++++++---------------
 pitivi/ui/viewer.py  |   33 +++++-----------------
 pitivi/utils.py      |   27 ++++++++++++++++++
 tests/test_seeker.py |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 117 insertions(+), 47 deletions(-)

diff --git a/pitivi/ui/ruler.py b/pitivi/ui/ruler.py
index c205dc7..71fb7ab 100644
--- a/pitivi/ui/ruler.py
+++ b/pitivi/ui/ruler.py
@@ -28,7 +28,7 @@ import gtk
 import gst
 from pitivi.ui.zoominterface import Zoomable
 from pitivi.log.loggable import Loggable
-from pitivi.utils import time_to_string
+from pitivi.utils import time_to_string, Seeker
 
 class ScaleRuler(gtk.Layout, Zoomable, Loggable):
 
@@ -68,13 +68,11 @@ class ScaleRuler(gtk.Layout, Zoomable, Loggable):
 
         # position is in nanoseconds
         self.position = 0
-        self.requested_time = gst.CLOCK_TIME_NONE
-        self.currentlySeeking = False
         self.pressed = False
-        self.pending_seek_id = None
         self.shaded_duration = gst.CLOCK_TIME_NONE
         self.max_duration = gst.CLOCK_TIME_NONE
-        self.seek_delay = 80
+        self.seeker = Seeker(80)
+        self.seeker.connect('seek', self._seekerSeekCb)
 
 ## Zoomable interface override
 
@@ -168,32 +166,22 @@ class ScaleRuler(gtk.Layout, Zoomable, Loggable):
 
 ## Seeking methods
 
-    def _seekTimeoutCb(self):
-        self.pending_seek_id = None
-
-        self.debug("delayed seek timeout %s %s",
-                   gst.TIME_ARGS(self.seek_position), self.seek_format)
-
+    def _seekerSeekCb(self, seeker, position, format):
         # clamping values within acceptable range
         duration = self.getShadedDuration()
         if duration == gst.CLOCK_TIME_NONE:
             return
-        if self.seek_position > duration:
-            self.seek_position = duration - (1 * gst.MSECOND)
-        elif self.seek_position < 0:
-            self.seek_position = 0
+        if position > duration:
+            position = duration - (1 * gst.MSECOND)
+        elif position < 0:
+            position = 0
 
-        self.emit('seek', self.seek_position)
+        self.emit('seek', position)
 
         return False
 
     def _doSeek(self, value, format=gst.FORMAT_TIME):
-        if self.pending_seek_id is None:
-            self.pending_seek_id = gobject.timeout_add(self.seek_delay,
-                    self._seekTimeoutCb)
-
-        self.seek_position = value
-        self.seek_format = format
+        self.seeker.seek(value, format)
 
 ## Drawing methods
 
diff --git a/pitivi/ui/viewer.py b/pitivi/ui/viewer.py
index 3000b67..ec509dc 100644
--- a/pitivi/ui/viewer.py
+++ b/pitivi/ui/viewer.py
@@ -26,7 +26,7 @@ import gst
 
 from pitivi.action import ViewAction
 
-from pitivi.utils import time_to_string
+from pitivi.utils import time_to_string, Seeker
 from pitivi.log.loggable import Loggable
 
 class ViewerError(Exception):
@@ -53,15 +53,15 @@ class PitiviViewer(gtk.VBox, Loggable):
         Loggable.__init__(self)
         self.log("New PitiviViewer")
 
+        self.seeker = Seeker(80)
+        self.seeker.connect('seek', self._seekerSeekCb)
         self.action = action
         self.pipeline = pipeline
         self.producer = None
 
         self.current_time = long(0)
-        self.requested_time = gst.CLOCK_TIME_NONE
         self._initial_seek = None
         self.current_frame = -1
-        self.currentlySeeking = False
 
         self.currentState = gst.STATE_PAUSED
         self._haveUI = False
@@ -322,29 +322,12 @@ class PitiviViewer(gtk.VBox, Loggable):
                 seekvalue = min(self.current_frame + 1, self.pipeline.getDuration())
             self._doSeek(seekvalue, gst.FORMAT_DEFAULT)
 
-    def _seekTimeoutCb(self):
-        self.debug("requested_time %s", gst.TIME_ARGS(self.requested_time))
-        self.currentlySeeking = False
-        if (self.requested_time != gst.CLOCK_TIME_NONE) and (self.current_time != self.requested_time):
-            self._doSeek(self.requested_time)
-        return False
+    def _doSeek(self, position, format=gst.FORMAT_TIME):
+        self.seeker.seek(position, format)
 
-    def _doSeek(self, value, format=gst.FORMAT_TIME):
-        self.debug("%s , currentlySeeking:%r", gst.TIME_ARGS(value),
-                   self.currentlySeeking)
-        if not self.currentlySeeking:
-            self.currentlySeeking = True
-            try:
-                self.pipeline.seek(value, format=format)
-                self.debug("seek succeeded, request_time = NONE")
-                self.requested_time = gst.CLOCK_TIME_NONE
-                gobject.timeout_add(80, self._seekTimeoutCb)
-                self._newTime(value)
-            except:
-                self.currentlySeeking = False
-        else:
-            if format == gst.FORMAT_TIME:
-                self.requested_time = value
+    def _seekerSeekCb(self, seeker, position, format):
+        self.pipeline.seek(position, format)
+        self._newTime(position)
 
     def _newTime(self, value, frame=-1):
         self.info("value:%s, frame:%d", gst.TIME_ARGS(value), frame)
diff --git a/pitivi/utils.py b/pitivi/utils.py
index 5143d3b..ba5dc75 100644
--- a/pitivi/utils.py
+++ b/pitivi/utils.py
@@ -22,6 +22,7 @@
 
 # set of utility functions
 
+import gobject
 import gst, bisect
 from pitivi.signalinterface import Signallable
 import pitivi.log.log as log
@@ -206,3 +207,29 @@ class PropertyChangeTracker(object, Signallable):
         self.properties[property_name] = value
 
         self.emit(property_name + '-changed', timeline_object, old_value, value)
+
+class Seeker(object, Signallable):
+    __signals__ = {'seek': ['position', 'format']}
+
+    def __init__(self, timeout):
+        self.timeout = timeout
+        self.pending_seek_id = None
+        self.position = None
+        self.format = None
+
+    def seek(self, position, format=gst.FORMAT_TIME):
+        if self.pending_seek_id is None:
+            self.pending_seek_id = self._scheduleSeek(self.timeout,
+                    self._seekTimeoutCb)
+
+        self.position = position
+        self.format = format
+
+    def _scheduleSeek(self, timeout, callback):
+        return gobject.timeout_add(timeout, callback)
+
+    def _seekTimeoutCb(self):
+        self.pending_seek_id = None
+        position, self.position = self.position, None
+        format, self.format = self.format, None
+        self.emit('seek', position, format)
diff --git a/tests/test_seeker.py b/tests/test_seeker.py
new file mode 100644
index 0000000..97af9ab
--- /dev/null
+++ b/tests/test_seeker.py
@@ -0,0 +1,72 @@
+# PiTiVi , Non-linear video editor
+#
+#       tests/test_timeline.py
+#
+# Copyright (c) 2009, Alessandro Decina <alessandro decina collabora co uk>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+from unittest import TestCase
+from pitivi.utils import Seeker
+import gst
+
+class StubSeeker(Seeker):
+    seek_id = 0
+
+    def _scheduleSeek(self, position, format):
+        # mock Seeker._scheduleSeek so that we don't need a mainloop
+        seek_id = self.seek_id
+        self.seek_id += 1
+
+        return seek_id
+
+class TestSeeker(TestCase):
+    def setUp(self):
+        self.seek_count = 0
+        self.seek_position = None
+        self.seek_format = None
+
+    def testSeek(self):
+        def seek_cb(seeker, position, format):
+            self.seek_count += 1
+            self.seek_position = position
+            self.seek_format = format
+
+        seeker = StubSeeker(timeout=10)
+        seeker.connect('seek', seek_cb)
+
+        seeker.seek(1)
+        self.failUnlessEqual(seeker.pending_seek_id, 0)
+        self.failUnlessEqual(seeker.position, 1)
+        self.failUnlessEqual(seeker.format, gst.FORMAT_TIME)
+
+        seeker.seek(2, gst.FORMAT_BYTES)
+        self.failUnlessEqual(seeker.pending_seek_id, 0)
+        self.failUnlessEqual(seeker.position, 2)
+        self.failUnlessEqual(seeker.format, gst.FORMAT_BYTES)
+
+        seeker._seekTimeoutCb()
+        self.failUnlessEqual(self.seek_count, 1)
+        self.failUnlessEqual(self.seek_position, 2)
+        self.failUnlessEqual(self.seek_format, gst.FORMAT_BYTES)
+        self.failUnlessEqual(seeker.pending_seek_id, None)
+        self.failUnlessEqual(seeker.position, None)
+        self.failUnlessEqual(seeker.format, None)
+
+        seeker.seek(3)
+        self.failUnlessEqual(seeker.pending_seek_id, 1)
+        self.failUnlessEqual(seeker.position, 3)
+        self.failUnlessEqual(seeker.format, gst.FORMAT_TIME)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]