Ejemplo n.º 1
0
    def addFadingEffect(self):
        """
        Add the fading effect.
        @see: self.setupFadeBin()
        """
        self.setupFadeBin()

        #Volume control element
        self.volumeControl = gst.Controller(self.volume, "volume")
        self.volumeControl.set_interpolation_mode("volume",
                                                  gst.INTERPOLATE_LINEAR)

        fade_time = 20
        fade_volume = 0.5
        fade_end_time = 30

        reset_time = self.fade_end_1 + 1

        self.volumeControl.set("volume", self.fade_start_1 * gst.SECOND, 1.0)
        self.volumeControl.set("volume", self.fade_end_1 * gst.SECOND,
                               fade_volume * 0.2)
        self.volumeControl.set("volume", reset_time * gst.SECOND, 1.0)
        self.volumeControl.set("volume", self.fade_start_2 * gst.SECOND, 1.0)
        self.volumeControl.set("volume", self.fade_end_2 * gst.SECOND,
                               fade_volume * 0.2)
Ejemplo n.º 2
0
def get_smpte(duration, transition=1):
    """
    Not used right now.
    """
    # To crossfade, we add an alpha channel to both streams. Then a video
    # mixer mixes them according to the alpha channel. We put a control
    # on the alpha channel to linearly sweep it over the duration of the
    # crossfade. The returned bin should get placed in a gnloperation.
    # The reason to put the alpha and final ffmpegcolorspace conversion
    # in this bin is that are only applied during the crossfade and not
    # all the time (saves some processing time).
    bin = gst.Bin()
    alpha1 = gst.element_factory_make("alpha")
    smpte = gst.element_factory_make("smptealpha")
    mixer = gst.element_factory_make("videomixer")
    color = gst.element_factory_make("ffmpegcolorspace")

    bin.add(alpha1, smpte, mixer, color)
    alpha1.link(mixer)
    smpte.link(mixer)
    mixer.link(color)

    smpte.set_property("type", transition)

    controller = gst.Controller(smpte, "position")
    controller.set_interpolation_mode("position", gst.INTERPOLATE_LINEAR)
    controller.set("position", 0, 1.0)
    controller.set("position", duration * gst.MILLISECOND, 0.0)

    bin.add_pad(gst.GhostPad("sink1", alpha1.get_pad("sink")))
    bin.add_pad(gst.GhostPad("sink2", smpte.get_pad("sink")))
    bin.add_pad(gst.GhostPad("src", color.get_pad("src")))

    return bin, controller
Ejemplo n.º 3
0
 def attachToElementProperty(self, prop, element):
     self._element = element
     self._property = prop
     self.debug("Creating a GstController for element %r and property %s",
         self._element, prop.name)
     self._controller = gst.Controller(self._element, prop.name)
     self._controller.set_interpolation_mode(prop.name, gst.INTERPOLATE_LINEAR)
Ejemplo n.º 4
0
def main():
    pipeline = gst.Pipeline("videocontroller")
    src = gst.element_factory_make("videotestsrc", "src")
    mix = gst.element_factory_make("videomixer", "mix")
    conv = gst.element_factory_make("ffmpegcolorspace", "conv")
    sink = gst.element_factory_make("autovideosink", "sink")
    pipeline.add(src, mix, conv, sink)

    spad = src.get_static_pad('src')
    dpad = mix.get_request_pad('sink_%d')

    spad.link(dpad)
    mix.link(conv)
    conv.link(sink)

    control = gst.Controller(dpad, "xpos", "ypos")
    control.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
    control.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)

    control.set("xpos", 0, 0)
    control.set("xpos", 5 * gst.SECOND, 200)

    control.set("ypos", 0, 0)
    control.set("ypos", 5 * gst.SECOND, 200)

    pipeline.set_state(gst.STATE_PLAYING)

    time.sleep(7)
Ejemplo n.º 5
0
    def __init__(self, position=0, duration=2 * gst.SECOND, fadefromblack=True):
        gst.Bin.__init__(self)
        self.incsp = gst.element_factory_make("ffmpegcolorspace", "incsp")
        self.outcsp = gst.element_factory_make("ffmpegcolorspace", "outcsp")
        self.alpha = gst.element_factory_make("alpha", "alpha")
        self.vmix = gst.element_factory_make("videomixer", "videomix")
        self.vmix.set_property("background", 1)
        self.add(self.incsp, self.alpha, self.vmix, self.outcsp)
        gst.element_link_many(self.incsp, self.alpha, self.vmix, self.outcsp)

        self._sinkpad = gst.GhostPad("sink", self.incsp.get_pad("sink"))
        self._sinkpad.set_active(True)
        self._srcpad = gst.GhostPad("src", self.outcsp.get_pad("src"))
        self._srcpad.set_active(True)

        self.add_pad(self._sinkpad)
        self.add_pad(self._srcpad)

        self.startposition = position
        self.duration = duration
        self.fadefromblack = fadefromblack

        self.alphacontrol = gst.Controller(self.alpha, "alpha")
        self.alphacontrol.set_interpolation_mode("alpha", gst.INTERPOLATE_LINEAR)

        self._resetControllerValues()
Ejemplo n.º 6
0
def get_crossfade(duration):
    # To crossfade, we add an alpha channel to both streams. Then a video
    # mixer mixes them according to the alpha channel. We put a control
    # on the alpha channel to linearly sweep it over the duration of the
    # crossfade. The returned bin should get placed in a gnloperation.
    # The reason to put the alpha and final ffmpegcolorspace conversion
    # in this bin is that are only applied during the crossfade and not
    # all the time (saves some processing time).
    bin = gst.Bin()
    alpha1 = gst.element_factory_make("alpha")
    alpha2 = gst.element_factory_make("alpha")
    mixer = gst.element_factory_make("videomixer")
    color = gst.element_factory_make("ffmpegcolorspace")

    bin.add(alpha1, alpha2, mixer, color)
    alpha1.link(mixer)
    alpha2.link(mixer)
    mixer.link(color)

    controller = gst.Controller(alpha2, "alpha")
    controller.set_interpolation_mode("alpha", gst.INTERPOLATE_LINEAR)
    controller.set("alpha", 0, 0.0)
    controller.set("alpha", duration * gst.MILLISECOND, 1.0)

    bin.add_pad(gst.GhostPad("sink1", alpha1.get_pad("sink")))
    bin.add_pad(gst.GhostPad("sink2", alpha2.get_pad("sink")))
    bin.add_pad(gst.GhostPad("src", color.get_pad("src")))

    return bin, controller  # return the controller otherwise it will go out of scope and get deleted before it is even applied
