[pitivi: 3/9] mixer: track: undo: curve: Only allow alpha passthrough when all alpha=1.0



commit d7b447f189e1ef4159dff89dcc17f3a17a1ef2ac
Author: Robert Swain <robert swain collabora co uk>
Date:   Wed Aug 4 16:13:49 2010 +0200

    mixer: track: undo: curve: Only allow alpha passthrough when all alpha=1.0
    
    This works around an issue with videomixer where it fixes its caps and so all
    its inputs to non-alpha if ramping from alpha=1.0 down to less than 1.0. This
    caused the pipeline to not use alpha when it should have been.

 pitivi/elements/mixer.py         |   94 +++++++++++++++++++++++++++++++++++++-
 pitivi/timeline/timeline_undo.py |    4 +-
 pitivi/timeline/track.py         |   12 +++--
 pitivi/ui/curve.py               |    7 ++-
 4 files changed, 106 insertions(+), 11 deletions(-)
---
diff --git a/pitivi/elements/mixer.py b/pitivi/elements/mixer.py
index 78aac17..b2859d0 100644
--- a/pitivi/elements/mixer.py
+++ b/pitivi/elements/mixer.py
@@ -26,6 +26,8 @@ Audio and Video mixers
 import gobject
 import gst
 
+from pitivi.signalinterface import Signallable
+
 
 class SmartAdderBin(gst.Bin):
 
@@ -122,7 +124,7 @@ class SmartVideomixerBin(gst.Bin):
 
         )
 
-    def __init__(self):
+    def __init__(self, track):
         gst.Bin.__init__(self)
         self.videomixer = gst.element_factory_make("videomixer", "real-videomixer")
         # black background
@@ -138,6 +140,8 @@ class SmartVideomixerBin(gst.Bin):
         self.inputs = {} # key : pad_name,
                          # value : (sinkpad, ffmpegcolorspace, capsfilter, videomixerpad)
 
+        self.alpha_helper = SmartVideomixerBinPropertyHelper(track, self.inputs)
+
     def update_priority(self, pad, priority):
         self.debug("pad:%r, priority:%d" % ( pad, priority))
         if priority > 10000:
@@ -156,7 +160,11 @@ class SmartVideomixerBin(gst.Bin):
 
         csp = gst.element_factory_make("ffmpegcolorspace", "csp-%d" % self.pad_count)
         capsfilter = gst.element_factory_make("capsfilter", "capsfilter-%d" % self.pad_count)
-        capsfilter.props.caps = gst.Caps("video/x-raw-yuv")
+        # configure the capsfilter caps
+        if self.alpha_helper.alpha_count != 0:
+            capsfilter.props.caps = gst.Caps('video/x-raw-yuv,format=(fourcc)AYUV')
+        else:
+            capsfilter.props.caps = gst.Caps('video/x-raw-yuv')
 
         self.add(csp, capsfilter)
 
@@ -189,6 +197,88 @@ class SmartVideomixerBin(gst.Bin):
             self.remove(capsfilter)
         self.debug("done")
 
+class SmartVideomixerBinPropertyHelper(Signallable):
+    """A set of callbacks used for considering the alpha state of all track
+       objects in the composition."""
+
+    def __init__(self, track, inputs):
+        # this import is here because of a circular dependence
+        from pitivi.timeline.track import TrackError
+        self.inputs = inputs
+        self.alpha_count = 0
+        # connect track-object-{added,removed} signals from track to callbacks
+        track.connect("track-object-added", self._trackAddedCb)
+        track.connect("track-object-removed", self._trackRemovedCb)
+        # connect track_objects' alpha interpolator keyframe-moved signals
+        # to callback and configure initial alpha state
+        for track_object in track.track_objects:
+            try:
+                interpolator =  track_object.getInterpolator("alpha")
+            except TrackError:
+                # no alpha
+                pass
+            else:
+                interpolator.connect("keyframe-added", self._keyframeChangedCb)
+                interpolator.connect("keyframe-moved", self._keyframeChangedCb)
+                interpolator.connect("keyframe-removed", self._keyframeChangedCb)
+                for kf in interpolator.getKeyframes():
+                    if interpolator.valueAt(kf.time) < 1.0:
+                        self.alpha_count += 1
+        if self.alpha_count != 0:
+            self.alphaStateChanged(True)
+        else:
+            self.alphaStateChanged(False)
+
+
+    def _trackAddedCb(self, track, track_object):
+        # this import is here because of a circular dependence
+        from pitivi.timeline.track import TrackError
+        try:
+            interpolator = track_object.getInterpolator("alpha")
+        except TrackError:
+            # no alpha
+            pass
+        else:
+            interpolator.connect("keyframe-added", self._keyframeChangedCb)
+            interpolator.connect("keyframe-moved", self._keyframeChangedCb)
+            interpolator.connect("keyframe-removed", self._keyframeChangedCb)
+
+    def _trackRemovedCb(self, track, track_object):
+        # this import is here because of a circular dependence
+        from pitivi.timeline.track import TrackError
+        try:
+            interpolator = track_object.getInterpolator("alpha")
+        except TrackError:
+            # no alpha
+            pass
+        else:
+            interpolator.disconnect_by_func(self._keyframeChangedCb)
+
+    def _keyframeChangedCb(self, interpolator, keyframe, old_value=None):
+        """Checks the alpha state and emits a signal if it has changed"""
+        # FIXME: This code assumes the interpolation mode is linear and as
+        # such only considers the alpha values at keyframes
+        old_alpha_count = self.alpha_count
+        new_value = interpolator.valueAt(keyframe.time)
+        if old_value == 1.0 or old_value is None:
+            if new_value < 1.0:
+                self.alpha_count += 1
+        elif old_value < 1.0 or old_value is not None:
+            if new_value == 1.0:
+                self.alpha_count -= 1
+        if old_alpha_count == 0 and self.alpha_count > 0:
+            self.alphaStateChanged(True)
+        elif old_alpha_count > 0 and self.alpha_count == 0:
+            self.alphaStateChanged(False)
+
+    def alphaStateChanged(self, has_alpha):
+        """Updates capsfilter caps to reflect the alpha state of composition"""
+        caps = gst.Caps('video/x-raw-yuv')
+        if has_alpha == True:
+            caps[0]["format"] = gst.Fourcc('AYUV')
+        for input in self.inputs.values():
+            input[2].props.caps = caps
+
 
 gobject.type_register(SmartVideomixerBin)
 gst.element_register(SmartVideomixerBin, 'smart-videomixer-bin')
