[pitivi] previewers: implements a pipelineCPUAdapter class.



commit ef71100478d8e1beb70ded00dee54e8ad83a8dbe
Author: Mathieu Duponchelle <mathieu duponchelle epitech eu>
Date:   Thu Jun 20 04:21:41 2013 +0200

    previewers: implements a pipelineCPUAdapter class.
    
        + And use it in waveforms.

 pitivi/timeline/previewers.py |   90 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 89 insertions(+), 1 deletions(-)
---
diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py
index 585dc78..8aa0b0d 100644
--- a/pitivi/timeline/previewers.py
+++ b/pitivi/timeline/previewers.py
@@ -20,6 +20,7 @@
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
+import multiprocessing
 import numpy
 import hashlib
 import os
@@ -37,8 +38,15 @@ from pitivi.utils.ui import EXPANDED_SIZE, SPACING
 from pitivi.utils.misc import path_from_uri, quote_uri
 from pitivi.utils.ui import EXPANDED_SIZE, SPACING, CONTROL_WIDTH
 
+from math import log1p, log10
+
+import resource
+
 from renderer import *
 
+
+CPU_USAGE = 30 * multiprocessing.cpu_count()
+
 INTERVAL = 500000  # For the waveform update interval.
 
 BORDER_WIDTH = 3  # For the timeline elements
@@ -474,6 +482,62 @@ class ThumbnailCache(Loggable):
         self.log("Saved thumbnail cache file: %s" % self._filehash)
 
 
+class PipelineCpuAdapter:
+    """
+    This pipeline manager will modulate the rate of the provided pipeline.
+    It is the responsibility of the caller to set the sync of the sink to False,
+    disable QOS and provide a pipeline with a rate of 1.0.
+    Doing otherwise would be cheating. Cheating is bad.
+    """
+    def __init__(self, pipeline):
+        self.pipeline = pipeline
+
+        self.lastMoment = datetime.now()
+        self.lastUsage = resource.getrusage(resource.RUSAGE_SELF)
+        self.rate = 1.0
+        self.growthFactor = 0.1
+        self.decreaseFactor = 0.1
+        self.done = False
+
+        GLib.timeout_add(200, self._modulateRate)
+
+    def stop(self):
+        self.pipeline = None
+        self.done = True
+
+    def _modulateRate(self):
+        if self.done:
+            return False
+
+        deltaTime = (datetime.now() - self.lastMoment).total_seconds()
+        deltaUsage = resource.getrusage(resource.RUSAGE_SELF).ru_utime - self.lastUsage.ru_utime
+
+        usage_percent = float(deltaUsage) / deltaTime * 100
+
+        print usage_percent, "% CPU"
+
+        if usage_percent >= CPU_USAGE and self.rate > 1.0:
+            self.rate -= self.rate * self.decreaseFactor
+
+        elif usage_percent < CPU_USAGE:
+            self.rate += self.rate * self.growthFactor
+
+        self.lastMoment = datetime.now()
+        self.lastUsage = resource.getrusage(resource.RUSAGE_SELF)
+
+        self.pipeline.set_state(Gst.State.PAUSED)
+        self.pipeline.seek(self.rate,
+                           Gst.Format.TIME,
+                           Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
+                           Gst.SeekType.SET,
+                           self.pipeline.query_position(Gst.Format.TIME)[1],
+                           Gst.SeekType.NONE,
+                           -1)
+        self.pipeline.set_state(Gst.State.PLAYING)
+
+        return True
+
+
 class AudioPreviewer(Clutter.Actor, Zoomable):
     """
     Audio previewer based on the results from the "level" gstreamer element.
@@ -506,10 +570,15 @@ class AudioPreviewer(Clutter.Actor, Zoomable):
 
     def startLevelsDiscovery(self, uri):
         self.peaks = None
-        self.pipeline = Gst.parse_launch("uridecodebin uri=" + uri + " ! audioconvert ! level 
interval=10000000 post-messages=true ! fakesink")
+        self.pipeline = Gst.parse_launch("uridecodebin uri=" + uri + " ! audioconvert ! level 
interval=10000000 post-messages=true ! fakesink qos=false")
+
+        self.adapter = None
+
         bus = self.pipeline.get_bus()
         bus.add_signal_watch()
+
         bus.connect("message", self._messageCb)
+
         self.pipeline.set_state(Gst.State.PLAYING)
 
     def set_size(self, width, height):
@@ -592,12 +661,31 @@ class AudioPreviewer(Clutter.Actor, Zoomable):
             self.start = 0
             self.end = self.nbSamples
             self._compute_geometry()
+            if self.adapter:
+                self.adapter.stop()
             self.pipeline.set_state(Gst.State.NULL)
 
         elif message.type == Gst.MessageType.ERROR:
+            if self.adapter:
+                self.adapter.stop()
             # Something went wrong TODO : recover
             self.pipeline.set_state(Gst.State.NULL)
 
+        elif message.type == Gst.MessageType.STATE_CHANGED:
+            prev, new, pending = message.parse_state_changed()
+            if message.src == self.pipeline:
+                if prev == Gst.State.READY and new == Gst.State.PAUSED:
+                    self.pipeline.seek(1.0,
+                                       Gst.Format.TIME,
+                                       Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
+                                       Gst.SeekType.SET,
+                                       0,
+                                       Gst.SeekType.NONE,
+                                       -1)
+
+                elif not self.adapter and prev == Gst.State.PAUSED and new == Gst.State.PLAYING:
+                    self.adapter = PipelineCpuAdapter(self.pipeline)
+
     def _drawContentCb(self, canvas, cr, surf_w, surf_h):
         cr.set_operator(cairo.OPERATOR_CLEAR)
         cr.paint()


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