Ejemplo n.º 7
0
 def setupEchoControl(self):
     """
     Setup the gst.Controller object to adjust the
     intensity of the audio echo.
     """
     self.echoControl = gst.Controller(self.echo, "intensity")
     self.echoControl.set("intensity", 0*gst.SECOND, 0.5)
     self.echoControl.set("intensity", 4*gst.SECOND, 0.0)
Ejemplo n.º 8
0
    def __init__(self):

        src1 = gst.element_factory_make("filesrc")
        src2 = gst.element_factory_make("filesrc")

        src1.set_property("location", "/home/flavio/001")
        src2.set_property("location", "/home/flavio/002")

        dec1 = gst.element_factory_make("decodebin2")
        dec2 = gst.element_factory_make("decodebin2")

        alpha1 = gst.element_factory_make("alpha")
        alpha2 = gst.element_factory_make("alpha")

        self.controller = gst.Controller(alpha2, "alpha")
        self.controller.set_interpolation_mode("alpha", gst.INTERPOLATE_LINEAR)
        self.controller.set("alpha", 0, 0.0)
        #self.controller.set("alpha", 5*gst.SECOND, 0.5)
        self.controller.set("alpha", 0.0, 0.5)

        mixer = gst.element_factory_make("videomixer")

        queue = gst.element_factory_make("queue")
        color = gst.element_factory_make("ffmpegcolorspace")
        sink = gst.element_factory_make("xvimagesink")

        pipeline = gst.Pipeline("pipeline")

        pipeline.add(src1, src2, dec1, dec2, alpha1, alpha2, mixer, queue,
                     color, sink)

        def on_pad(comp, pad, data, element):
            #padname = pad.get_name()
            caps = pad.get_caps()
            name = caps[0].get_name()

            if 'video/x-raw-yuv' in name:
                sinkpad = element.get_compatible_pad(pad, pad.get_caps())
                #sinkpad = element.get_pad('sink')
                pad.link(sinkpad)

            else:
                pass

        dec1.connect("new-decoded-pad", on_pad, alpha1)
        dec2.connect("new-decoded-pad", on_pad, alpha2)

        src1.link(dec1)
        src2.link(dec2)

        alpha1.link(mixer)
        alpha2.link(mixer)

        mixer.link(queue)
        queue.link(color)
        color.link(sink)

        self.pipeline = pipeline
Ejemplo n.º 9
0
    def _makeGnlObject(self):
        trans = gst.element_factory_make("alpha")
        self.controller = gst.Controller(trans, "alpha")
        self.controller.set_interpolation_mode("alpha", gst.INTERPOLATE_LINEAR)

        self.operation = gst.element_factory_make("gnloperation")
        self.operation.add(trans)
        self.operation.props.media_start = 0
        self.operation.props.caps = self.caps
Ejemplo n.º 10
0
    def _makeGnlObject(self):
        trans = gst.element_factory_make("volume")
        self.a_controller = gst.Controller(trans, "volume")
        self.a_controller.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR)

        self.a_operation = gst.element_factory_make("gnloperation")
        self.a_operation.add(trans)

        trans = gst.element_factory_make("volume")
        self.b_controller = gst.Controller(trans, "volume")
        self.b_controller.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR)

        self.b_operation = gst.element_factory_make("gnloperation")
        self.b_operation.add(trans)

        self.a_operation.props.media_start = 0

        self.b_operation.props.media_start = 0
Ejemplo n.º 11
0
def get_crossfade_bin(name, config, duration, start1):
    bin = get_alpha_transition(config, element="alpha")
    alpha = bin.get_by_name("alpha2")

    controller = gst.Controller(alpha, "alpha")
    controller.set_interpolation_mode("alpha", gst.INTERPOLATE_LINEAR)
    controller.set("alpha", 0, 0.0)
    controller.set("alpha", duration, 1.0)

    return bin, controller
Ejemplo n.º 12
0
    def get_bin(self, duration=None):
        if self.filename == "silence":
            return Audio.get_silence_bin(self.config)

        bin = gst.Bin()
        elements = []
        for name in [
                "filesrc",
                "decodebin2",
                "audioconvert",
                "audioresample",
                "capsfilter",
                "volume",
        ]:
            elements.append(gst.element_factory_make(name, name))
            exec("%s = elements[-1]" % name)

        capsfilter.props.caps = self.config.get_audio_caps()
        caps2 = gst.element_factory_make("capsfilter")
        caps2.props.caps = self.config.get_audio_caps()
        elements.append(caps2)
        filesrc.set_property("location", self.filename)
        bin.add(*elements)
        filesrc.link(decodebin2)
        gst.element_link_many(*elements[2:])

        if (self.settings.has_key("volume")):
            vol = self.settings["volume"]
        else:
            vol = 1.0
        print "vol=", vol, " settings=", self.settings

        c = gst.Controller(volume, "volume")
        c.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR)
        if self.fadein:
            c.set("volume", self.start, 0.0)
            c.set("volume", self.start + self.fadein, vol)
        else:
            c.set("volume", 0, vol)

        if self.fadeout:
            c.set("volume", duration - self.fadeout, vol)
            c.set("volume", duration, 0.0)
        else:
            c.set("volume", duration, vol)
        self.controllers.append(c)

        def on_pad(src_element, pad, data, sink_element):
            sinkpad = sink_element.get_compatible_pad(pad, pad.get_caps())
            pad.link(sinkpad)

        decodebin2.connect("new-decoded-pad", on_pad, audioconvert)
        bin.add_pad(gst.GhostPad("src", elements[-1].get_pad("src")))
        return bin
Ejemplo n.º 13
0
 def setupVolumeControl(self):
     """
     Setup the gst.Controller object to adjust the volume.
     @todo: See a TODO comment about use of
           Controller.set_interpolation_mode()
     """
     self.volumeControl = gst.Controller(self.volume, "volume")
     self.volumeControl.set("volume", 0.0 * gst.SECOND, self.volumeLevel)
     # Alternatively, try gst.INTERPOLATE_CUBIC to see how it affects
     # the fading effect.
     self.volumeControl.set_interpolation_mode("volume",
                                               gst.INTERPOLATE_LINEAR)
