[pitivi] previewers: Use a new clock to control CPU usage
- From: Alexandru Băluț <alexbalut src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi] previewers: Use a new clock to control CPU usage
- Date: Fri, 7 Jul 2017 22:33:53 +0000 (UTC)
commit 13c4bd26b9420cd65d17787ce55b31220687238c
Author: Alexandru Băluț <alexandru balut gmail com>
Date: Tue Apr 25 00:31:52 2017 +0200
previewers: Use a new clock to control CPU usage
Fixes T7653
Reviewed-by: Thibault Saunier <tsaunier gnome org>
Differential Revision: https://phabricator.freedesktop.org/D1730
pitivi/timeline/previewers.py | 119 +++++------------------------------------
1 files changed, 14 insertions(+), 105 deletions(-)
---
diff --git a/pitivi/timeline/previewers.py b/pitivi/timeline/previewers.py
index bb3b1d3..926bcf5 100644
--- a/pitivi/timeline/previewers.py
+++ b/pitivi/timeline/previewers.py
@@ -33,6 +33,7 @@ from gi.repository import Gst
from gi.repository import Gtk
from pitivi.settings import get_dir
+from pitivi.settings import GlobalSettings
from pitivi.settings import xdg_cache_home
from pitivi.utils.loggable import Loggable
from pitivi.utils.misc import binary_search
@@ -71,6 +72,13 @@ PREVIEW_GENERATOR_SIGNALS = {
THUMB_HEIGHT = EXPANDED_SIZE - 2 * THUMB_MARGIN_PX
+GlobalSettings.addConfigSection("previewers")
+
+GlobalSettings.addConfigOption("previewers_max_cpu",
+ section="previewers",
+ key="max-cpu-usage",
+ default=90)
+
class PreviewerBin(Gst.Bin, Loggable):
"""Baseclass for elements gathering datas to create previews."""
@@ -843,109 +851,6 @@ class ThumbnailCache(Loggable):
return False
-class PipelineCpuAdapter(Loggable):
- """Pipeline manager modulating the rate of the provided pipeline.
-
- It is the responsibility of the caller to set the sync of the sink to True,
- disable QOS and provide a pipeline with a rate of 1.0.
- Doing otherwise would be cheating. Cheating is bad.
- """
-
- def __init__(self, pipeline):
- Loggable.__init__(self)
- self.pipeline = pipeline
- self.bus = self.pipeline.get_bus()
-
- self.cpu_usage_tracker = CPUUsageTracker()
- self.rate = 1.0
- self.done = False
- self.ready = False
- self.last_pos = 0
- self._bus_cb_id = None
-
- def start(self):
- """Start modulating the rate on the controlled pipeline.
-
- This avoid using too much CPU.
- """
- GLib.timeout_add(200, self._modulateRate)
- self._bus_cb_id = self.bus.connect("message", self.__bus_message_cb)
- self.done = False
-
- def stop(self):
- """Stops modulating the rate on the controlled pipeline."""
- if self._bus_cb_id is not None:
- self.bus.disconnect(self._bus_cb_id)
- self._bus_cb_id = None
- self.pipeline = None
- self.done = True
-
- def _modulateRate(self):
- """Adapts the rate of audio analysis depending on CPU usage."""
- if self.done:
- return False
-
- usage_percent = self.cpu_usage_tracker.usage()
- self.cpu_usage_tracker.reset()
- if usage_percent >= WAVEFORMS_CPU_USAGE:
- if self.rate < 0.1:
- if not self.ready:
- res, position = self.pipeline.query_position(
- Gst.Format.TIME)
- if res:
- self.last_pos = position
- self.pipeline.set_state(Gst.State.READY)
- self.ready = True
- return True
-
- if self.rate > 0.0:
- self.rate *= 0.9
- self.log(
- 'Pipeline rate slowed down (-10%%) to %.3f' % self.rate)
- else:
- self.rate *= 1.1
- self.log('Pipeline rate sped up (+10%%) to %.3f' % self.rate)
-
- if not self.ready:
- res, position = self.pipeline.query_position(Gst.Format.TIME)
- assert res
- else:
- # This to avoid going back and forth from READY to PAUSED
- if self.rate > 0.5:
- # The message handler will unset ready and seek correctly.
- self.pipeline.set_state(Gst.State.PAUSED)
- return True
-
- self.pipeline.set_state(Gst.State.PAUSED)
- self.pipeline.seek(self.rate,
- Gst.Format.TIME,
- Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
- Gst.SeekType.SET,
- position,
- Gst.SeekType.NONE,
- -1)
- self.pipeline.set_state(Gst.State.PLAYING)
- self.ready = False
- # Keep the glib timer running:
- return True
-
- def __bus_message_cb(self, unused_bus, message):
- if not self.ready:
- return
- if message.type == Gst.MessageType.STATE_CHANGED:
- prev, new, unused_pending_state = 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,
- self.last_pos,
- Gst.SeekType.NONE,
- -1)
- self.ready = False
-
-
def get_wavefile_location_for_uri(uri):
"""Computes the URI where the pickled wave file should be stored."""
filename = hash_file(Gst.uri_get_location(uri)) + ".wave"
@@ -1094,8 +999,12 @@ class AudioPreviewer(Previewer, Zoomable, Loggable):
# In case we failed previously, we won't modulate next time
elif not self.adapter and prev == Gst.State.PAUSED and \
new == Gst.State.PLAYING and self._num_failures == 0:
- self.adapter = PipelineCpuAdapter(self.pipeline)
- self.adapter.start()
+ # This line is necessary so we can instantiate GstTranscoder's
+ # GstCpuThrottlingClock below.
+ Gst.ElementFactory.make("uritranscodebin", None)
+ clock = GObject.new(GObject.type_from_name("GstCpuThrottlingClock"))
+ clock.props.cpu_usage = self.app.settings.previewers_max_cpu
+ self.pipeline.use_clock(clock)
# pylint: disable=no-self-use
def _autoplug_select_cb(self, unused_decode, unused_pad, unused_caps, factory):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]