diff --git a/pitivi/timeline/timeline_undo.py b/pitivi/timeline/timeline_undo.py
index a846b14..b7a29ff 100644
--- a/pitivi/timeline/timeline_undo.py
+++ b/pitivi/timeline/timeline_undo.py
@@ -85,10 +85,10 @@ class KeyframeChangeTracker(Signallable):
     def _keyframeAddedCb(self, interpolator, keyframe):
         self.keyframes[keyframe] = self._getKeyframeSnapshot(keyframe)
 
-    def _keyframeRemovedCb(self, interpolator, keyframe):
+    def _keyframeRemovedCb(self, interpolator, keyframe, old_value=None):
         pass
 
-    def _keyframeMovedCb(self, interpolator, keyframe):
+    def _keyframeMovedCb(self, interpolator, keyframe, old_value=None):
         old_snapshot = self.keyframes[keyframe]
         new_snapshot = self._getKeyframeSnapshot(keyframe)
         self.keyframes[keyframe] = new_snapshot
diff --git a/pitivi/timeline/track.py b/pitivi/timeline/track.py
index 41cae1f..7b99fd7 100644
--- a/pitivi/timeline/track.py
+++ b/pitivi/timeline/track.py
@@ -132,8 +132,8 @@ class Interpolator(Signallable, Loggable):
 
     __signals__ = {
         'keyframe-added' : ['keyframe'],
-        'keyframe-removed' : ['keyframe'],
-        'keyframe-moved' : ['keyframe'],
+        'keyframe-removed' : ['keyframe', 'old_value'],
+        'keyframe-moved' : ['keyframe', 'old_value'],
     }
 
     def __init__(self, trackobject, element, prop, minimum=None, maximum=None,
@@ -217,10 +217,11 @@ class Interpolator(Signallable, Loggable):
         return keyframe
 
     def removeKeyframe(self, keyframe):
+        old_value = self._controller.get(self._property.name, keyframe.time)
         self._controller.unset(self._property.name, keyframe.time)
         if keyframe is not self.start and keyframe is not self.end:
             self._keyframes.remove(keyframe)
-            self.emit("keyframe-removed", keyframe)
+            self.emit("keyframe-removed", keyframe, old_value)
 
     def setKeyframeMode(self, kf, mode):
         # FIXME: currently InterpolationSourceControllers only support a
@@ -246,10 +247,11 @@ class Interpolator(Signallable, Loggable):
         self.debug("kf.time:%s, ptime:%s, value:%r",
                    gst.TIME_ARGS(kf.time),
                    gst.TIME_ARGS(ptime), value)
+        old_value = self._controller.get(self._property.name, ptime)
         self._controller.set(self._property.name, ptime, value)
         if kf.time != ptime:
             self._controller.unset(self._property.name, kf.time)
-        self.emit("keyframe-moved", kf)
+        self.emit("keyframe-moved", kf, old_value)
 
     def getKeyframes(self):
         # TODO: This could be more efficient. We are re-sorting all the keyframes
@@ -979,7 +981,7 @@ class Track(Signallable, Loggable):
             return gnl
         elif isinstance(stream, VideoStream):
             gnl = gst.element_factory_make("gnloperation", "top-level-video-mixer")
-            m = SmartVideomixerBin()
+            m = SmartVideomixerBin(self)
             gnl.add(m)
             gnl.props.expandable = True
             gnl.props.priority = 0
diff --git a/pitivi/ui/curve.py b/pitivi/ui/curve.py
index 17ddcab..6e2d41c 100644
--- a/pitivi/ui/curve.py
+++ b/pitivi/ui/curve.py
@@ -173,7 +173,7 @@ class Curve(goocanvas.ItemSimple, goocanvas.Item, View, Zoomable):
     interpolator = receiver()
 
     @handler(interpolator, "keyframe-removed")
-    def keyframeRemoved(self, unused_interpolator, keyframe):
+    def keyframeRemoved(self, unused_interpolator, keyframe, old_value=None):
         if keyframe in self.keyframes:
             del self.keyframes[keyframe]
             if keyframe is self._focused_kf:
@@ -181,10 +181,13 @@ class Curve(goocanvas.ItemSimple, goocanvas.Item, View, Zoomable):
         self.changed(False)
 
     @handler(interpolator, "keyframe-added")
-    @handler(interpolator, "keyframe-moved")
     def curveChanged(self, unused_interpolator, unused_keyframe):
         self.changed(False)
 
+    @handler(interpolator, "keyframe-moved")
+    def curveChanged(self, unused_interpolator, unused_keyframe, old_value=None):
+        self.changed(False)
+
 ## Zoomable interface overries
 
     def zoomChanged(self):



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