Ejemplo n.º 14
0
def get_smpte_bin(name, config, duration, start1):
    if (name == "wipe"):
        name = "bar-wipe-lr"

    bin = get_alpha_transition(config, element="smptealpha")
    alpha = bin.get_by_name("alpha2")
    alpha.props.type = name

    controller = gst.Controller(alpha, "position")
    controller.set_interpolation_mode("position", gst.INTERPOLATE_LINEAR)
    controller.set("position", 0, 1.0)
    controller.set("position", duration, 0.0)

    return bin, controller
Ejemplo n.º 15
0
def configure_kenburns(self, kenburns, duration):
    import gst
    for i, fx in enumerate(self.effects):
        if fx.name == "kenburns":
            zstart, pstart, zend, pend = map(str.strip, fx.param.split(";"))
            zpos1, xpos1, ypos1 = parse_kb_params(zstart, pstart, self.config, self.width, self.height)
            zpos2, xpos2, ypos2 = parse_kb_params(zend,   pend,   self.config, self.width, self.height)
            c = gst.Controller(kenburns, "zpos", "ypos", "xpos")
            c.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
            c.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
            c.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
            c.set("zpos", 0,        zpos1)
            c.set("zpos", duration, zpos2)
            c.set("xpos", 0,        xpos1)
            c.set("xpos", duration, xpos2)
            c.set("ypos", 0,        ypos1)
            c.set("ypos", duration, ypos2)
            self.controllers.append(c)
Ejemplo n.º 16
0
def main():
    type = 'async'
    loop = gobject.MainLoop()

    pipeline = gst.Pipeline("cutter")
    src = gst.element_factory_make("sinesrc", "src")
    cutter = gst.element_factory_make("cutter")
    cutter.set_property('threshold', 0.5)
    sink = gst.element_factory_make("fakesink", "sink")
    pipeline.add(src, cutter, sink)
    src.link(cutter)
    cutter.link(sink)

    control = gst.Controller(src, "volume")
    control.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR)

    control.set("volume", 0, 0.0)
    control.set("volume", 2 * gst.SECOND, 1.0)
    control.set("volume", 4 * gst.SECOND, 0.0)
    control.set("volume", 6 * gst.SECOND, 1.0)
    control.set("volume", 8 * gst.SECOND, 0.0)
    control.set("volume", 10 * gst.SECOND, 1.0)

    bus = pipeline.get_bus()

    if type == 'async':
        bus.add_signal_watch()
        bus.connect('message::element', on_message_application, loop)
    else:
        # FIXME: needs wrapping in gst-python
        bus.set_sync_handler(bus.sync_signal_handler)
        bus.connect('sync-message::element', on_message_application, loop)

    pipeline.set_state(gst.STATE_PLAYING)

    loop.run()

    pipeline.set_state(gst.STATE_NULL)
Ejemplo n.º 17
0
def main():
    pipeline = gst.Pipeline("audiocontroller")
    src = gst.element_factory_make("audiotestsrc", "src")
    sink = gst.element_factory_make("alsasink", "sink")
    pipeline.add(src, sink)
    src.link(sink)

    control = gst.Controller(src, "freq", "volume")
    control.set_interpolation_mode("volume", gst.INTERPOLATE_LINEAR)
    control.set_interpolation_mode("freq", gst.INTERPOLATE_LINEAR)

    control.set("volume", 0, 0.0)
    control.set("volume", 2 * gst.SECOND, 1.0)
    control.set("volume", 4 * gst.SECOND, 0.0)
    control.set("volume", 6 * gst.SECOND, 1.0)

    control.set("freq", 0, 440.0)
    control.set("freq", 3 * gst.SECOND, 3000.0)
    control.set("freq", 6 * gst.SECOND, 880.0)

    pipeline.set_state(gst.STATE_PLAYING)

    time.sleep(7)
Ejemplo n.º 18
0
    def __init__(self, uri, start, duration, fadein, fadeout, volume):
        gst.Bin.__init__(self)
        self.start = start
        self.duration = duration
        self.clip_volume = volume
        self.already_seeked = False
        self.fading = False

        self.src_wav_file = gst.element_factory_make("filesrc")
        self.src_wav_file.set_property("location", uri)
        self.wavparse = gst.element_factory_make("wavparse")
        self.audioconvert = gst.element_factory_make("audioconvert")
        self.audioresample = gst.element_factory_make("audioresample")
        self.audiopanorama = gst.element_factory_make("audiopanorama")
        self.volume = gst.element_factory_make("volume")
        self.controller = gst.Controller(self.volume, "volume")
        self.controller.set_interpolation_mode("volume",
                                               gst.INTERPOLATE_LINEAR)
        self.controller.set("volume", 0, 0.0)
        self.controller.set("volume", start, 0.0)
        self.controller.set("volume", start + fadein, volume)
        self.controller.set("volume", start + duration - fadeout, volume)
        self.controller.set("volume", start + duration, 0.0)
        self.add(self.src_wav_file, self.wavparse, self.audioconvert,
                 self.audioresample, self.audiopanorama, self.volume)
        gst.element_link_many(self.src_wav_file, self.wavparse)
        gst.element_link_many(self.audioconvert, self.audioresample,
                              self.audiopanorama, self.volume)

        def on_pad(comp, pad):
            convpad = self.audioconvert.get_compatible_pad(pad, pad.get_caps())
            pad.link(convpad)

        self.wavparse.connect("pad-added", on_pad)
        self.pad = self.volume.get_pad("src")
        self.ghostpad = gst.GhostPad("src", self.pad)
        self.add_pad(self.ghostpad)
Ejemplo n.º 19
0
def parse_annotate_params(self, element, params, duration=0):
    # valid params:
    #  text= ;
    #  halign=<left|center|right>
    #  valign=<top|bottom|baseline>
    #  size=X%;                     (as percent of total image)
    #  color=color;                 ('black', 'white', 'orange','0x556633')
    #  font=font;                   
    #  fontstyle=fontstle (space separated list of varient, weight, stretch, or gravity;                   
    #  vertical=<0|1>               (display text vertically)
    #  justification=<0-left|1-right|2-center>

    props = dict(text = "Fill me in", 
                 shaded_background=False,
                 duration=0, # 0 means the duration of the entire slide
                 start=0,    # start time to turn on the annotation
                 )

    # first initialize props based on config dictionary (global defaults)
    for key in [ "annotate_size", "annotate_font", "annotate_color", "annotate_halign", "annotate_valign", "annotate_vertical", "annotate_justification", "annotate_fontstyle" ]:
        props[key.replace("annotate_","")] = self.config[key]

    params = map(str.strip, params.strip().split(";"))
    for param in params:
        if param:
            key,val = param.split("=",1)
            props[key] = val

    if props.has_key("size"):
        if props["size"].endswith("%"):
            props["size"] = round(self.config["height"] * eval(props["size"].replace("%","")) / 10.)/10.
        else:
            props["size"] = eval(props["size"])


    font = "%s %s %gpx" % (props["font"], props["fontstyle"], props["size"],)
    props["text"] = props["text"].replace("\\n", "\n")

    def set_prop(element, prop, value):
        try:
            element.set_property(prop, value)
        except TypeError:
            log.warn("Annotation: Cannot set property %s to %s because gstreamer-plugins-base is too old. Update to enable this feature." % (prop, value))

    set_prop(element, "text",              props["text"])
    set_prop(element, "shaded-background", int(props["shaded_background"]))
    set_prop(element, "halignment", props["halign"])
    set_prop(element, "valignment", props["valign"])
    set_prop(element, "color",      Element.get_color(props["color"]))
    try:
        ctlr = gst.Controller(element, "silent", "xpos", "ypos", "color")
    except RuntimeError:
        log.warn("Annotation: Your gstreamer-plugins-base library is too old to support dynamic annotation such as xpos2, ypos2, start, duration. Update your gstreamer library to enable this feature.")
        ctlr = None

        
    if props.has_key("xpos") or props.has_key("ypos"):
        supported_props = [x.name for x in gobject.list_properties(element)]
        if "xpos" not in supported_props:
            log.warn("Annotation: you selected xpos and ypos in your annimation, but your version of gstreamer-plugins-base does not support it.")
        else:
            set_prop(element, "xpos", float(props.get("xpos", 0.5)))
            set_prop(element, "ypos", float(props.get("ypos", 0.5)))
            set_prop(element, "halignment", "position")
            set_prop(element, "valignment", "position")
            
            def create_pos_controller(cont, prop, start, stop, dur):
                if not(cont): return
                cont.set_interpolation_mode(prop, gst.INTERPOLATE_LINEAR)
                cont.set(prop, 0,   start)
                cont.set(prop, dur, stop)

            if props.has_key("xpos2"):
                create_pos_controller(ctlr, "xpos", element.props.xpos, float(props["xpos2"]), duration)
            if props.has_key("ypos2"):
                create_pos_controller(ctlr, "ypos", element.props.ypos, float(props["ypos2"]), duration)

    set_prop(element, "vertical-render", int(props["vertical"]))
    set_prop(element, "font-desc",       font)
    set_prop(element, "auto-resize",     False)
    set_prop(element, "line-alignment",  props["justification"])

    if (props["duration"] or props["start"]) and ctlr:
        dur   = int(round(float(props["duration"]) * gst.SECOND))
        start = int(round(float(props["start"]) * gst.SECOND))
    
        ctlr.set_interpolation_mode("silent", gst.INTERPOLATE_NONE)
        
        if start > 0:
            ctlr.set("silent", 0,     1)
            ctlr.set("silent", start, 0)
        else:
            ctlr.set("silent", 0,     0)
        if dur > 0:
            ctlr.set("silent", start+dur,   1)

    # save off a reference to the controller so that it does not pop
    # off the the stack and dissapear.
    self.controllers.append(ctlr)
Ejemplo n.º 20
0
    def __init__(self, project, name, type, pixbuf, id=None):
        """
		Creates a new instance of Instrument.
		
		Parameters:
			project -- the currently active Project.
			name -- name of the Instrument.
			type -- type of the Instrument.
			pixbuf -- image of the Instrument resource object.
			id -- unique ID value for the Instrument.
		"""
        gobject.GObject.__init__(self)

        self.project = project

        self.events = []  # List of events attached to this instrument
        self.graveyard = [
        ]  # List of events that have been deleted (kept for undo)
        self.effects = []  # List of GStreamer effect elements

        self.name = name  # Name of this instrument
        self.pixbuf = pixbuf  # The icon pixbuf resource
        self.instrType = type  # The type of instrument

        self.isArmed = False  # True if the instrument is armed for recording
        self.isMuted = False  # True if the "mute" button is toggled on
        self.actuallyIsMuted = False  # True if the instrument is muted (silent)
        self.isSolo = False  # True if the instrument is solo'd (only instrument active)
        self.isVisible = True  # True if the instrument should be displayed in the mixer views
        self.isSelected = False  # True if the instrument is currently selected

        self.level = 0.0  # Current audio level in range 0..1
        self.volume = 1.0  # Gain of the current instrument in range 0..1
        self.pan = 0.0  # pan number (between -100 and 100)
        self.currentchainpreset = None  # current instrument wide chain preset
        self.output = ""
        self.recordingbin = None
        self.id = project.GenerateUniqueID(
            id)  #check is id is already being used before setting

        self.input = None  # the device to use for recording on this instrument.
        self.inTrack = 0  # Input track to record from if device is multichannel.

        # CREATE GSTREAMER ELEMENTS #
        self.playbackbin = gst.element_factory_make("bin",
                                                    "Instrument_%d" % self.id)
        self.volumeElement = gst.element_factory_make(
            "volume", "Instrument_Volume_%d" % self.id)
        self.levelElement = gst.element_factory_make(
            "level", "Instrument_Level_%d" % self.id)
        self.panElement = gst.element_factory_make(
            "audiopanorama", "Instrument_Pan_%d" % self.id)
        self.resample = gst.element_factory_make("audioresample")

        self.composition = gst.element_factory_make("gnlcomposition")
        self.silentGnlSource = gst.element_factory_make(
            "gnlsource"
        )  # the default source that makes the silence between the tracks
        self.silenceAudioSource = gst.element_factory_make("audiotestsrc")

        self.effectsBin = gst.element_factory_make(
            "bin", "InstrumentEffects_%d" % self.id)
        self.effectsBinConvert = gst.element_factory_make(
            "audioconvert", "Start_Effects_Converter_%d" % self.id)
        self.effectsBinCaps = gst.element_factory_make(
            "capsfilter", "Effects_float_caps_%d" % self.id)
        self.effectsBinCaps.set_property("caps",
                                         gst.Caps(self.LADSPA_ELEMENT_CAPS))
        self.effectsBinEndConvert = gst.element_factory_make(
            "audioconvert", "End_Effects_Converter_%d" % self.id)

        self.volumeFadeBin = gst.element_factory_make("bin",
                                                      "Volume_fades_bin")
        self.volumeFadeElement = gst.element_factory_make(
            "volume", "Volume_Fade_Element")
        self.volumeFadeStartConvert = gst.element_factory_make(
            "audioconvert", "Start_fadebin_converter")
        self.volumeFadeEndConvert = gst.element_factory_make(
            "audioconvert", "End_fadebin_converter")
        self.volumeFadeOperation = gst.element_factory_make(
            "gnloperation", "gnloperation")
        self.volumeFadeController = gst.Controller(self.volumeFadeElement,
                                                   "volume")

        # CREATE GHOSTPADS FOR BINS #
        self.effectsBin.add(self.effectsBinConvert, self.effectsBinCaps,
                            self.effectsBinEndConvert)
        self.effectsBinSink = gst.GhostPad(
            "sink", self.effectsBinConvert.get_pad("sink"))
        self.effectsBin.add_pad(self.effectsBinSink)
        self.effectsBinSrc = gst.GhostPad(
            "src", self.effectsBinEndConvert.get_pad("src"))
        self.effectsBin.add_pad(self.effectsBinSrc)

        self.volumeFadeBin.add(self.volumeFadeElement)
        self.volumeFadeBin.add(self.volumeFadeStartConvert)
        self.volumeFadeBin.add(self.volumeFadeEndConvert)
        volumeFadeBinSink = gst.GhostPad(
            "sink", self.volumeFadeStartConvert.get_pad("sink"))
        self.volumeFadeBin.add_pad(volumeFadeBinSink)
        volumeFadeBinSrc = gst.GhostPad(
            "src", self.volumeFadeEndConvert.get_pad("src"))
        self.volumeFadeBin.add_pad(volumeFadeBinSrc)

        # SET ELEMENT PROPERTIES #
        self.levelElement.set_property("interval", gst.SECOND / 50)
        self.levelElement.set_property("message", True)
        self.levelElement.set_property("peak-ttl", 0)
        self.levelElement.set_property("peak-falloff", 20)

        self.panElement.set_property("panorama", 0)

        self.silenceAudioSource.set_property("wave", 4)  #4 is silence

        self.silentGnlSource.set_property("priority", 2**32 - 1)
        self.silentGnlSource.set_property("start", 0)
        self.silentGnlSource.set_property("duration", 1000 * gst.SECOND)
        self.silentGnlSource.set_property("media-start", 0)
        self.silentGnlSource.set_property("media-duration", 1000 * gst.SECOND)

        self.volumeFadeOperation.set_property("start", long(0) * gst.SECOND)
        self.volumeFadeOperation.set_property("duration",
                                              long(20) * gst.SECOND)
        self.volumeFadeOperation.set_property("priority", 1)

        self.volumeFadeController.set_interpolation_mode(
            "volume", gst.INTERPOLATE_LINEAR)

        # ADD ELEMENTS TO THE PIPELINE AND/OR THEIR BINS #
        self.playbackbin.add(self.volumeElement, self.levelElement,
                             self.panElement, self.resample)
        self.playbackbin.add(self.composition)
        self.playbackbin.add(self.effectsBin)

        self.volumeFadeOperation.add(self.volumeFadeBin)
        self.silentGnlSource.add(self.silenceAudioSource)
        self.composition.add(self.silentGnlSource)
        self.composition.add(self.volumeFadeOperation)

        # LINK GSTREAMER ELEMENTS #
        self.effectsBinConvert.link(self.effectsBinCaps)
        self.effectsBinCaps.link(self.effectsBinEndConvert)

        self.effectsBin.link(self.volumeElement)
        self.volumeElement.link(self.levelElement)
        self.levelElement.link(self.panElement)
        self.panElement.link(self.resample)

        self.playghostpad = gst.GhostPad("src", self.resample.get_pad("src"))
        self.playbackbin.add_pad(self.playghostpad)

        self.volumeFadeStartConvert.link(self.volumeFadeElement)
        self.volumeFadeElement.link(self.volumeFadeEndConvert)

        self.AddAndLinkPlaybackbin()

        self.composition.connect("pad-added", self.__PadAddedCb)
        self.composition.connect("pad-removed", self.__PadRemovedCb)

        #mute this instrument if another one is solo
        self.OnMute()
        #set the volume element since it depends on the project's volume as well
        self.UpdateVolume()
Ejemplo n.º 21
0
    def __init__(self,
                 player,
                 source,
                 originator,
                 decodebin=False,
                 nodatabinunlinker=False):
        super(StreamBin, self).__init__()
        gst.Bin.__init__(self)

        self.__player = player
        self.__originator = originator
        self.__source = source

        self.linked = False
        self.is_nodatabinunlinker = nodatabinunlinker
        self.state = None

        self.__adder_sink = None
        self.src_blocked = False
        self.emitted_playing_message = False
        self.__decoder_linked = False
        self.__error = None
        self.__error_id = None

        self.loop_id = None

        if decodebin:
            self.__decodebin = gst.element_factory_make("decodebin", None)
            self.__decodebin.connect("new-decoded-pad",
                                     self.__new_decodebin_pad_cb)
        else:
            self.__decodebin = VorbisDecodeBin()

        # oggdemux ! vorbisdec
        # self.__oggdemux = gst.element_factory_make("oggdemux", None)
        # self.__oggdemux.connect("pad-added", self.demuxer_callback)
        # self.__sourcequeue = gst.element_factory_make("queue", None)
        # self.__vorbisdec = gst.element_factory_make("vorbisdec", None)

        self.__audioconvert = gst.element_factory_make("audioconvert", None)
        if nodatabinunlinker:
            self.__nodatabinunlinker = NoDataBinUnlinker(unlink=self,
                                                         tolerance=1)

        self.__audioresample = gst.element_factory_make("audioresample", None)
        self.__capsfilter = gst.element_factory_make("capsfilter", None)
        self.pos = Position(self.__player.stream)

        self.__volume = gst.element_factory_make("volume", None)
        self.__volume_control = gst.Controller(self.__volume, "volume")
        self.__volume_control.set_interpolation_mode("volume",
                                                     gst.INTERPOLATE_LINEAR)
        # self.__loudness = Loudness(volume = self.__volume)

        self.__preroll = gst.element_factory_make("queue", None)

        self.__capsfilter.set_property("caps", self.__player.caps)
        self.__preroll.set_property("min-threshold-buffers", 10)

        self.add(self.__source, self.__decodebin, self.__audioconvert,
                 self.__audioresample, self.__capsfilter, self.pos,
                 self.__volume, self.__preroll)
        if nodatabinunlinker:
            self.add(self.__nodatabinunlinker)
        # self.__source.link(self.__decodebin)
        # gst.element_link_many(self.__source, self.__sourcequeue, self.__oggdemux)
        if decodebin:
            gst.element_link_many(self.__source, self.__decodebin)
            if nodatabinunlinker:
                gst.element_link_many(self.__audioconvert,
                                      self.__audioresample, self.__capsfilter,
                                      self.__nodatabinunlinker, self.__preroll,
                                      self.pos, self.__volume)
            else:
                gst.element_link_many(self.__audioconvert,
                                      self.__audioresample, self.__capsfilter,
                                      self.__preroll, self.pos, self.__volume)
        else:
            if nodatabinunlinker:
                gst.element_link_many(self.__source, self.__decodebin,
                                      self.__audioconvert,
                                      self.__audioresample, self.__capsfilter,
                                      self.__nodatabinunlinker, self.__preroll,
                                      self.pos, self.__volume)
            else:
                gst.element_link_many(self.__source, self.__decodebin,
                                      self.__audioconvert,
                                      self.__audioresample, self.__capsfilter,
                                      self.__preroll, self.pos, self.__volume)

        preroll_src = self.__volume.get_pad("src")
        self.src = gst.GhostPad("src", preroll_src)
        self.add_pad(self.src)

        # Add a padprobe to the src to catch the OES and other events
        self.src.add_event_probe(self.__src_event_cb)

        # Share the bus with the player
        self.set_bus(self.__player.pipe.get_bus())
Ejemplo n.º 22
0
#!/usr/bin/python
import gobject
gobject.threads_init()
import pygst
pygst.require("0.10")
import gst

p = gst.parse_launch("""
   v4l2src !
   videoconvert ! queue ! video/x-raw,width=320,height=240,framerate=30/1 !  burn qos=true name=vf ! videoconvert !  timeoverlay ! xvimagesink
   """)

m = p.get_by_name("vf")
m.set_property("adjustment", 128)

control = gst.Controller(m, "adjustment")
control.set_interpolation_mode("adjustment", gst.INTERPOLATE_LINEAR)
control.set("adjustment", 0 * gst.SECOND, 128)
control.set("adjustment", 5 * gst.SECOND, 256)
control.set("adjustment", 25 * gst.SECOND, 0)

p.set_state(gst.STATE_PLAYING)

gobject.MainLoop().run()
Ejemplo n.º 23
0
    def __init__(self, filename="default.gst", config=dict()):
        conffile = None
        extension = ".gst"
        if filename.endswith(extension):
            conffile = filename[:-len(extension)] + ".ctl"
        self.eventhandlers = dict()
        self.restart = False
        self.config = config

        # (self.pipestring, ctrls) = _pipeParseCtrl(_pipeRead(filename, config))
        self.pipestring = _pipeRead(filename, config)
        ctrls = _ctrlRead(conffile)

        log.info("pipeline: %s" % (self.pipestring))
        log.info("ctrls: %s" % (ctrls))

        self.setEventHandlers(None)

        self.pipeline = gst.parse_launch(self.pipestring)
        self.bus = self.pipeline.get_bus()
        self.bus.add_watch(self._async_handler)

        self.previewOut = self.pipeline.get_by_name("preview")
        self.liveOut = self.pipeline.get_by_name("live")

        log.info("OUT: %s\t%s", self.previewOut, self.liveOut)

        # get all controllables
        control_dict = {}
        for lmn in self.pipeline.elements():
            for p in lmn.props:
                if False and p.flags & gst.PARAM_CONTROLLABLE:
                    if lmn.props.name not in control_dict:
                        control_dict[lmn.props.name] = []
                    control_dict[lmn.props.name] += [p.name]

        self.controller = {}
        self.setter = {}
        if ctrls:
            for ctl, elemprop in ctrls.items():
                # ctl = 'FOO'
                # elemprop = {'textoverlay_3': ['xpos'], 'textoverlay_1': ['ypos', 'xpos']}
                for elem, props in elemprop.items():
                    # elem = 'textoverlay_3'
                    # prop = ['xpos']
                    ctlprops = []
                    setprops = []
                    for p in props:
                        if (elem in control_dict) and (p
                                                       in control_dict[elem]):
                            ctlprops += [p]
                        else:
                            setprops += [p]
                    lmn = self.pipeline.get_by_name(elem)
                    log.info("element '%s' %s" % (elem, lmn))
                    # create a controller
                    if ctlprops:
                        tmpctl = gst.Controller(lmn, *ctlprops)
                        for cp in ctlprops:
                            tmpctl.set_interpolation_mode(
                                cp, gst.INTERPOLATE_LINEAR)
                            v = lmn.get_property(cp)
                            log.debug("%s: %s" % (ctl, v))
                            tmpctl.set(cp, 0, v)

                        if ctl not in self.controller:
                            self.controller[ctl] = []
                        self.controller[ctl] += [(tmpctl, ctlprops)]
                    # create setters
                    # (this is just a list so we remember)
                    if setprops:
                        if ctl not in self.setter:
                            self.setter[ctl] = {}
                        if lmn not in self.setter[ctl]:
                            self.setter[ctl][lmn] = []
                        self.setter[ctl][lmn] += setprops
Ejemplo n.º 24
0
#!/usr/bin/python
import gobject; gobject.threads_init()
import pygst; pygst.require("0.10")
import gst

p = gst.parse_launch ("""
   v4l2src !
   videoconvert ! queue ! video/x-raw,width=320,height=240,framerate=30/1 !  gaussianblur qos=true name=vf ! videoconvert !  timeoverlay ! xvimagesink
   """)

m = p.get_by_name ("vf")
m.set_property ("sigma", 0.5)

control = gst.Controller(m, "sigma")
control.set_interpolation_mode("sigma", gst.INTERPOLATE_LINEAR)
control.set("sigma", 0 * gst.SECOND, 0.5)
control.set("sigma", 5 * gst.SECOND, 10.0)
control.set("sigma", 25 * gst.SECOND, -5.0)

p.set_state (gst.STATE_PLAYING)

gobject.MainLoop().run()
Ejemplo n.º 25
0
def get_kenburns_bin(name, config, duration, start1):
    bin = gst.Bin()
    kb1 = gst.element_factory_make("kenburns")
    kb2 = gst.element_factory_make("kenburns")
    mixer = gst.element_factory_make(config["videomixer"])
    mixer.props.background = "transparent"
    caps = gst.element_factory_make("capsfilter")
    caps.props.caps = config.get_video_caps("AYUV")
    bin.add(kb1, kb2, mixer, caps)
    kb1.get_pad("src").link(mixer.get_pad("sink_0"))
    kb2.get_pad("src").link(mixer.get_pad("sink_1"))
    mixer.link(caps)
    bin.add_pad(gst.GhostPad("sink1", kb1.get_pad("sink")))
    bin.add_pad(gst.GhostPad("sink2", kb2.get_pad("sink")))
    bin.add_pad(gst.GhostPad("src", caps.get_pad("src")))

    if name.startswith("swap"):
        c1 = gst.Controller(kb1, "zpos", "xpos", "ypos")
        c1.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c1.set("zpos", start1, 1.0)
        c1.set("xpos", start1, 0.0)
        c1.set("ypos", start1, 0.0)
        c1.set("zpos", start1 + duration, 3.0)

        c2 = gst.Controller(kb2, "zpos", "xpos", "ypos")
        c2.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c2.set("zpos", 0, 3.0)
        c2.set("zpos", duration, 1.0)
        c2.set("xpos", duration, 0.0)
        c2.set("ypos", duration, 0.0)
        ctrls = [c1, c2]

        if name.endswith("random"):
            name = random.sample(["lr", "rl", "tb", "bt"], 1)[0]

        if name.endswith("rl"):
            c1.set("xpos", start1 + duration, -1.0)
            c2.set("xpos", 0, 1.2)
        elif name.endswith("lr"):
            c1.set("xpos", start1 + duration, 1.0)
            c2.set("xpos", 0, -1.2)
        elif name.endswith("tb"):
            c1.set("ypos", start1 + duration, -1.0)
            c2.set("ypos", 0, 1.2)
        elif name.endswith("bt"):
            c1.set("ypos", start1 + duration, 1.0)
            c2.set("ypos", 0, -1.2)

    elif name.startswith("border-train"):
        c1 = gst.Controller(kb1, "zpos", "xpos", "ypos")
        c1.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c2 = gst.Controller(kb2, "zpos", "xpos", "ypos")
        c2.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        ctrls = [c1, c2]

        c1.set("zpos", start1 + 0, 1.0)
        c1.set("zpos", start1 + duration / 4, 1.3)
        c1.set("xpos", start1 + 0, 0.0)
        c1.set("xpos", start1 + duration / 4, 0.0)
        c1.set("ypos", start1 + 0, 0.0)
        c1.set("ypos", start1 + duration / 4, 0.0)

        c2.set("zpos", 0, 1.3)
        c2.set("zpos", duration / 4, 1.3)
        c2.set("zpos", duration * 3 / 4, 1.3)
        c2.set("zpos", duration, 1.0)
        c2.set("xpos", duration * 3 / 4, 0.0)
        c2.set("xpos", duration, 0.0)
        c2.set("ypos", duration * 3 / 4, 0.0)
        c2.set("ypos", duration, 0.0)

        if name.endswith("random"):
            name = random.sample(["lr", "rl", "tb", "bt"], 1)[0]
        if name.endswith("lr"):
            c1.set("xpos", start1 + duration * 3 / 4, 2.5)
            c2.set("xpos", 0, -2.5)
            c2.set("xpos", duration / 4, -2.5)
        elif name.endswith("rl"):
            c1.set("xpos", start1 + duration * 3 / 4, -2.5)
            c2.set("xpos", 0, 2.5)
            c2.set("xpos", duration / 4, 2.5)
        elif name.endswith("tb"):
            c1.set("ypos", start1 + duration * 3 / 4, -2.5)
            c2.set("ypos", 0, 2.5)
            c2.set("ypos", duration / 4, 2.5)
        elif name.endswith("bt"):
            c1.set("ypos", start1 + duration * 3 / 4, 2.5)
            c2.set("ypos", 0, -2.5)
            c2.set("ypos", duration / 4, -2.5)

    elif name.startswith("train"):
        c1 = gst.Controller(kb1, "xpos", "ypos")
        c1.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c2 = gst.Controller(kb2, "xpos", "ypos")
        c2.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        ctrls = [c1, c2]

        c1.set("xpos", start1 + 0, 0.0)
        c1.set("ypos", start1 + 0, 0.0)
        c2.set("xpos", duration, 0.0)
        c2.set("ypos", duration, 0.0)

        if name.endswith("random"):
            name = random.sample(["lr", "rl", "tb", "bt"], 1)[0]
        if name.endswith("lr"):
            c1.set("xpos", start1 + duration, 2.0)
            c2.set("xpos", 0, -2.0)
        elif name.endswith("rl"):
            c1.set("xpos", start1 + duration, -2.0)
            c2.set("xpos", 0, 2.0)
        elif name.endswith("tb"):
            c1.set("ypos", start1 + duration, -2.0)
            c2.set("ypos", 0, 2.0)
        elif name.endswith("bt"):
            c1.set("ypos", start1 + duration, 2.0)
            c2.set("ypos", 0, -2.0)

    elif name.startswith("reel"):
        c1 = gst.Controller(kb1, "zpos", "xpos", "ypos", "yrot", "xrot")
        c1.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("xrot", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("yrot", gst.INTERPOLATE_LINEAR)
        c2 = gst.Controller(kb2, "zpos", "xpos", "ypos", "yrot", "xrot")
        c2.set_interpolation_mode("zpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("xpos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("ypos", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("xrot", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("yrot", gst.INTERPOLATE_LINEAR)
        ctrls = [c1, c2]

        c1.set("zpos", start1 + 0, 1.0)
        c1.set("zpos", start1 + duration / 4, 1.3)
        c1.set("xpos", start1 + 0, 0.0)
        c1.set("xpos", start1 + duration / 4, 0.0)
        c1.set("xrot", start1 + 0, 0.0)
        c1.set("xrot", start1 + duration / 4, 0.0)
        c1.set("ypos", start1 + 0, 0.0)
        c1.set("ypos", start1 + duration / 4, 0.0)
        c1.set("yrot", start1 + 0, 0.0)
        c1.set("yrot", start1 + duration / 4, 0.0)

        c2.set("zpos", 0, 1.3)
        c2.set("zpos", duration / 4, 1.3)
        c2.set("zpos", duration * 3 / 4, 1.3)
        c2.set("zpos", duration, 1.0)
        c2.set("xpos", duration * 3 / 4, 0.0)
        c2.set("xpos", duration, 0.0)
        c2.set("ypos", duration * 3 / 4, 0.0)
        c2.set("ypos", duration, 0.0)
        c2.set("xrot", duration * 3 / 4, 0.0)
        c2.set("xrot", duration, 0.0)
        c2.set("yrot", duration * 3 / 4, 0.0)
        c2.set("yrot", duration, 0.0)

        if name.endswith("random"):
            name = random.sample(["lr", "rl", "tb", "bt"], 1)[0]
        if name.endswith("lr"):
            c1.set("xpos", start1 + duration * 3 / 4, 2.5)
            c1.set("xrot", start1 + duration * 3 / 4, -85)
            c1.set("zpos", start1 + duration * 3 / 4, 1.3)
            c1.set("zpos", start1 + duration * 3 / 4, 2.5)
            c2.set("xpos", 0, -2.5)
            c2.set("xpos", duration / 4, -2.5)
            c2.set("xrot", duration / 4, 90)
            c2.set("xrot", 0, 90)
            c2.set("zpos", 0, 2.5)
            c2.set("zpos", duration / 4, 2.5)
        elif name.endswith("rl"):
            c1.set("xpos", start1 + duration * 3 / 4, -2.5)
            c1.set("xrot", start1 + duration * 3 / 4, 85)
            c1.set("zpos", start1 + duration * 3 / 4, 1.3)
            c1.set("zpos", start1 + duration * 3 / 4, 2.5)
            c2.set("xpos", 0, 2.5)
            c2.set("xpos", duration / 4, 2.5)
            c2.set("xrot", duration / 4, -90)
            c2.set("xrot", 0, -90)
            c2.set("zpos", 0, 2.5)
            c2.set("zpos", duration / 4, 2.5)
        elif name.endswith("tb"):
            c1.set("ypos", start1 + duration * 3 / 4, -2.5)
            c1.set("yrot", start1 + duration * 3 / 4, -85)
            c1.set("zpos", start1 + duration * 3 / 4, 1.3)
            c1.set("zpos", start1 + duration * 3 / 4, 2.5)
            c2.set("ypos", 0, 2.5)
            c2.set("ypos", duration / 4, 2.5)
            c2.set("yrot", duration / 4, 90)
            c2.set("yrot", 0, 90)
            c2.set("zpos", 0, 2.5)
            c2.set("zpos", duration / 4, 2.5)
        elif name.endswith("bt"):
            c1.set("ypos", start1 + duration * 3 / 4, 2.5)
            c1.set("yrot", start1 + duration * 3 / 4, 85)
            c1.set("zpos", start1 + duration * 3 / 4, 1.3)
            c1.set("zpos", start1 + duration * 3 / 4, 2.5)
            c2.set("ypos", 0, -2.5)
            c2.set("ypos", duration / 4, -2.5)
            c2.set("yrot", duration / 4, -90)
            c2.set("yrot", 0, -90)
            c2.set("zpos", 0, 2.5)
            c2.set("zpos", duration / 4, 2.5)

    elif name.startswith("turn-over"):
        c1 = gst.Controller(kb1, "yrot", "xrot")
        c1.set_interpolation_mode("xrot", gst.INTERPOLATE_LINEAR)
        c1.set_interpolation_mode("yrot", gst.INTERPOLATE_LINEAR)
        c2 = gst.Controller(kb2, "yrot", "xrot")
        c2.set_interpolation_mode("xrot", gst.INTERPOLATE_LINEAR)
        c2.set_interpolation_mode("yrot", gst.INTERPOLATE_LINEAR)
        ctrls = [c1, c2]

        c1.set("xrot", start1 + 0, 0)
        c1.set("yrot", start1 + 0, 0)
        c2.set("xrot", duration, 0)
        c2.set("yrot", duration, 0)

        if name.endswith("random"):
            name = random.sample(["lr", "rl", "tb", "bt"], 1)[0]
        if name.endswith("lr"):
            c1.set("xrot", start1 + duration / 2, 90)
            c2.set("xrot", 0, -90)
            c2.set("xrot", duration / 2, -90)
        elif name.endswith("rl"):
            c1.set("xrot", start1 + duration / 2, -90)
            c2.set("xrot", 0, 90)
            c2.set("xrot", duration / 2, 90)
        elif name.endswith("tb"):
            c1.set("yrot", start1 + duration / 2, 90)
            c2.set("yrot", 0, -90)
            c2.set("yrot", duration / 2, -90)
        elif name.endswith("bt"):
            c1.set("yrot", start1 + duration / 2, -90)
            c2.set("yrot", 0, 90)
            c2.set("yrot", duration / 2, 90)

    return bin, ctrls