[pitivi/ges: 48/287] Cleaning up the codebase
- From: Jean-FranÃois Fortin Tam <jfft src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pitivi/ges: 48/287] Cleaning up the codebase
- Date: Thu, 15 Mar 2012 16:29:52 +0000 (UTC)
commit f2cc15b0127b898a441696f4ac269a1b61052ea6
Author: Mathieu Duponchelle <seeed laposte net>
Date: Mon Oct 3 21:16:02 2011 -0300
Cleaning up the codebase
configure.ac | 3 -
pitivi/Makefile.am | 8 -
pitivi/action.py | 751 -----------------
pitivi/actioner.py | 269 ------
pitivi/elements/.gitignore | 3 -
pitivi/elements/Makefile.am | 13 -
pitivi/elements/__init__.py | 3 -
pitivi/elements/arraysink.py | 77 --
pitivi/elements/extractionsink.py | 94 ---
pitivi/elements/mixer.py | 344 --------
pitivi/elements/singledecodebin.py | 421 ----------
pitivi/elements/thumbnailsink.py | 101 ---
pitivi/elements/videofade.py | 101 ---
pitivi/encode.py | 168 ----
pitivi/factories/Makefile.am | 12 -
pitivi/factories/base.py | 521 ------------
pitivi/factories/file.py | 82 --
pitivi/factories/operation.py | 44 -
pitivi/factories/test.py | 120 ---
pitivi/factories/timeline.py | 185 -----
pitivi/formatters/Makefile.am | 11 -
pitivi/formatters/__init__.py | 24 -
pitivi/formatters/base.py | 421 ----------
pitivi/formatters/etree.py | 892 --------------------
pitivi/formatters/format.py | 82 --
pitivi/formatters/playlist.py | 97 ---
pitivi/pipeline.py | 954 ---------------------
pitivi/plumber.py | 179 ----
pitivi/project.py | 4 -
pitivi/projectmanager.py | 5 +-
pitivi/settings.py | 83 --
pitivi/stream.py | 584 -------------
pitivi/timeline/Makefile.am | 6 +-
pitivi/timeline/align.py | 2 -
pitivi/timeline/gap.py | 148 ----
pitivi/timeline/timeline.py | 1599 +-----------------------------------
pitivi/timeline/timeline_undo.py | 3 +-
pitivi/timeline/track.py | 1366 ------------------------------
pitivi/ui/clipproperties.py | 4 +-
pitivi/ui/mainwindow.py | 3 -
pitivi/ui/previewer.py | 5 -
pitivi/ui/sourcelist.py | 2 -
pitivi/ui/timeline.py | 8 +-
pitivi/ui/timelinecontrols.py | 1 -
pitivi/ui/track.py | 1 -
pitivi/ui/trackobject.py | 4 -
pitivi/ui/viewer.py | 7 +-
47 files changed, 13 insertions(+), 9802 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 45f50d7..7f206c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,10 +86,7 @@ help/Makefile
pitivi/Makefile
pitivi/configure.py
pitivi/ui/Makefile
-pitivi/elements/Makefile
-pitivi/factories/Makefile
pitivi/log/Makefile
-pitivi/formatters/Makefile
pitivi/timeline/Makefile
pitivi.spec
po/Makefile.in
diff --git a/pitivi/Makefile.am b/pitivi/Makefile.am
index 48d7d84..2cbe4f5 100644
--- a/pitivi/Makefile.am
+++ b/pitivi/Makefile.am
@@ -1,8 +1,5 @@
SUBDIRS = \
ui \
- elements \
- factories \
- formatters \
timeline \
log
@@ -10,17 +7,13 @@ pitividir = $(libdir)/pitivi/python/pitivi
pitivi_PYTHON = \
__init__.py \
- action.py \
- actioner.py \
application.py \
check.py \
configure.py \
effects.py \
encode.py \
instance.py \
- pipeline.py \
pitivigstutils.py \
- plumber.py \
project.py \
projectmanager.py \
receiver.py \
@@ -30,7 +23,6 @@ pitivi_PYTHON = \
signalinterface.py \
sourcelist.py \
sourcelist_undo.py \
- stream.py \
threads.py \
thumbnailcache.py \
undo.py \
diff --git a/pitivi/encode.py b/pitivi/encode.py
index b7a07b5..b36ca0f 100644
--- a/pitivi/encode.py
+++ b/pitivi/encode.py
@@ -23,176 +23,8 @@
Encoding-related utilities and classes
"""
-import gobject
import gst
import pitivi.log.log as log
-from pitivi.factories.base import OperationFactory
-from pitivi.factories.operation import TransformFactory, get_modifier_for_stream
-
-
-class EncoderFactory(TransformFactory):
- """
- Creates one-to-one encoding bins based on provided L{StreamEncodeSettings}.
-
- @cvar settings: The encoding settings.
- @type settings: L{StreamEncodeSettings}
- """
- def __init__(self, settings, *args, **kwargs):
- self.settings = settings
- TransformFactory.__init__(self, *args, **kwargs)
- if self.settings.input_stream:
- self.addInputStream(self.settings.input_stream)
- if self.settings.output_stream:
- self.addOutputStream(self.settings.output_stream)
-
- def _makeBin(self, *args):
- s = self.settings
- b = gst.Bin()
-
- # encoder
- enc = gst.element_factory_make(s.encoder)
- for k, v in s.encodersettings.iteritems():
- self.debug("Setting property %r value %r", k, v)
- enc.set_property(k, v)
- b.add(enc)
-
- # optional input stream
- if s.input_stream and s.modifyinput:
- filt = get_modifier_for_stream(output_stream=s.input_stream)
- mod = filt.makeBin()
- b.add(mod)
- mod.link(enc)
- gsink = gst.GhostPad("sink", mod.get_pad("sink"))
- else:
- gsink = gst.GhostPad("sink", enc.get_pad("sink"))
- gsink.set_active(True)
- b.add_pad(gsink)
-
- # optional output stream
- if s.output_stream and s.modifyoutput:
- outfilt = gst.element_factory_make("capsfilter")
- outfilt.props.caps = s.output_stream.caps
- b.add(outfilt)
- enc.link(outfilt)
- gsrc = gst.GhostPad("src", outfilt.get_pad("src"))
- else:
- gsrc = gst.GhostPad("src", enc.get_pad("src"))
- gsrc.set_active(True)
- b.add_pad(gsrc)
-
- return b
-
- def _releaseBin(self, bin):
- for b in bin.elements():
- if isinstance(b, gst.Bin):
- b.factory.releaseBin(b)
-
-
-class RenderFactory(OperationFactory):
- """
- Handles factories that consume streams and output one (and only one
- output stream according to the given encoding settings.
-
- @cvar settings: The rendering settings
- @type settings: L{RenderSettings}
- """
-
- def __init__(self, settings, *args, **kwargs):
- self.settings = settings
- OperationFactory.__init__(self, *args, **kwargs)
- # add input streams according to the settings
- for i in range(len(settings.settings)):
- self.debug("Adding stream %d %r", i, settings.settings[i].input_stream)
- self.addInputStream(settings.settings[i].input_stream)
-
- def _makeBin(self, *args):
- s = self.settings
-
- b = gst.Bin()
-
- self.debug("Creating muxer")
- mux = gst.element_factory_make(s.muxer)
- for k, v in s.muxersettings.iteritems():
- mux.set_property(k, v)
-
- b.add(mux)
-
- self.debug("Ghosting source pad")
- gsrc = gst.GhostPad("src", mux.get_pad("src"))
- gsrc.set_active(True)
- b.add_pad(gsrc)
-
- i = 0
- # add all the encoders
- for setting in s.settings:
- self.debug("Creating encoder %d", i)
- b2 = EncoderFactory(setting).makeBin()
- b.add(b2)
-
- src2 = b2.get_pad("src")
-
- # request a compatible pad from the muxer
- n2 = get_compatible_sink_pad(s.muxer, src2.get_caps())
- if n2 == None:
- raise Exception("can't find a compatible pad")
- # FIXME : We're assuming it's a request pad
- p2 = mux.get_request_pad(n2)
-
- if gst.version() < (0, 10, 22, 1):
- segment_eater = NewsegmentEater()
- b.add(segment_eater)
- segment_eater.get_pad('src').link(p2)
- p2 = segment_eater.get_pad('sink')
-
- src2.link(p2)
-
- # expose encoder sink pad
- gsink = gst.GhostPad("sink_%d" % i,
- b2.get_pad("sink"))
- gsink.set_active(True)
- b.add_pad(gsink)
- i += 1
-
- self.debug("Done")
- return b
-
- def _releaseBin(self, bin):
- for b in bin.elements():
- if isinstance(b, gst.Bin):
- b.factory.releaseBin(b)
-
- def _requestNewInputStream(self, bin, input_stream):
- raise NotImplementedError
-
-
-class NewsegmentEater(gst.BaseTransform):
- __gstdetails__ = (
- "Description",
- "Klass",
- "Description",
- "Author")
-
- sink_template = gst.PadTemplate("sink",
- gst.PAD_SINK, gst.PAD_ALWAYS,
- gst.Caps('ANY'))
- src_template = gst.PadTemplate("src",
- gst.PAD_SRC, gst.PAD_ALWAYS,
- gst.Caps('ANY'))
-
- __gsttemplates__ = (sink_template, src_template)
-
- def __init__(self):
- gst.BaseTransform.__init__(self)
-
- def do_event(self, event):
- res = gst.BaseTransform.do_event(self, event)
- if event.type == gst.EVENT_NEWSEGMENT:
- # don't forward the event downstream
- return False
-
- return res
-
-gobject.type_register(NewsegmentEater)
def get_compatible_sink_pad(factoryname, caps):
diff --git a/pitivi/factories/base.py b/pitivi/factories/base.py
index 26e72b2..57cc0b3 100644
--- a/pitivi/factories/base.py
+++ b/pitivi/factories/base.py
@@ -25,10 +25,7 @@ from urllib import unquote
import gst
from pitivi.log.loggable import Loggable
-from pitivi.elements.singledecodebin import SingleDecodeBin
from pitivi.signalinterface import Signallable
-from pitivi.stream import match_stream_groups, AudioStream, VideoStream, \
- STREAM_MATCH_COMPATIBLE_CAPS
from pitivi.utils import formatPercent
# FIXME: define a proper hierarchy
@@ -199,457 +196,6 @@ class ObjectFactory(Signallable, Loggable):
return {}
-class SourceFactory(ObjectFactory):
- """
- Base class for factories that produce output and have no input.
-
- @ivar max_bins: Max number of bins the factory can create.
- @type max_bins: C{int}
- @ivar current_bins: Number of bin instances created and not released.
- @type current_bins: C{int}
- """
-
- __signals__ = {
- 'bin-created': ['bin'],
- 'bin-released': ['bin']
- }
-
- ffscale_factory = 'ffvideoscale'
-
- # make this an attribute to inject it from tests
- singleDecodeBinClass = SingleDecodeBin
-
- def __init__(self, uri, name=''):
- name = name or os.path.basename(unquote(uri))
- ObjectFactory.__init__(self, name)
- self.uri = uri
- self.max_bins = -1
- self.current_bins = 0
- self._filtercaps = gst.Caps("video/x-raw-rgb;video/x-raw-yuv")
-
- def getInterpolatedProperties(self, stream):
- self.debug("stream:%r", stream)
- props = ObjectFactory.getInterpolatedProperties(self, stream)
- if isinstance(stream, AudioStream):
- props.update({"volume": (0.0, 2.0, formatPercent)})
- elif isinstance(stream, VideoStream):
- props.update({"alpha": (0.0, 1.0, formatPercent)})
- self.debug("returning %r", props)
- return props
-
- def makeBin(self, output_stream=None):
- """
- Create a bin that outputs the stream described by C{output_stream}.
-
- If C{output_stream} is None, it's up to the implementations to return a
- suitable "default" bin.
-
- @param output_stream: A L{MultimediaStream}
- @return: The bin.
- @rtype: C{gst.Bin}
-
- @see: L{releaseBin}
- """
-
- compatible_stream = None
- self.debug("stream %r", output_stream)
-
- if output_stream is not None:
- self.debug("output_streams:%r", self.output_streams)
-
- # get the best stream from self.output_streams that matches
- # output_stream
- stream_map_rank = match_stream_groups([output_stream],
- self.output_streams)
- stream_map = dict(stream_map_rank.keys())
- if output_stream not in stream_map:
- self.warning("stream not available in map %r", stream_map)
- raise ObjectFactoryError("can not create stream")
-
- compatible_stream = stream_map[output_stream]
- rank = stream_map_rank[output_stream, compatible_stream]
- if rank < STREAM_MATCH_COMPATIBLE_CAPS:
- raise ObjectFactoryError("can not create stream")
-
- if self.max_bins != -1 and self.current_bins == self.max_bins:
- raise ObjectFactoryError('no bins available')
-
- bin = self._makeBin(compatible_stream)
- bin.factory = self
- self.bins.append(bin)
- self.current_bins += 1
- self.emit('bin-created', bin)
-
- return bin
-
- def releaseBin(self, bin):
- """
- Release a bin created with L{makeBin}.
-
- Some factories can create a limited number of bins or implement caching.
- You should call C{releaseBin} once you are done using a bin.
- """
- bin.set_state(gst.STATE_NULL)
- self._releaseBin(bin)
- self.debug("Finally releasing %r", bin)
- self.current_bins -= 1
- self.bins.remove(bin)
- self.emit('bin-released', bin)
- del bin.factory
-
- def _makeBin(self, output_stream):
- if output_stream is None:
- return self._makeDefaultBin()
-
- return self._makeStreamBin(output_stream)
-
- def _makeDefaultBin(self):
- """
- Return a bin that decodes all the available streams.
-
- This is generally used to get an overview of the source media before
- splitting it in separate streams.
- """
- bin = gst.Bin("%s" % self.name)
- src = gst.element_make_from_uri(gst.URI_SRC, self.uri)
- try:
- dbin = gst.element_factory_make("decodebin2")
- except:
- dbin = gst.element_factory_make("decodebin")
- bin.add(src, dbin)
- src.link_pads_full("src", dbin, "sink", gst.PAD_LINK_CHECK_NOTHING)
-
- dbin.connect("new-decoded-pad", self._binNewDecodedPadCb, bin)
- dbin.connect("removed-decoded-pad", self._binRemovedDecodedPadCb, bin)
-
- bin.decodebin = dbin
- return bin
-
- def _binNewDecodedPadCb(self, unused_dbin, pad, unused_is_last, bin):
- ghost_pad = gst.GhostPad(pad.get_name(), pad)
- ghost_pad.set_active(True)
- bin.add_pad(ghost_pad)
-
- def _binRemovedDecodedPadCb(self, unused_dbin, pad, bin):
- ghost_pad = bin.get_pad(pad.get_name())
- bin.remove_pad(ghost_pad)
-
- def _releaseBin(self, bin):
- if hasattr(bin, "decodebin"):
- try:
- # bin is a bin returned from makeDefaultBin
- bin.decodebin.disconnect_by_func(self._binNewDecodedPadCb)
- bin.decodebin.disconnect_by_func(self._binRemovedDecodedPadCb)
- except TypeError:
- # bin is a stream bin
- bin.decodebin.disconnect_by_func(self._singlePadAddedCb)
- bin.decodebin.disconnect_by_func(self._singlePadRemovedCb)
- del bin.decodebin
-
- if hasattr(bin, "child"):
- bin.child.set_state(gst.STATE_NULL)
- del bin.child
-
- if hasattr(bin, "volume"):
- # only audio bins have a volume element
- for elt in [bin.aconv, bin.ares, bin.arate, bin.volume]:
- elt.set_state(gst.STATE_NULL)
- bin.remove(elt)
- del bin.volume
- del bin.aconv
- del bin.ares
- del bin.arate
- elif hasattr(bin, "alpha"):
- for elt in [bin.csp, bin.queue, bin.alpha, bin.capsfilter, bin.scale]:
- elt.set_state(gst.STATE_NULL)
- bin.remove(elt)
- del bin.queue
- del bin.csp
- del bin.alpha
- del bin.capsfilter
- del bin.scale
-
- if hasattr(bin, "ghostpad"):
- # singledecodebin found something on this pad
- bin.ghostpad.set_active(False)
- bin.remove_pad(bin.ghostpad)
- del bin.ghostpad
-
- def _makeStreamBinReal(self, output_stream):
- b = gst.Bin()
- b.decodebin = self.singleDecodeBinClass(uri=self.uri, caps=output_stream.caps,
- stream=output_stream)
- b.decodebin.connect("pad-added", self._singlePadAddedCb, b)
- b.decodebin.connect("pad-removed", self._singlePadRemovedCb, b)
- return b
-
- def _makeStreamBin(self, output_stream, child_bin=None):
- self.debug("output_stream:%r", output_stream)
- b = self._makeStreamBinReal(output_stream)
-
- if isinstance(output_stream, AudioStream):
- self._addCommonAudioElements(b, output_stream)
- elif isinstance(output_stream, VideoStream):
- self._addCommonVideoElements(b, output_stream, child_bin)
-
- if hasattr(b, "decodebin"):
- b.add(b.decodebin)
- return b
-
- def _singlePadAddedCb(self, dbin, pad, topbin):
- self.debug("dbin:%r, pad:%r, topbin:%r", dbin, pad, topbin)
- if hasattr(topbin, "child"):
- topbin.child.sync_state_with_parent()
- if hasattr(topbin, "volume"):
- # make sure audio elements reach our same state. This is needed
- # since those elements are still unlinked downstream at this point,
- # so state change order doesn't happen in the usual
- # downstream-to-upstream way.
- for element in [topbin.aconv, topbin.ares, topbin.arate, topbin.volume]:
- element.sync_state_with_parent()
-
- pad.link_full(topbin.aconv.get_pad("sink"), gst.PAD_LINK_CHECK_NOTHING)
- topbin.ghostpad = gst.GhostPad("src", topbin.volume.get_pad("src"))
- elif hasattr(topbin, "alpha"):
- for element in [topbin.queue, topbin.scale, topbin.csp, topbin.alpha, topbin.capsfilter]:
- element.sync_state_with_parent()
-
- pad.link_full(topbin.queue.get_pad("sink"), gst.PAD_LINK_CHECK_NOTHING)
- topbin.ghostpad = gst.GhostPad("src", topbin.capsfilter.get_pad("src"))
- else:
- topbin.ghostpad = gst.GhostPad("src", pad)
-
- if pad.props.caps is not None:
- topbin.ghostpad.set_caps(pad.props.caps)
- topbin.ghostpad.set_active(True)
- topbin.add_pad(topbin.ghostpad)
-
- def _singlePadRemovedCb(self, dbin, pad, topbin):
- self.debug("dbin:%r, pad:%r, topbin:%r", dbin, pad, topbin)
-
- # work around for http://bugzilla.gnome.org/show_bug.cgi?id=590735
- if hasattr(topbin, "ghostpad"):
- die = gst.Pad("die", gst.PAD_SRC)
- topbin.ghostpad.set_target(die)
-
- topbin.remove_pad(topbin.ghostpad)
- del topbin.ghostpad
-
- if hasattr(topbin, "volume"):
- pad.unlink(topbin.aconv.get_pad("sink"))
- elif hasattr(topbin, "alpha"):
- pad.unlink(topbin.queue.get_pad("sink"))
-
- def addInputStream(self, stream):
- raise AssertionError("source factories can't have input streams")
-
- def setFilterCaps(self, caps, b=None):
- caps_copy = gst.Caps(caps)
- for structure in caps_copy:
- # remove framerate as we don't adjust framerate here
- if structure.has_field("framerate"):
- del structure["framerate"]
- # remove format as we will have converted to AYUV/ARGB
- if structure.has_field("format"):
- del structure["format"]
- if b is None:
- for bin in self.bins:
- if hasattr(bin, "capsfilter"):
- bin.capsfilter.props.caps = caps_copy
- else:
- b.capsfilter.props.caps = caps_copy
- self._filtercaps = caps_copy
-
- def _addCommonVideoElements(self, video_bin, output_stream, child_bin=None):
- if child_bin:
- video_bin.child = child_bin
- video_bin.add(child_bin)
-
- video_bin.queue = gst.element_factory_make("queue", "internal-queue")
- video_bin.queue.props.max_size_bytes = 0
- video_bin.queue.props.max_size_time = 0
- video_bin.queue.props.max_size_buffers = 3
-
- # all video needs to be AYUV, but the colorspace conversion
- # element depends on the input. if there is no alpha we need to
- # add ffmpegcolorspace. if we have an argb or rgba stream, we need
- # alphacolor to preserve the alpha channel (ffmpeg clobbers it).
- # if we have an ayuv stream we don't want any colorspace
- # converter.
-
- if not output_stream.has_alpha():
- video_bin.csp = gst.element_factory_make("ffmpegcolorspace",
- "internal-colorspace")
- elif output_stream.videotype == 'video/x-raw-rgb':
- video_bin.csp = gst.element_factory_make("alphacolor",
- "internal-alphacolor")
- else:
- video_bin.csp = gst.element_factory_make("identity")
-
- video_bin.alpha = gst.element_factory_make("alpha", "internal-alpha")
-
- try:
- video_bin.alpha.props.prefer_passthrough = True
- except AttributeError:
- self.warning("User has old version of alpha. "
- "prefer-passthrough not enabled")
-
- video_bin.scale = gst.element_factory_make("videoscale")
- try:
- video_bin.scale.props.add_borders = True
- except AttributeError:
- self.warning("User has old version of videoscale. "
- "add-border not enabled")
- video_bin.capsfilter = gst.element_factory_make("capsfilter",
- "capsfilter-proj-settings")
- self.setFilterCaps(self._filtercaps, video_bin)
-
- video_bin.add(video_bin.queue, video_bin.scale, video_bin.csp,
- video_bin.alpha, video_bin.capsfilter)
- video_bin.queue.link_pads_full("src", video_bin.csp, "sink", gst.PAD_LINK_CHECK_NOTHING)
- video_bin.csp.link_pads_full("src", video_bin.scale, "sink", gst.PAD_LINK_CHECK_NOTHING)
- if child_bin is not None:
- gst.element_link_many(video_bin.scale, video_bin.child,
- video_bin.alpha)
- video_bin.alpha.link_pads_full("src", video_bin.capsfilter, "sink", gst.PAD_LINK_CHECK_NOTHING)
- video_bin.child.sync_state_with_parent()
- else:
- video_bin.scale.link_pads_full("src", video_bin.alpha, "sink", gst.PAD_LINK_CHECK_NOTHING)
- video_bin.alpha.link_pads_full("src", video_bin.capsfilter, "sink", gst.PAD_LINK_CHECK_NOTHING)
-
- video_bin.capsfilter.sync_state_with_parent()
- video_bin.scale.sync_state_with_parent()
- video_bin.queue.sync_state_with_parent()
- video_bin.csp.sync_state_with_parent()
- video_bin.alpha.sync_state_with_parent()
-
- def _addCommonAudioElements(self, audio_bin, output_stream):
- self.debug("Adding volume element")
- # add a volume element
- audio_bin.aconv = gst.element_factory_make("audioconvert", "internal-aconv")
- audio_bin.ares = gst.element_factory_make("audioresample", "internal-audioresample")
- # Fix audio jitter of up to 40ms
- audio_bin.arate = gst.element_factory_make("audiorate", "internal-audiorate")
- audio_bin.arate.props.tolerance = 40 * gst.MSECOND
- audio_bin.volume = gst.element_factory_make("volume", "internal-volume")
- audio_bin.add(audio_bin.volume, audio_bin.ares, audio_bin.aconv, audio_bin.arate)
- #if child_bin:
- # gst.element_link_many(audio_bin.aconv, audio_bin.ares, audio_bin.arate, audio_bin.child, audio_bin.volume)
- # audio_bin.child.sync_state_with_parent()
- #else:
- audio_bin.aconv.link_pads_full("src", audio_bin.ares, "sink", gst.PAD_LINK_CHECK_NOTHING)
- audio_bin.ares.link_pads_full("src", audio_bin.arate, "sink", gst.PAD_LINK_CHECK_NOTHING)
- audio_bin.arate.link_pads_full("src", audio_bin.volume, "sink", gst.PAD_LINK_CHECK_NOTHING)
-
- audio_bin.aconv.sync_state_with_parent()
- audio_bin.ares.sync_state_with_parent()
- audio_bin.arate.sync_state_with_parent()
- audio_bin.volume.sync_state_with_parent()
-
-
-class SinkFactory(ObjectFactory):
- """
- Base class for factories that consume input and have no output.
-
- @ivar max_bins: Max number of bins the factory can create.
- @type max_bins: C{int}
- @ivar current_bins: Number of bin instances created and not released.
- @type current_bins: C{int}
- """
-
- __signals__ = {
- 'bin-created': ['bin'],
- 'bin-released': ['bin']
- }
-
- def __init__(self, name=''):
- ObjectFactory.__init__(self, name)
- self.max_bins = -1
- self.current_bins = 0
-
- def makeBin(self, input_stream=None):
- """
- Create a bin that consumes the stream described by C{input_stream}.
-
- If C{input_stream} is None, it's up to the implementations to return a
- suitable "default" bin.
-
- @param input_stream: A L{MultimediaStream}
- @return: The bin.
- @rtype: C{gst.Bin}
-
- @see: L{releaseBin}
- """
-
- self.debug("stream %r", input_stream)
- compatible_stream = None
- if input_stream is not None:
- self.debug("Streams %r", self.input_streams)
- for stream in self.input_streams:
- if input_stream.isCompatible(stream):
- compatible_stream = stream
- break
-
- if compatible_stream is None:
- raise ObjectFactoryError('unknown stream')
-
- if self.max_bins != -1 and self.current_bins == self.max_bins:
- raise ObjectFactoryError('no bins available')
-
- bin = self._makeBin(input_stream)
- bin.factory = self
- self.bins.append(bin)
- self.current_bins += 1
- self.emit('bin-created', bin)
-
- return bin
-
- def _makeBin(self, input_stream=None):
- raise NotImplementedError()
-
- def requestNewInputStream(self, bin, input_stream):
- """
- Request a new input stream on a bin.
-
- @param bin: The C{gst.Bin} on which we request a new stream.
- @param input_stream: The new input C{MultimediaStream} we're requesting.
- @raise ObjectFactoryStreamError: If the L{input_stream} isn't compatible
- with one of the factory's L{input_streams}.
- @return: The pad corresponding to the newly created input stream.
- @rtype: C{gst.Pad}
- """
- if not hasattr(bin, 'factory') or bin.factory != self:
- raise ObjectFactoryError("The provided bin isn't handled by this Factory")
- for ins in self.input_streams:
- if ins.isCompatible(input_stream):
- return self._requestNewInputStream(bin, input_stream)
- raise ObjectFactoryError("Incompatible stream")
-
- def _requestNewInputStream(self, bin, input_stream):
- raise NotImplementedError
-
- def releaseBin(self, bin):
- """
- Release a bin created with L{makeBin}.
-
- Some factories can create a limited number of bins or implement caching.
- You should call C{releaseBin} once you are done using a bin.
- """
- bin.set_state(gst.STATE_NULL)
- self._releaseBin(bin)
- self.bins.remove(bin)
- self.current_bins -= 1
- del bin.factory
- self.emit('bin-released', bin)
-
- def _releaseBin(self, bin):
- # default implementation does nothing
- pass
-
- def addOutputStream(self, stream):
- raise AssertionError("sink factories can't have output streams")
-
-
class OperationFactory(ObjectFactory):
"""
Base class for factories that process data (inputs data AND outputs data).
@@ -737,70 +283,3 @@ class OperationFactory(ObjectFactory):
def _releaseBin(self, bin):
# default implementation does nothing
pass
-
-
-class LiveSourceFactory(SourceFactory):
- """
- Base class for factories that produce live streams.
-
- The duration of a live source is unknown and it's possibly infinite. The
- default duration is set to 5 seconds to a live source can be managed in a
- timeline.
- """
-
- def __init__(self, uri, name='', default_duration=None):
- SourceFactory.__init__(self, uri, name)
- if default_duration is None:
- default_duration = 5 * gst.SECOND
-
- self.default_duration = default_duration
-
-
-class RandomAccessSourceFactory(SourceFactory):
- """
- Base class for source factories that support random access.
-
- @ivar offset: Offset in nanoseconds from the beginning of the stream.
- @type offset: C{int}
- @ivar offset_length: Length in nanoseconds.
- @type offset_length: C{int}
- @ivar abs_offset: Absolute offset from the beginning of the stream.
- @type abs_offset: C{int}
- @ivar abs_offset_length: Length in nanoseconds, clamped to avoid overflowing
- the parent's length if any.
- @type abs_offset_length: C{int}
- """
-
- def __init__(self, uri, name='',
- offset=0, offset_length=gst.CLOCK_TIME_NONE):
- self.offset = offset
- self.offset_length = offset_length
-
- SourceFactory.__init__(self, uri, name)
-
- def _getAbsOffset(self):
- if self.parent is None:
- offset = self.offset
- else:
- parent_offset = self.parent.offset
- parent_length = self.parent.offset_length
-
- offset = min(self.parent.offset + self.offset,
- self.parent.offset + self.parent.offset_length)
-
- return offset
-
- abs_offset = property(_getAbsOffset)
-
- def _getAbsOffsetLength(self):
- if self.parent is None:
- offset_length = self.offset_length
- else:
- parent_end = self.parent.abs_offset + self.parent.abs_offset_length
- end = self.abs_offset + self.offset_length
- abs_end = min(end, parent_end)
- offset_length = abs_end - self.abs_offset
-
- return offset_length
-
- abs_offset_length = property(_getAbsOffsetLength)
diff --git a/pitivi/project.py b/pitivi/project.py
index 5fa459e..59dec87 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -24,12 +24,9 @@ Project class
"""
from pitivi.log.loggable import Loggable
-from pitivi.pipeline import Pipeline
-from pitivi.factories.timeline import TimelineSourceFactory
from pitivi.sourcelist import SourceList
from pitivi.settings import ExportSettings
from pitivi.signalinterface import Signallable
-from pitivi.action import ViewAction
from pitivi.utils import Seeker
import gst
import ges
@@ -104,7 +101,6 @@ class Project(Signallable, Loggable):
self.pipeline = ges.TimelinePipeline()
self.pipeline._setUp = False
self.pipeline.add_timeline(self.timeline)
- self.view_action = ViewAction()
self.seeker = Seeker(80)
self.settings = ExportSettings()
diff --git a/pitivi/projectmanager.py b/pitivi/projectmanager.py
index c73ea62..2a0982d 100644
--- a/pitivi/projectmanager.py
+++ b/pitivi/projectmanager.py
@@ -29,15 +29,12 @@ from urlparse import urlparse
from pwd import getpwuid
from pitivi.project import Project
-from pitivi.formatters.format import get_formatter_for_uri
-from pitivi.formatters.base import FormatterLoadError, FormatterSaveError
from pitivi.signalinterface import Signallable
from pitivi.log.loggable import Loggable
-from pitivi.stream import AudioStream, VideoStream
-from pitivi.timeline.track import Track
from pitivi.undo import UndoableAction
+
class ProjectSettingsChanged(UndoableAction):
def __init__(self, project, old, new):
diff --git a/pitivi/settings.py b/pitivi/settings.py
index 032f9a1..9b24bcc 100644
--- a/pitivi/settings.py
+++ b/pitivi/settings.py
@@ -33,7 +33,6 @@ from gettext import gettext as _
from pitivi.signalinterface import Signallable
from pitivi.encode import available_combinations, \
get_compatible_sink_caps
-from pitivi.stream import get_stream_for_caps
from pitivi.log.loggable import Loggable
@@ -320,61 +319,6 @@ class GlobalSettings(Signallable):
cls.options[section] = {}
-class StreamEncodeSettings(object):
- """
- Settings for encoding a L{MultimediaStream}.
-
- @ivar encoder: Name of the encoder used to encode this stream. If None, no
- encoder is used and the incoming stream will be outputted directly.
- @type encoder: C{str}
- @ivar input_stream: The type of streams accepted by this settings. If
- None are specified, the stream type will be extracted from the encoder.
- @type input_stream: L{MultimediaStream}
- @ivar output_stream: The type of streams accepted by this settings. If
- None are specified, the stream type will be extracted from the encoder.
- @type output_stream: L{MultimediaStream}
- @ivar encodersettings: Encoder-specific settings.
- @type encodersettings: C{dict}
- """
-
- def __init__(self, encoder=None, input_stream=None, output_stream=None,
- encodersettings={}):
- """
- @param encoder: The encoder to use. If None, no encoder is used and the
- incoming stream will be outputted directly.
- @type encoder: C{str}.
- @param input_stream: The type of streams accepted by this settings. If
- None are specified, the stream type will be extracted from the encoder.
- If one is specified, then a L{StreamModifierFactory} will be use to
- conform the incoming stream to the specified L{Stream}.
- @type input_stream: L{MultimediaStream}
- @param output_stream: The type of streams accepted by this settings. If
- None are specified, the stream type will be extracted from the encoder.
- @type output_stream: L{MultimediaStream}
- @param encodersettings: Encoder-specific settings.
- @type encodersettings: C{dict}
- """
- # FIXME : What if we need parsers after the encoder ??
- self.encoder = encoder
- self.input_stream = input_stream
- self.output_stream = output_stream
- self.encodersettings = encodersettings
- self.modifyinput = (input_stream != None)
- self.modifyoutput = (output_stream != None)
- if not self.input_stream or not self.output_stream:
- # extract stream from factory
- for p in gst.registry_get_default().lookup_feature(self.encoder).get_static_pad_templates():
- if p.direction == gst.PAD_SINK and not self.input_stream:
- self.input_stream = get_stream_for_caps(p.get_caps().copy())
- self.input_stream.pad_name = p.name_template
- elif p.direction == gst.PAD_SRC and not self.output_stream:
- self.output_stream = get_stream_for_caps(p.get_caps().copy())
- self.output_stream.pad_name = p.name_template
-
- def __str__(self):
- return "<StreamEncodeSettings %s>" % self.encoder
-
-
class RenderSettings(object):
"""
Settings for rendering and multiplexing one or multiple streams.
@@ -595,30 +539,3 @@ class ExportSettings(Signallable, Loggable):
""" Returns the list of video encoders compatible with the current
muxer """
return self.vencoders[self.muxer]
-
-
-def export_settings_to_render_settings(export,
- have_video=True, have_audio=True):
- """Convert the specified ExportSettings object to a RenderSettings object.
- """
- # Get the audio and video caps/encoder/settings
- astream = get_stream_for_caps(export.getAudioCaps())
- vstream = get_stream_for_caps(export.getVideoCaps(render=True))
-
- encoder_settings = []
- if export.vencoder is not None and have_video:
- vset = StreamEncodeSettings(encoder=export.vencoder,
- input_stream=vstream,
- encodersettings=export.vcodecsettings)
- encoder_settings.append(vset)
-
- if export.aencoder is not None and have_audio:
- aset = StreamEncodeSettings(encoder=export.aencoder,
- input_stream=astream,
- encodersettings=export.acodecsettings)
- encoder_settings.append(aset)
-
- settings = RenderSettings(settings=encoder_settings,
- muxer=export.muxer,
- muxersettings=export.containersettings)
- return settings
diff --git a/pitivi/timeline/Makefile.am b/pitivi/timeline/Makefile.am
index 39ae4d5..7592c9f 100644
--- a/pitivi/timeline/Makefile.am
+++ b/pitivi/timeline/Makefile.am
@@ -5,10 +5,8 @@ timeline_PYTHON = \
align.py \
alignalgs.py \
extract.py \
- timeline.py \
- timeline_undo.py \
- track.py \
- gap.py
+ timeline.py \
+ timeline_undo.py
clean-local:
rm -rf *.pyc *.pyo
diff --git a/pitivi/timeline/align.py b/pitivi/timeline/align.py
index e34ccac..b9bfe9f 100644
--- a/pitivi/timeline/align.py
+++ b/pitivi/timeline/align.py
@@ -33,8 +33,6 @@ except ImportError:
import gobject
import gst
from pitivi.utils import beautify_ETA, call_false
-from pitivi.timeline.extract import Extractee, RandomAccessAudioExtractor
-from pitivi.stream import AudioStream
from pitivi.log.loggable import Loggable
from pitivi.timeline.alignalgs import rigidalign
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 06595b0..c3a1c9d 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -20,22 +20,12 @@
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301, USA.
-import collections
-from bisect import bisect_left
-
-from pitivi.signalinterface import Signallable
-from pitivi.log.loggable import Loggable
-from pitivi.utils import UNKNOWN_DURATION, closest_item, PropertyChangeTracker
-from pitivi.timeline.track import TrackObject, SourceTrackObject,\
- TrackEffect, TrackError
-from pitivi.stream import match_stream_groups_map
-from pitivi.utils import start_insort_right, infinity, getPreviousObject, \
- getNextObject
-from pitivi.timeline.gap import Gap, SmallestGapsFinder, invalid_gap
-from pitivi.stream import VideoStream
-from pitivi.timeline.align import AutoAligner
import ges
+from pitivi.utils import infinity
+
+#from pitivi.timeline.align import AutoAligner
+
# Selection modes
SELECT = 0
"""Set the selection to the given set."""
@@ -47,877 +37,6 @@ SELECT_BETWEEN = 3
"""Select a range of clips"""
-class TimelineError(Exception):
- """Base Exception for errors happening in L{Timeline}s or L{TimelineObject}s"""
- pass
-
-
-class TimelineObject(Signallable, Loggable):
- """
- Base class for contents of a C{Timeline}.
-
- A L{TimelineObject} controls one or many L{TrackObject}.
-
- Signals:
- - C{start-changed} : The position changed.
- - C{duration-changed} : The duration changed.
- - C{in-point-changed} : The in-point changed.
- - C{out-point-changed} : The out-point changed.
- - C{media-duration-changed} : The used media duration changed.
- - C{priority-changed} : The priority changed.
- - C{selected-changed} : The selected status changed.
-
- @ivar start: The position of the object in a timeline (nanoseconds)
- @type start: L{long}
- @ivar duration: The duration of the object in a timeline (nanoseconds)
- @type duration: L{long}
- @ivar in_point: The in-point of the object (nanoseconds)
- @type in_point: L{long}
- @ivar out_point: The out-point of the object (nanoseconds)
- @type out_point: L{long}
- @ivar media_duration: The duration to use from the object (nanoseconds)
- @type media_duration: L{long}
- @ivar priority: The priority of the object in a timeline. 0 is top-priority.
- @type priority: L{int}
- @ivar selected: Whether the object is selected or not.
- @type selected: L{bool}
- @ivar track_objects: The Track objects controlled.
- @type track_objects: list of L{TrackObject}
- @ivar timeline: The L{Timeline} to which this object belongs
- @type timeline: L{Timeline}
- """
- __signals__ = {
- 'start-changed': ['start'],
- 'duration-changed': ['duration'],
- 'in-point-changed': ['in-point'],
- 'out-point-changed': ['in-point'],
- 'media-duration-changed': ['media-duration'],
- 'priority-changed': ['priority'],
- 'selected-changed': ['state'],
- 'track-object-added': ["track_object"],
- 'track-object-removed': ["track_object"],
- }
-
- DEFAULT_START = 0
- DEFAULT_DURATION = UNKNOWN_DURATION
- DEFAULT_IN_POINT = 0
- DEFAULT_OUT_POINT = UNKNOWN_DURATION
- DEFAULT_PRIORITY = 0
-
- def __init__(self, factory):
- Loggable.__init__(self)
- self.factory = factory
- self.track_objects = []
- self.timeline = None
- self.link = None
- self._selected = False
-
- def copy(self, copy_track_objects=True):
- cls = self.__class__
- other = cls(self.factory)
- other.track_objects = []
- if copy_track_objects:
- for track_object in self.track_objects:
- other.addTrackObject(track_object.copy())
-
- return other
-
- #{ Property methods
-
- def _getStart(self):
- if not self.track_objects:
- return self.DEFAULT_START
-
- return self.track_objects[0].start
-
- def setStart(self, position, snap=False):
- """
- Set the start position of the object.
-
- If snap is L{True}, then L{position} will be modified if it is close
- to a timeline edge.
-
- @param position: The position in nanoseconds.
- @type position: L{long}
- @param snap: Whether to snap to the nearest edge or not.
- @type snap: L{bool}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- if snap:
- position = self.timeline.snapToEdge(position, position + self.duration)
-
- if self.link is not None:
- # if we're part of a link, we need to check if it's necessary to
- # clamp position so that we don't push the earliest element before 0s
- delta = position - self.start
- off = self.link.earliest_start + delta
- if off < 0:
- # clamp so that the earliest element is shifted to 0s
- position -= off
-
- for track_object in self.track_objects:
- track_object.setObjectStart(position)
-
- self.emit('start-changed', position)
-
- def _getDuration(self):
- if not self.track_objects:
- return self.DEFAULT_DURATION
-
- return self.track_objects[0].duration
-
- def setDuration(self, duration, snap=False, set_media_stop=True):
- """
- Sets the duration of the object.
-
- If snap is L{True}, then L{duration} will be modified if it is close
- to a timeline edge.
-
- If set_media_stop is L{False} then the change will not be propagated
- to the C{TrackObject}s this object controls.
-
- @param duration: The duration in nanoseconds.
- @type duration: L{long}
- @param snap: Whether to snap to the nearest edge or not.
- @type snap: L{bool}
- @param set_media_stop: propagate changes to track objects.
- @type set_media_stop: L{bool}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- if snap:
- position = self.start + duration
- position = self.timeline.snapToEdge(position)
- duration = position - self.start
-
- duration = min(duration, self.factory.duration -
- self.track_objects[0].in_point)
-
- for track_object in self.track_objects:
- track_object.setObjectDuration(duration)
- if set_media_stop:
- track_object.setObjectMediaDuration(duration)
-
- self.emit('duration-changed', duration)
-
- def _getInPoint(self):
- if not self.track_objects:
- return self.DEFAULT_IN_POINT
-
- return self.track_objects[0].in_point
-
- # FIXME: 'snap' is a bogus argument here !
- def setInPoint(self, position, snap=False):
- """
- Sets the in-point of the object.
-
- @param position: The position in nanoseconds.
- @type position: L{long}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- for track_object in self.track_objects:
- track_object.setObjectInPoint(position)
-
- self.emit('in-point-changed', position)
-
- def _getOutPoint(self):
- if not self.track_objects:
- return self.DEFAULT_IN_POINT
-
- return self.track_objects[0].out_point
-
- def _getMediaDuration(self):
- if not self.track_objects:
- return self.DEFAULT_OUT_POINT
-
- return self.track_objects[0].media_duration
-
- # FIXME: 'snaps' is a bogus argument here !
- def setMediaDuration(self, position, snap=False):
- """
- Sets the media-duration of the object.
-
- @param position: The position in nanoseconds.
- @type position: L{long}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- for track_object in self.track_objects:
- track_object.setObjectMediaDuration(position)
-
- self.emit('media-duration-changed', position)
-
- def _getPriority(self):
- if not self.track_objects:
- return self.DEFAULT_PRIORITY
-
- return self.track_objects[0].priority
-
- def setPriority(self, priority):
- """
- Sets the priority of the object. 0 is the highest priority.
-
- @param priority: The priority (0 : highest)
- @type priority: L{int}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- for track_object in self.track_objects:
- track_object.setObjectPriority(priority)
-
- self.emit('priority-changed', priority)
-
- # True when the timeline object is part of the track object's current
- # selection.
-
- def _getSelected(self):
- return self._selected
-
- def setSelected(self, state):
- """
- Sets the selected state of the object.
-
- @param state: L{True} if the object should be selected.
- @type state: L{bool}
- """
- self._selected = state
-
- for obj in self.track_objects:
- obj.setObjectSelected(state)
-
- self.emit("selected-changed", state)
-
- #}
-
- selected = property(_getSelected, setSelected)
- start = property(_getStart, setStart)
- duration = property(_getDuration, setDuration)
- in_point = property(_getInPoint, setInPoint)
- out_point = property(_getOutPoint)
- media_duration = property(_getMediaDuration, setMediaDuration)
- priority = property(_getPriority, setPriority)
-
- #{ Time-related methods
-
- def trimStart(self, position, snap=False):
- """
- Trim the beginning of the object to the given L{position} in nanoseconds.
-
- If snap is L{True}, then L{position} will be modified if it is close
- to a timeline edge.
-
- @param position: The position in nanoseconds.
- @type position: L{long}
- @param snap: Whether to snap to the nearest edge or not.
- @type snap: L{bool}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- if snap:
- position = self.timeline.snapToEdge(position)
-
- for track_object in self.track_objects:
- track_object.trimObjectStart(position)
-
- self.emit('start-changed', self.start)
- self.emit('duration-changed', self.duration)
- self.emit('in-point-changed', self.in_point)
-
- def split(self, position, snap=False):
- """
- Split the given object at the given position in nanoseconds.
-
- The object will be resized to the given position, and another object will
- be created which starts just after and ends at the initial end position.
-
- If snap is L{True}, then L{position} will be modified if it is close
- to a timeline edge.
-
- @param position: The position in nanoseconds.
- @type position: L{long}
- @param snap: Whether to snap to the nearest edge or not.
- @type snap: L{bool}
- @returns: The object corresponding to the other half.
- @rtype: L{TimelineObject}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- @postcondition: If the originating object was not yet in a C{Timeline}, then
- it is up to the caller to add the returned 'half' object to a C{Timeline}.
- """
- if not self.track_objects:
- raise TimelineError("TimelineObject doesn't control any TrackObjects")
-
- other = self.copy(copy_track_objects=False)
-
- for track_object in self.track_objects:
- try:
- other_track_object = track_object.splitObject(position)
- except TrackError, e:
- # FIXME: hallo exception hierarchy?
- raise TimelineError(str(e))
-
- other.addTrackObject(other_track_object)
-
- if self.timeline is not None:
- # if self is not yet in a timeline, the caller needs to add "other"
- # as well when it adds self
- self.timeline.addTimelineObject(other)
-
- self.emit('duration-changed', self.duration)
-
- return other
-
- #{ TrackObject methods
-
- def addTrackObject(self, obj):
- """
- Add the given C{TrackObject} to the list of controlled track objects.
-
- @param obj: The track object to add
- @type obj: C{TrackObject}
- @raises TimelineError: If the object doesn't control any C{TrackObject}s.
- @raises TimelineError: If the provided C{TrackObject} is already controlled
- by this L{TimelineObject}
- @raises TimelineError: If the newly provided C{TrackObject} doesn't have the
- same start position as the other objects controlled.
- @raises TimelineError: If the newly provided C{TrackObject} doesn't have the
- same duration as the other objects controlled.
- """
- if obj.timeline_object is not None:
- raise TimelineError("TrackObject already controlled by another TimelineObject")
-
- if obj in self.track_objects:
- # FIXME : couldn't we just silently return ?
- raise TimelineError("TrackObject already controlled by this TimelineObject")
-
- if self.track_objects:
- # multiple track objects are used for groups.
- # For example if you have the timeline:
- #
- # |sourceA|gap|sourceB|
- # | sourceC |gap
- #
- # If you group A B and C the group will create two gnl compositions,
- # one [A, B] with start A.start and duration B.duration and another
- # [C] with start C.start and duration B.duration (with silence used
- # as padding).
- # The compositions will always be aligned with the same start and
- # duration.
-
- # FIXME : We really should be able to support controlling more than
- # one trackobject with offseted start/duration/in-/out-point/priorities
- existing_track_object = self.track_objects[0]
- if obj.start != existing_track_object.start or \
- obj.duration != existing_track_object.duration:
- raise TimelineError("New TrackObject doesn't have same duration as other controlled TrackObjects")
-
- # FIXME: cycle
- obj.timeline_object = self
- start_insort_right(self.track_objects, obj)
-
- self.emit("track-object-added", obj)
-
- def removeTrackObject(self, obj):
- """
- Remove the given object from the list of controlled C{TrackObject}.
-
- @param obj: The Track Object to remove.
- @type obj: C{TrackObject}
- @raises TimelineError: If the Track object isn't controlled by this TimelineObject.
- """
- if obj.track is None:
- raise TimelineError("TrackObject doesn't belong to any Track")
-
- try:
- self.track_objects.remove(obj)
- obj.timeline_object = None
- except ValueError:
- raise TimelineError("TrackObject doesn't belong to this TimelineObject")
-
- self.emit("track-object-removed", obj)
-
-
-class Selection(Signallable):
- """
- A collection of L{TimelineObject}.
-
- Signals:
- - C{selection-changed} : The contents of the L{Selection} changed.
-
- @ivar selected: Set of selected L{TrackObject}
- @type selected: C{list}
- """
-
- __signals__ = {
- "selection-changed": []}
-
- def __init__(self):
- self.selected = set([])
- self.last_single_obj = None
-
- def setToObj(self, obj, mode):
- """
- Convenience method for calling L{setSelection} with a single L{TimelineObject}
-
- @see: L{setSelection}
- """
- self.setSelection(set([obj]), mode)
-
- def addTimelineObject(self, timeline_object):
- """
- Add the given timeline_object to the selection.
-
- @param timeline_object: The object to add
- @type timeline_object: L{TimelineObject}
- @raises TimelineError: If the object is already controlled by this
- Selection.
- """
- if timeline_object in self.timeline_objects:
- raise TimelineError("TrackObject already in this selection")
-
- def setSelection(self, objs, mode):
- """
- Update the current selection.
-
- Depending on the value of C{mode}, the selection will be:
- - L{SELECT} : set to the provided selection.
- - L{UNSELECT} : the same minus the provided selection.
- - L{SELECT_ADD} : extended with the provided selection.
-
- @param selection: The list of timeline objects to update the selection with.
- @param mode: The type of update to apply. Can be C{SELECT},C{UNSELECT} or C{SELECT_ADD}
-
- @see: L{setToObj}
- """
- # get a list of timeline objects
- selection = set()
- for obj in objs:
- if isinstance(obj, TrackObject):
- selection.add(obj.timeline_object)
- else:
- selection.add(obj)
- old_selection = self.selected
- if mode == SELECT_ADD:
- selection = self.selected | selection
- elif mode == UNSELECT:
- selection = self.selected - selection
- self.selected = selection
-
- if len(self.selected) == 1:
- self.last_single_obj = iter(selection).next()
-
- for obj in self.selected - old_selection:
- obj.selected = True
- for obj in old_selection - self.selected:
- obj.selected = False
-
- # FIXME : shouldn't we ONLY emit this IFF the selection has changed ?
- self.emit("selection-changed")
-
- def getSelectedTrackObjs(self):
- """
- Returns the list of L{TrackObject} contained in this selection.
- """
- objects = []
- for timeline_object in self.selected:
- objects.extend(timeline_object.track_objects)
-
- return set(objects)
-
- def getSelectedTrackEffects(self):
- """
- Returns the list of L{TrackEffect} contained in this selection.
- """
- track_effects = []
- for timeline_object in self.selected:
- for track in timeline_object.track_objects:
- if isinstance(track, TrackEffect):
- track_effects.append(track)
-
- return track_effects
-
- def __len__(self):
- return len(self.selected)
-
- def __iter__(self):
- return iter(self.selected)
-
-
-class LinkPropertyChangeTracker(PropertyChangeTracker):
- """
- Tracker for private usage by L{Link}
-
- @see: L{Link}
- """
- __signals__ = {
- 'start-changed': ['old', 'new'],
- 'duration-changed': ['old', 'new']}
-
- property_names = ('start', 'duration')
-
-
-class Link(object):
-
- def __init__(self):
- self.timeline_objects = set([])
- self.property_trackers = {}
- self.waiting_update = []
- self.earliest_object = None
- self.earliest_start = None
-
- def addTimelineObject(self, timeline_object):
- if timeline_object.link is not None:
- raise TimelineError("TimelineObject already in a Link")
-
- if timeline_object in self.timeline_objects:
- raise TimelineError("TimelineObject already controlled by this Link")
-
- self.timeline_objects.add(timeline_object)
-
- tracker = LinkPropertyChangeTracker()
- tracker.connectToObject(timeline_object)
- self.property_trackers[timeline_object] = tracker
-
- tracker.connect('start-changed', self._startChangedCb)
-
- # FIXME: cycle
- # Edward : maybe use a weak reference instead ? pydoc weakref
- timeline_object.link = self
-
- if self.earliest_start is None or \
- timeline_object.start < self.earliest_start:
- self.earliest_object = timeline_object
- self.earliest_start = timeline_object.start
-
- def removeTimelineObject(self, timeline_object):
- try:
- self.timeline_objects.remove(timeline_object)
- except KeyError:
- raise TimelineError("TimelineObject not controlled by this Link")
-
- tracker = self.property_trackers.pop(timeline_object)
- tracker.disconnectFromObject(timeline_object)
-
- timeline_object.link = None
-
- def join(self, other_link):
- """
- Joins this Link with another and returns the resulting link.
-
- @type other_link: C{Link}
- @postcondition: L{self} and L{other_link} must not be used after
- calling this method !!
- """
- new_link = Link()
-
- for timeline_object in list(self.timeline_objects):
- self.removeTimelineObject(timeline_object)
- new_link.addTimelineObject(timeline_object)
-
- for timeline_object in list(other_link.timeline_objects):
- other_link.removeTimelineObject(timeline_object)
- new_link.addTimelineObject(timeline_object)
-
- return new_link
-
- def _startChangedCb(self, tracker, timeline_object, old_start, start):
- if not self.waiting_update:
- delta = start - old_start
- earliest = timeline_object
-
- self.waiting_update = list(self.timeline_objects)
- # we aren't waiting
- self.waiting_update.remove(timeline_object)
- for linked_object in list(self.waiting_update):
- # this will trigger signals that modify self.waiting_update so
- # we iterate over a copy
- linked_object.start += delta
-
- if linked_object.start < earliest.start:
- earliest = linked_object
-
- assert not self.waiting_update
-
- self.earliest_object = earliest
- self.earliest_start = earliest.start
-
- else:
- self.waiting_update.remove(timeline_object)
-
-
-# FIXME: This seems overly complicated and (therefore) a potential speed bottleneck.
-# It would be much simpler to just track objects, and specify for each object
-# which property we would like to track (start, end, both). We could then have
-# two lists of those objects, one sorted by start values, and another sorted by
-# end values.
-# Bonus : GnlComposition already has all this information, we could maybe add
-# an action signal to it to drastically speed up this process.
-#
-# Alessandro: this is faster than having two separate lists. By keeping start
-# and end edges in the same list, we reduce the time we scan the list
-# of edges. In fact once we find a start edge at pos X, we then scan for an end
-# edge by starting at edges[X] and going forward, avoiding to rescan the edges
-# from 0 to X.
-# I don't see how exposing the gnl lists would make things faster, what's taking
-# time here is scanning the lists, and it's something you'd have to do anyway.
-class TimelineEdges(object):
- """
- Tracks start/stop values and offers convenience methods to find the
- closest value for a given position.
- """
- def __init__(self):
- self.edges = []
- self.by_start = {}
- self.by_end = {}
- self.by_time = {}
- self.by_object = {}
- self.changed_objects = {}
- self.enable_updates = True
-
- def addTimelineObject(self, timeline_object):
- """
- Add this object's start/stop values to the edges.
-
- @param timeline_object: The object whose start/stop we want to track.
- @type timeline_object: L{TimelineObject}
- """
- for obj in timeline_object.track_objects:
- self.addTrackObject(obj)
-
- self._connectToTimelineObject(timeline_object)
-
- def removeTimelineObject(self, timeline_object):
- """
- Remove this object's start/stop values from the edges.
-
- @param timeline_object: The object whose start/stop we no longer want
- to track.
- @type timeline_object: L{TimelineObject}
- """
- self._disconnectFromTimelineObject(timeline_object)
- for obj in timeline_object.track_objects:
- self.removeTrackObject(obj)
-
- def _connectToTimelineObject(self, timeline_object):
- timeline_object.connect("track-object-added", self._trackObjectAddedCb)
- timeline_object.connect("track-object-removed", self._trackObjectRemovedCb)
-
- def _disconnectFromTimelineObject(self, timeline_object):
- timeline_object.disconnect_by_func(self._trackObjectAddedCb)
- timeline_object.disconnect_by_func(self._trackObjectRemovedCb)
-
- def _trackObjectAddedCb(self, timeline_object, track_object):
- self.addTrackObject(track_object)
-
- def _trackObjectRemovedCb(self, timeline_object, track_object):
- self.removeTrackObject(track_object)
-
- def addTrackObject(self, track_object):
- if track_object in self.by_object:
- raise TimelineError("TrackObject already controlled by this TimelineEdge")
-
- start = track_object.start
- end = track_object.start + track_object.duration
-
- self.addStartEnd(start, end)
-
- self.by_start.setdefault(start, []).append(track_object)
- self.by_end.setdefault(end, []).append(track_object)
- self.by_time.setdefault(start, []).append(track_object)
- self.by_time.setdefault(end, []).append(track_object)
- self.by_object[track_object] = (start, end)
- self._connectToTrackObject(track_object)
-
- def removeTrackObject(self, track_object):
- try:
- old_start, old_end = self.by_object.pop(track_object)
- except KeyError:
- raise TimelineError("TrackObject not controlled by this TimelineEdge")
-
- try:
- del self.changed_objects[track_object]
- start = old_start
- end = old_end
- except KeyError:
- start = track_object.start
- end = track_object.start + track_object.duration
-
- self.removeStartEnd(start, end)
-
- # remove start and end from self.by_start, self.by_end and self.by_time
- for time, time_dict in ((start, self.by_start), (end, self.by_end),
- (start, self.by_time), (end, self.by_time)):
- time_dict[time].remove(track_object)
- if not time_dict[time]:
- del time_dict[time]
-
- self._disconnectFromTrackObject(track_object)
-
- def _connectToTrackObject(self, track_object):
- track_object.connect("start-changed", self._trackObjectStartChangedCb)
- track_object.connect("duration-changed", self._trackObjectDurationChangedCb)
-
- def _disconnectFromTrackObject(self, track_object):
- track_object.disconnect_by_func(self._trackObjectStartChangedCb)
- track_object.disconnect_by_func(self._trackObjectDurationChangedCb)
-
- def _trackObjectStartChangedCb(self, track_object, start):
- start = track_object.start
- end = start + track_object.duration
-
- self.changed_objects[track_object] = (start, end)
-
- self._maybeProcessChanges()
-
- def _trackObjectDurationChangedCb(self, track_object, duration):
- start = track_object.start
- end = start + track_object.duration
-
- self.changed_objects[track_object] = (start, end)
-
- self._maybeProcessChanges()
-
- def addStartEnd(self, start, end=None):
- lo = 0
- index = bisect_left(self.edges, start, lo=lo)
- lo = index
- self.edges.insert(index, start)
-
- if end is not None:
- index = bisect_left(self.edges, end, lo=lo)
- self.edges.insert(index, end)
-
- def removeStartEnd(self, start, end=None):
- lo = 0
- index = bisect_left(self.edges, start, lo=lo)
- # check if start is a valid edge
- if index == len(self.edges) or self.edges[index] != start:
- raise TimelineError("Start (%r) is not a valid edge" % start)
-
- del self.edges[index]
- lo = index
-
- if end is not None:
- index = bisect_left(self.edges, end, lo=lo)
- # check if end is a valid edge
- if index == len(self.edges) or self.edges[index] != end:
- raise TimelineError("End (%r) is not a valid edge")
-
- del self.edges[index]
-
- def enableUpdates(self):
- self.enable_updates = True
- self._maybeProcessChanges()
-
- def _maybeProcessChanges(self):
- if not self.enable_updates:
- return
-
- changed, self.changed_objects = self.changed_objects, {}
-
- for track_object, (start, end) in changed.iteritems():
- old_start, old_end = self.by_object[track_object]
-
- for old_time, time, time_dict in ((old_start, start, self.by_start),
- (old_end, end, self.by_end), (old_start, start, self.by_time),
- (old_end, end, self.by_time)):
- time_dict[old_time].remove(track_object)
- if not time_dict[old_time]:
- del time_dict[old_time]
- time_dict.setdefault(time, []).append(track_object)
-
- old_edges = []
- new_edges = []
- if start != old_start:
- old_edges.append(old_start)
- new_edges.append(start)
-
- if end != old_end:
- old_edges.append(old_end)
- new_edges.append(end)
-
- if old_edges:
- self.removeStartEnd(*old_edges)
- if new_edges:
- self.addStartEnd(*new_edges)
-
- self.by_object[track_object] = (start, end)
-
- def disableUpdates(self):
- self.enable_updates = False
-
- def snapToEdge(self, start, end=None):
- """
- Returns:
- - the closest edge to the given start/stop position.
- - the difference between the provided position and the returned edge.
- """
- if len(self.edges) == 0:
- return start, 0
-
- start_closest, start_diff, start_index = \
- closest_item(self.edges, start)
-
- if end is None or len(self.edges) == 1:
- return start_closest, start_diff,
-
- end_closest, end_diff, end_index = \
- closest_item(self.edges, end, start_index)
-
- if start_diff <= end_diff:
- return start_closest, start_diff
-
- return start + end_diff, end_diff
-
- def closest(self, position):
- """
- Returns two values:
- - The closest value just *before* the given position.
- - The closest value just *after* the given position.
-
- @param position: The position to search for.
- @type position: L{long}
- """
- closest, diff, index = closest_item(self.edges, position)
- return self.edges[max(0, index - 2)], self.edges[min(
- len(self.edges) - 1, index + 1)]
-
- def getObjsIncidentOnTime(self, time):
- """Return a list of all track objects whose start or end (start +
- duration) are exactly equal to a given time"""
- if time in self.by_time:
- return self.by_time[time]
- return []
-
- def getObjsAdjacentToStart(self, trackobj):
- """Return a list of all track objects whose ends (start + duration)
- are equal to the given track object's start"""
- if trackobj.start in self.by_end:
- return self.by_end[trackobj.start]
- return []
-
- def getObjsAdjacentToEnd(self, trackobj):
- """Return a list of all track objects whose start property are
- adjacent to the given track object's end (start + duration)"""
- end = trackobj.start + trackobj.duration
- if end in self.by_start:
- return self.by_start[end]
- return []
-
-
class EditingContext(object):
DEFAULT = 0
@@ -1168,9 +287,6 @@ class MoveContext(EditingContext):
# special case for transitions. Allow a single object to overlap
# either of its two neighbors if it overlaps no other objects
if len(self.timeline_objects) == 1:
- #if not self._overlapsAreTransitions(focus_timeline_object,
- #priority):
- #self._defaultTo(initial_position, initial_priority)
EditingContext.finish(self)
return
@@ -1457,710 +573,3 @@ class TrimEndContext(EditingContext):
left_gap, right_gap = Gap.findAroundObject(self.focus_timeline_object)
duration = absolute_initial_duration + right_gap.duration
self._defaultTo(duration, self.focus.priority)
-
-
-class Timeline(Signallable, Loggable):
- """
- Top-level container for L{TimelineObject}s.
-
- Signals:
- - C{duration-changed} : The duration changed.
- - C{track-added} : A L{timeline.Track} was added.
- - C{track-removed} : A L{timeline.Track} was removed.
- - C{selection-changed} : The current selection changed.
-
- @ivar tracks: list of Tracks controlled by the Timeline
- @type tracks: List of L{timeline.Track}
- @ivar duration: Duration of the Timeline in nanoseconds.
- @type duration: C{long}
- @ivar selection: The currently selected TimelineObjects
- @type selection: L{Selection}
- """
- __signals__ = {
- 'duration-changed': ['duration'],
- 'timeline-object-added': ['timeline_object'],
- 'timeline-object-removed': ['timeline_object'],
- 'track-added': ['track'],
- 'track-removed': ['track'],
- 'selection-changed': [],
- 'disable-updates': ['bool']}
-
- def __init__(self):
- Loggable.__init__(self)
- self.tracks = []
- self.selection = Selection()
- self.selection.connect("selection-changed", self._selectionChanged)
- self.timeline_objects = []
- self.duration = 0
- self.links = []
- # FIXME : What's the unit of dead_band ?
- self.dead_band = 10
- self.edges = TimelineEdges()
- self.property_trackers = {}
- self._video_caps = None
-
- def addTrack(self, track):
- """
- Add the track to the timeline.
-
- @param track: The track to add
- @type track: L{timeline.Track}
- @raises TimelineError: If the track is already in the timeline.
- """
- if track in self.tracks:
- raise TimelineError("Provided track already controlled by the timeline")
-
- self.tracks.append(track)
- self.updateVideoCaps()
- self._updateDuration()
- track.connect('start-changed', self._trackDurationChangedCb)
- track.connect('duration-changed', self._trackDurationChangedCb)
-
- self.emit('track-added', track)
-
- def removeTrack(self, track, removeTrackObjects=True):
- """
- Remove the track from the timeline.
-
- @param track: The track to remove.
- @type track: L{timeline.Track}
- @param removeTrackObjects: If C{True}, clear the Track from its objects.
- @type removeTrackObjects: C{bool}
- @raises TimelineError: If the track isn't in the timeline.
- """
- try:
- self.tracks.remove(track)
- except ValueError:
- raise TimelineError("Track not controlled by this Timeline")
-
- if removeTrackObjects:
- track.removeAllTrackObjects()
-
- self.emit('track-removed', track)
-
- def _selectionChanged(self, selection):
- self.emit("selection-changed")
-
- def _trackStartChangedCb(self, track, duration):
- self._updateDuration()
-
- def _trackDurationChangedCb(self, track, duration):
- self._updateDuration()
-
- def _updateDuration(self):
- duration = max([track.start + track.duration for track in self.tracks])
- if duration != self.duration:
- self.duration = duration
- self.emit('duration-changed', duration)
-
- def updateVideoCaps(self, caps=None):
- if caps:
- self._video_caps = caps
-
- if self._video_caps:
- for track in self.tracks:
- if type(track.stream) is VideoStream:
- track.updateCaps(self._video_caps)
-
- def addTimelineObject(self, obj):
- """
- Add the TimelineObject to the Timeline.
-
- @param obj: The object to add
- @type obj: L{TimelineObject}
- @raises TimelineError: if the object is used in another Timeline.
- """
- self.debug("obj:%r", obj)
- if obj.timeline is not None:
- raise TimelineError("TimelineObject already controlled by another Timeline")
-
- # FIXME : wait... what's wrong with having empty timeline objects ??
- # And even if it was.. this shouldn't be checked here imho.
- if not obj.track_objects:
- raise TimelineError("TimelineObject doesn't have any TrackObject (THIS IS A VERY DUBIOUS CHECK, WE SHOULD ACCEPT THIS)")
-
- self._connectToTimelineObject(obj)
-
- start_insort_right(self.timeline_objects, obj)
- obj.timeline = self
-
- self.edges.addTimelineObject(obj)
-
- self.emit("timeline-object-added", obj)
-
- def removeTimelineObject(self, obj, deep=False):
- """
- Remove the given object from the Timeline.
-
- @param obj: The object to remove
- @type obj: L{TimelineObject}
- @param deep: If C{True}, remove the L{TrackObject}s associated to the object.
- @type deep: C{bool}
- @raises TimelineError: If the object doesn't belong to the timeline.
- """
- try:
- self.timeline_objects.remove(obj)
- except ValueError:
- raise TimelineError("TimelineObject not controlled by this Timeline")
-
- if obj.link is not None:
- obj.link.removeTimelineObject(obj)
-
- self._disconnectFromTimelineObject(obj)
-
- obj.timeline = None
-
- self.edges.removeTimelineObject(obj)
-
- self.emit("timeline-object-removed", obj)
-
- if deep:
- for track_object in obj.track_objects:
- track = track_object.track
- track.removeTrackObject(track_object)
-
- def removeMultipleTimelineObjects(self, objs, deep=False):
- """
- Remove multiple objects from the Timeline.
-
- @param objs: The collection of objects to remove
- @type obj: collection(L{TimelineObject})
- @param deep: If C{True}, remove the L{TrackObject}s associated with
- these objects.
- @type deep: C{bool}
- @raises TimelineError: If the object doesn't belong to the timeline.
- """
- for obj in objs:
- self.removeTimelineObject(obj, False)
-
- # If we are going to remove the associated track objects, first
- # group them by track so we can use the track's removeMultiple method.
- if deep:
- track_aggregate = collections.defaultdict(list)
- for obj in objs:
- for track_object in obj.track_objects:
- track_aggregate[track_object.track].append(track_object)
- for track, objects_to_remove in track_aggregate.items():
- track.removeMultipleTrackObjects(objects_to_remove)
-
- def removeFactory(self, factory):
- """Remove every instance factory in the timeline
- @param factory: the factory to remove from the timeline
- """
- objs = [obj for obj in self.timeline_objects if obj.factory is
- factory]
- self.removeMultipleTimelineObjects(objs, deep=True)
-
- def usesFactory(self, factory):
- """
- Return whether the specified factory is present in the timeline.
- @param the factory you are looking for
- @type factory
- @returns True if found, or False if not in the timeline.
- """
- for obj in self.timeline_objects:
- if obj.factory is factory:
- return True
- return False
-
- def _timelineObjectStartChangedCb(self, timeline_object, start):
- self.timeline_objects.remove(timeline_object)
- start_insort_right(self.timeline_objects, timeline_object)
-
- def _timelineObjectDurationChangedCb(self, timeline_object, duration):
- pass
-
- def _connectToTimelineObject(self, timeline_object):
- timeline_object.connect('start-changed',
- self._timelineObjectStartChangedCb)
- timeline_object.connect('duration-changed',
- self._timelineObjectDurationChangedCb)
-
- def _disconnectFromTimelineObject(self, timeline_object):
- timeline_object.disconnect_by_function(self._timelineObjectStartChangedCb)
- timeline_object.disconnect_by_function(self._timelineObjectDurationChangedCb)
-
- # FIXME : shouldn't this be made more generic (i.e. not specific to source factories) ?
- # FIXME : Maybe it should be up to the ObjectFactory to create the TimelineObject since
- # it would know the exact type of TimelineObject to create with what properties (essential
- # for being able to create Groups and importing Timelines within Timelines.
- def addSourceFactory(self, factory, stream_map=None, strict=False):
- """
- Creates a TimelineObject for the given SourceFactory and adds it to the timeline.
-
- @param factory: The factory to add.
- @type factory: L{SourceFactory}
- @param stream_map: A mapping of factory streams to track streams.
- @type stream_map: C{dict} of MultimediaStream => MultimediaStream
- @param strict: If C{True} only add the factory if an exact stream mapping can be
- calculated.
- @type strict: C{bool}
- @raises TimelineError: if C{strict} is True and no exact mapping could be calculated.
- """
- self.debug("factory:%r", factory)
- output_streams = factory.getOutputStreams()
- if not output_streams:
- raise TimelineError("SourceFactory doesn't provide any Output Streams")
-
- if stream_map is None:
- stream_map = self._getSourceFactoryStreamMap(factory)
- if len(stream_map) < len(output_streams):
- # we couldn't assign each stream to a track automatically,
- # error out and require the caller to pass a stream_map
- self.error("Couldn't find a complete stream mapping (self:%d < factory:%d)",
- len(stream_map), len(output_streams))
- if strict:
- raise TimelineError("Couldn't map all streams to available Tracks")
-
- timeline_object = TimelineObject(factory)
- start = 0
- for stream, track in stream_map.iteritems():
- self.debug("Stream: %s, Track: %s, Track duration: %d", str(stream),
- str(track), track.duration)
- start = max(start, track.duration)
- track_object = SourceTrackObject(factory, stream)
- track.addTrackObject(track_object)
- timeline_object.addTrackObject(track_object)
-
- timeline_object.start = start
- self.addTimelineObject(timeline_object)
- return timeline_object
-
- def addEffectFactoryOnObject(self, factory, timeline_objects):
- """
- Add EffectTracks corresponding to the effect from the factory to the corresponding
- L{TimelineObject}s on the timeline
-
- @param factory: The EffectFactory to add.
- @type factory: L{EffectFactory}
- @timeline_objects: The L{TimelineObject}s on whiches you want to add TrackObjects
- corresponding to the L{EffectFactory}
- @type timeline_objects: A C{List} of L{TimelineObject}s
-
- @raises TimelineError: if the factory doesn't have input or output streams
- @returns: A list of L{TimelineObject}, L{TrackObject} tuples
- """
- #Note: We should maybe be able to handle several streams for effects which
- #are actually working on audio/video streams
- self.debug("factory:%r", factory)
-
- output_stream = factory.getOutputStreams()
- if not output_stream:
- raise TimelineError()
- output_stream = output_stream[0]
-
- input_stream = factory.getInputStreams()
- if not input_stream:
- raise TimelineError()
- input_stream = input_stream[0]
-
- track = None
- for track_ in self.tracks:
- if type(track_.stream) == type(input_stream):
- track = track_
- break
-
- if track is None:
- raise TimelineError("There is no Track to add the effect to")
-
- if not timeline_objects:
- raise TimelineError("There is no timeline object to add effect to")
-
- listTimelineObjectTrackObject = []
- track_object = TrackEffect(factory, input_stream)
-
- for obj in timeline_objects:
- copy_track_obj = track_object.copy()
- track.addTrackObject(copy_track_obj)
- copy_track_obj.start = obj.start
- copy_track_obj.duration = obj.duration
- copy_track_obj.media_duration = obj.media_duration
- obj.addTrackObject(copy_track_obj)
- listTimelineObjectTrackObject.append((obj, copy_track_obj))
-
- self.debug("%s", ["TimelineObject %s => Track object: %s |"\
- % (listTo[0], listTo[1])\
- for listTo in listTimelineObjectTrackObject])
- return listTimelineObjectTrackObject
-
- def _getSourceFactoryStreamMap(self, factory):
- # track.stream -> track
- track_stream_to_track_map = dict((track.stream, track)
- for track in self.tracks)
-
- # output_stream -> track.stream
- output_stream_to_track_stream_map = \
- match_stream_groups_map(factory.output_streams,
- [track.stream for track in self.tracks])
-
- # output_stream -> track (result)
- output_stream_to_track_map = {}
- for stream, track_stream in output_stream_to_track_stream_map.iteritems():
- output_stream_to_track_map[stream] = \
- track_stream_to_track_map[track_stream]
-
- return output_stream_to_track_map
-
- def getPreviousTimelineObject(self, obj, priority=-1, tracks=None):
- if tracks is None:
- skip = None
- else:
-
- def skipIfNotInTheseTracks(timeline_object):
- return self._skipIfNotInTracks(timeline_object, tracks)
- skip = skipIfNotInTheseTracks
-
- prev = getPreviousObject(obj, self.timeline_objects,
- priority, skip=skip)
-
- if prev is None:
- raise TimelineError("no previous timeline object", obj)
-
- return prev
-
- def getNextTimelineObject(self, obj, priority=-1, tracks=None):
- if tracks is None:
- skip = None
- else:
-
- def skipIfNotInTheseTracks(timeline_object):
- return self._skipIfNotInTracks(timeline_object, tracks)
- skip = skipIfNotInTheseTracks
-
- next = getNextObject(obj, self.timeline_objects, priority, skip)
- if next is None:
- raise TimelineError("no next timeline object", obj)
-
- return next
-
- def _skipIfNotInTracks(self, timeline_object, tracks):
- timeline_object_tracks = set(track_object.track for track_object in
- timeline_object.track_objects)
-
- return not tracks.intersection(timeline_object_tracks)
-
- def setSelectionToObj(self, obj, mode):
- """
- Update the timeline's selection with the given object and mode.
-
- @see: L{Selection.setToObj}
- """
- if mode == SELECT_BETWEEN:
- if self.selection.last_single_obj:
- last = self.selection.last_single_obj
- earliest = min(last.start, obj.start)
- latest = max(last.start + last.duration,
- obj.start + obj.duration)
- min_priority = min(last.priority, obj.priority)
- max_priority = max(last.priority, obj.priority)
- objs = self.getObjsInRegion(earliest, latest,
- min_priority, max_priority)
- self.setSelectionTo(objs, SELECT)
- return
-
- self.selection.setToObj(obj, mode)
-
- def setSelectionTo(self, selection, mode):
- """
- Update the timeline's selection with the given selection and mode.
-
- @see: L{Selection.setSelection}
- """
- self.selection.setSelection(selection, mode)
-
- def linkSelection(self):
- """
- Link the currently selected timeline objects.
- """
- if len(self.selection) < 2:
- return
-
- # list of links that we joined and so need to be removed
- old_links = []
-
- # we start with a new empty link and we expand it as we find new objects
- # and links
- link = Link()
- for timeline_object in self.selection:
- if timeline_object.link is not None:
- old_links.append(timeline_object.link)
-
- link = link.join(timeline_object.link)
- else:
- link.addTimelineObject(timeline_object)
-
- for old_link in old_links:
- self.links.remove(old_link)
-
- self.links.append(link)
- self.emit("selection-changed")
-
- def unlinkSelection(self):
- """
- Unlink the currently selected timeline objects.
- """
- empty_links = set()
- for timeline_object in self.selection:
- if timeline_object.link is None:
- continue
-
- link = timeline_object.link
- link.removeTimelineObject(timeline_object)
- if not link.timeline_objects:
- empty_links.add(link)
-
- for link in empty_links:
- self.links.remove(link)
- self.emit("selection-changed")
-
- def groupSelection(self):
- if len(self.selection.selected) < 2:
- return
-
- # FIXME: pass a proper factory
- new_timeline_object = TimelineObject(factory=None)
-
- tracks = []
- for timeline_object in self.selection.selected:
- for track_object in timeline_object.track_objects:
- new_track_object = track_object.copy()
- tracks.append(track_object.track)
- new_timeline_object.addTrackObject(new_track_object)
-
- self.addTimelineObject(new_timeline_object)
-
- old_track_objects = []
- for timeline_object in list(self.selection.selected):
- old_track_objects.extend(timeline_object.track_objects)
- self.removeTimelineObject(timeline_object, deep=True)
-
- self.selection.setSelection(old_track_objects, UNSELECT)
- self.selection.setSelection(new_timeline_object.track_objects, SELECT_ADD)
-
- def ungroupSelection(self):
- new_track_objects = []
- for timeline_object in list(self.selection.selected):
- if len(timeline_object.track_objects) == 1:
- continue
-
- self.selection.setSelection(timeline_object.track_objects, UNSELECT)
- n_track_effects = []
- n_tl_objects = []
-
- for track_object in list(timeline_object.track_objects):
- if isinstance(track_object, TrackEffect):
- n_track_effects.append(track_object)
- else:
- new_track_object = track_object.copy()
- new_timeline_object = TimelineObject(new_track_object.factory)
- new_timeline_object.addTrackObject(new_track_object)
- n_tl_objects.append(new_timeline_object)
-
- for tl_object in n_tl_objects:
- for tck_effect in n_track_effects:
- if tl_object.track_objects[0].stream_type == tck_effect.stream_type:
- self.addEffectFactoryOnObject(tck_effect.factory, [tl_object])
-
- self.addTimelineObject(tl_object)
-
- new_track_objects.extend(new_timeline_object.track_objects)
-
- self.removeTimelineObject(timeline_object, deep=True)
-
- self.selection.setSelection(new_track_objects, SELECT_ADD)
-
- def alignSelection(self, callback):
- """
- Auto-align the selected set of L{TimelineObject}s based on their
- contents. Return asynchronously, and call back when finished.
-
- @param callback: function to call (with no arguments) when finished.
- @type callback: function
- @returns: a L{ProgressMeter} indicating the state of the alignment
- process
- @rtype: L{ProgressMeter}
- """
- auto_aligner = AutoAligner(self.selection.selected, callback)
- progress_meter = auto_aligner.start()
- return progress_meter
-
- def deleteSelection(self):
- """
- Removes all the currently selected L{TimelineObject}s from the Timeline.
- """
- self.unlinkSelection()
- self.removeMultipleTimelineObjects(self.selection, deep=True)
- self.selection.setSelection(set([]), SELECT)
-
- def split(self, time):
- """
- Splits objects under the playehad. If the selection is not empty, the
- split only applies to selected clips. Otherwise it applies to all
- clips"""
- objs = set(self.getObjsAtTime(time))
- if len(self.selection):
- objs = self.selection.selected.intersection(objs)
- for obj in objs:
- obj.split(time)
-
- def rebuildEdges(self):
- self.edges = TimelineEdges()
- for timeline_object in self.timeline_objects:
- self.edges.addTimelineObject(timeline_object)
-
- def snapToEdge(self, start, end=None):
- """
- Snaps the given start/end value to the closest edge if it is within
- the timeline's dead_band.
-
- @param start: The start position to snap.
- @param end: The stop position to snap.
- @returns: The snapped value if within the dead_band.
- """
- edge, diff = self.edges.snapToEdge(start, end)
-
- if self.dead_band != -1 and diff <= self.dead_band:
- return edge
-
- return start
-
- def disableUpdates(self):
- """
- Block internal updates. Use this when doing more than one consecutive
- modification in the pipeline.
- """
- for track in self.tracks:
- track.disableUpdates()
-
- self.edges.disableUpdates()
-
- self.emit("disable-updates", True)
-
- def enableUpdates(self):
- """
- Unblock internal updates. Use this after calling L{disableUpdates}.
- """
-
- for track in self.tracks:
- track.enableUpdates()
-
- self.edges.enableUpdates()
-
- self.emit("disable-updates", False)
-
- def getObjsAtTime(self, time):
- objects = []
- for obj in self.timeline_objects:
- if obj.start < time:
- if (obj.start + obj.duration) > time:
- objects.append(obj)
- else:
- break
- return objects
-
- def getObjsAfterObj(self, obj):
- return self.getObjsAfterTime(obj.start + obj.duration)
-
- def getObjsAfterTime(self, target):
- objects = []
- for i in range(0, len(self.timeline_objects)):
- if self.timeline_objects[i].start >= target:
- objects.extend(self.timeline_objects[i:])
- break
- return objects
-
- def getObjsBeforeObj(self, obj):
- return self.getObjsBeforeTime(obj.start)
-
- def getObjsBeforeTime(self, target):
- objects = []
- for obj in self.timeline_objects:
- if obj.start > target:
- break
- elif obj.start + obj.duration <= target:
- objects.append(obj)
- return objects
-
- def getObjsInRegion(self, start, end, min_priority=0,
- max_priority=4294967295L):
- objects = []
- for obj in self.timeline_objects:
- if obj.start >= start:
- if ((obj.start + obj.duration) <= end and
- obj.priority >= min_priority and
- obj.priority <= max_priority):
- objects.append(obj)
- elif obj.start > end:
- break
- return objects
-
- def getPrevKeyframe(self, time):
- tl_objs = []
-
- # Exclude objects that start after current position.
- for obj in self.timeline_objects:
- tl_objs.append(obj)
- if obj.start > time:
- break
-
- keyframe_positions = self._getKeyframePositions(tl_objs)
- for n in range(len(keyframe_positions) - 1, -1, -1):
- if keyframe_positions[n] < time:
- return keyframe_positions[n]
- return None
-
- def getNextKeyframe(self, time):
- tl_objs = []
-
- # Include from first object whose end is after the current
- # position onward.
- for obj in self.timeline_objects:
- if (obj.start + obj.duration) > time:
- n = self.timeline_objects.index(obj)
- tl_objs.extend(self.timeline_objects[n:])
- break
-
- keyframe_positions = self._getKeyframePositions(tl_objs)
- for n in range(0, len(keyframe_positions)):
- if keyframe_positions[n] > time:
- return keyframe_positions[n]
-
- return None
-
- def _getKeyframePositions(self, timeline_objects):
- keyframe_positions = set([])
- for tl_obj in timeline_objects:
- first_track = True
- for track_obj in tl_obj.track_objects:
- start = track_obj.start
- in_point = track_obj.in_point
- if first_track:
- keyframe_positions.add(start)
- keyframe_positions.add(start + track_obj.duration)
- first_track = False
-
- interpolators = track_obj.getInterpolators()
- for value in interpolators:
- interpolator = track_obj.getInterpolator(value)
- keyframes = interpolator.getInteriorKeyframes()
- for kf in keyframes:
- position_in_obj = kf.getTime() + start - in_point
- keyframe_positions.add(position_in_obj)
- keyframe_positions = list(keyframe_positions)
- keyframe_positions.sort()
- return keyframe_positions
-
- def getObjsToAddEffectTo(self, point, priority):
- timeline_objects = []
- if point == -1:
- for obj in self.timeline_objects:
- if obj.priority == priority:
- timeline_objects.append(obj)
- else:
- for obj in self.timeline_objects:
- if (obj.start <= point and
- point <= (obj.start + obj.duration) and\
- obj.priority == priority):
- timeline_objects.append(obj)
-
- return timeline_objects
diff --git a/pitivi/timeline/timeline_undo.py b/pitivi/timeline/timeline_undo.py
index 03dd3a7..85a3c81 100644
--- a/pitivi/timeline/timeline_undo.py
+++ b/pitivi/timeline/timeline_undo.py
@@ -24,7 +24,6 @@ import gobject
from pitivi.signalinterface import Signallable
from pitivi.utils import PropertyChangeTracker
from pitivi.undo import UndoableAction
-from pitivi.timeline.track import TrackEffect
from pitivi.ui.effectsconfiguration import PROPS_TO_IGNORE
from pitivi.effects import EffectGstElementPropertyChangeTracker
@@ -396,7 +395,7 @@ class TimelineLogObserver(object):
tracker = TimelineObjectPropertyChangeTracker()
tracker.connectToObject(timeline_object)
for property_name in tracker.property_names:
- tracker.connect("notify::" +property_name,
+ tracker.connect("notify::" + property_name,
self._timelineObjectPropertyChangedCb, property_name)
self.timeline_object_property_trackers[timeline_object] = tracker
diff --git a/pitivi/ui/clipproperties.py b/pitivi/ui/clipproperties.py
index 1121c8c..84c9aec 100644
--- a/pitivi/ui/clipproperties.py
+++ b/pitivi/ui/clipproperties.py
@@ -31,8 +31,6 @@ import os
from gettext import gettext as _
from pitivi.log.loggable import Loggable
-from pitivi.timeline.track import TrackEffect
-from pitivi.stream import VideoStream
from pitivi.ui.gstwidget import GstElementSettingsWidget
from pitivi.ui.effectsconfiguration import EffectsPropertiesHandling
@@ -638,4 +636,4 @@ class TransformationProperties(gtk.Expander):
if timeline:
self.app.projectManager.current.connect('selected-changed', self._selectionChangedCb)
- timeline = property(_getTimeline, _setTimeline)
\ No newline at end of file
+ timeline = property(_getTimeline, _setTimeline)
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index ee4b513..e4cb09f 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -42,11 +42,8 @@ from pitivi.ui.viewer import PitiviViewer
from pitivi.configure import pitivi_version, APPNAME, APPURL, \
get_pixmap_dir, get_ui_dir
from pitivi.ui import dnd
-from pitivi.pipeline import Pipeline
-from pitivi.action import ViewAction
from pitivi.settings import GlobalSettings
from pitivi.receiver import receiver, handler
-import pitivi.formatters.format as formatter
from pitivi.sourcelist import SourceListError
from pitivi.ui.sourcelist import SourceList
from pitivi.ui.effectlist import EffectList
diff --git a/pitivi/ui/previewer.py b/pitivi/ui/previewer.py
index cf96308..d421e95 100644
--- a/pitivi/ui/previewer.py
+++ b/pitivi/ui/previewer.py
@@ -30,15 +30,10 @@ import os
from gettext import gettext as _
import pitivi.utils as utils
from pitivi.configure import get_pixmap_dir
-from pitivi.elements.singledecodebin import SingleDecodeBin
-from pitivi.elements.thumbnailsink import CairoSurfaceThumbnailSink
-from pitivi.elements.arraysink import ArraySink
from pitivi.signalinterface import Signallable
-import pitivi.stream as stream
from pitivi.settings import GlobalSettings
from pitivi.ui.zoominterface import Zoomable
from pitivi.log.loggable import Loggable
-from pitivi.factories.file import PictureFileSourceFactory
from pitivi.thumbnailcache import ThumbnailCache
from pitivi.ui.prefs import PreferencesDialog
from pitivi.receiver import receiver, handler
diff --git a/pitivi/ui/sourcelist.py b/pitivi/ui/sourcelist.py
index 68a1aa9..488e7f0 100644
--- a/pitivi/ui/sourcelist.py
+++ b/pitivi/ui/sourcelist.py
@@ -28,7 +28,6 @@ import time
from urllib import unquote
from gettext import gettext as _
-from gettext import ngettext
import pitivi.ui.dnd as dnd
from pitivi.ui.pathwalker import PathWalker, quote_uri
@@ -41,7 +40,6 @@ from pitivi.utils import beautify_length
from pitivi.ui.common import beautify_info, info_name, \
SPACING, PADDING
from pitivi.log.loggable import Loggable
-from pitivi.sourcelist import SourceListError
from pitivi.ui.filechooserpreview import PreviewWidget
SHOW_TREEVIEW = 1
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 6783be6..2cd2f9a 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -43,7 +43,7 @@ from pitivi.ui.filelisterrordialog import FileListErrorDialog
from pitivi.ui.common import SPACING
from pitivi.ui.alignmentprogress import AlignmentProgressDialog
from pitivi.ui.depsmanager import DepsManager
-from pitivi.timeline.align import AutoAligner
+#from pitivi.timeline.align import AutoAligner
from pitivi.check import soft_deps
DND_EFFECT_LIST = [[dnd.VIDEO_EFFECT_TUPLE[0], dnd.EFFECT_TUPLE[0]],\
@@ -399,9 +399,6 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.drag_highlight()
if context.targets not in DND_EFFECT_LIST:
if not self._temp_objects:
- #GES break, FIXME
- pass
- self.timeline.disableUpdates()
self._add_temp_source()
focus = self._temp_objects[0]
self._move_context = MoveContext(self.timeline,
@@ -546,7 +543,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self._vscrollbar.set_value(self._vscrollbar.get_value() +
self.vadj.props.page_size ** (2.0 / 3.0))
- def unsureVadjHeight (self):
+ def unsureVadjHeight(self):
self._scroll_pos_ns = Zoomable.pixelToNs(self.hadj.get_value())
self._root_item.set_simple_transform(0 - self.hadj.get_value(),
0 - self.vadj.get_value(), 1.0, 0)
@@ -644,6 +641,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self._settingsChangedCb(self.project, None, self.project.getSettings())
self._seeker = self.project.seeker
+ #FIXME GES port
project = receiver(_setProject)
@handler(project, "settings-changed")
diff --git a/pitivi/ui/timelinecontrols.py b/pitivi/ui/timelinecontrols.py
index e83d545..7e14647 100644
--- a/pitivi/ui/timelinecontrols.py
+++ b/pitivi/ui/timelinecontrols.py
@@ -1,6 +1,5 @@
import gtk
from pitivi.receiver import receiver, handler
-import pitivi.stream as stream
from gettext import gettext as _
from common import LAYER_HEIGHT_EXPANDED, LAYER_SPACING
diff --git a/pitivi/ui/track.py b/pitivi/ui/track.py
index 24f506a..bab0003 100644
--- a/pitivi/ui/track.py
+++ b/pitivi/ui/track.py
@@ -1,6 +1,5 @@
from pitivi.ui.zoominterface import Zoomable
from pitivi.ui.trackobject import TrackObject
-from pitivi.timeline.track import TrackEffect
from pitivi.receiver import receiver, handler
from pitivi.ui.common import LAYER_HEIGHT_EXPANDED, LAYER_HEIGHT_COLLAPSED, LAYER_SPACING
import goocanvas
diff --git a/pitivi/ui/trackobject.py b/pitivi/ui/trackobject.py
index 70b91e9..72a39da 100644
--- a/pitivi/ui/trackobject.py
+++ b/pitivi/ui/trackobject.py
@@ -11,7 +11,6 @@ from pitivi.receiver import receiver, handler
from view import View
import controller
from zoominterface import Zoomable
-from pitivi.timeline.track import TrackError
from pitivi.timeline.timeline import SELECT, SELECT_ADD, UNSELECT, \
SELECT_BETWEEN, MoveContext, TrimStartContext, TrimEndContext
from preview import Preview
@@ -22,8 +21,6 @@ from common import LAYER_SPACING, unpack_cairo_pattern, unpack_cairo_gradient
from pitivi.ui.point import Point
from pitivi.ui.prefs import PreferencesDialog
from pitivi.settings import GlobalSettings
-from pitivi.stream import AudioStream, VideoStream
-import ges
LEFT_SIDE = gtk.gdk.Cursor(gtk.gdk.LEFT_SIDE)
RIGHT_SIDE = gtk.gdk.Cursor(gtk.gdk.RIGHT_SIDE)
@@ -486,7 +483,6 @@ class TrackObject(View, goocanvas.Group, Zoomable):
self.timeline.selected.append(elem)
for elem in element:
if elem == self.element:
- print elem.get_timeline_object().get_property("priority"), "la pute !!"
self.selection_indicator.props.visibility = goocanvas.ITEM_VISIBLE
elem.selected = True
elif self.element.selected == False:
diff --git a/pitivi/ui/viewer.py b/pitivi/ui/viewer.py
index c630150..cb9cad2 100644
--- a/pitivi/ui/viewer.py
+++ b/pitivi/ui/viewer.py
@@ -30,12 +30,8 @@ import ges
from gettext import gettext as _
-from pitivi.action import ViewAction
-
-from pitivi.stream import VideoStream
from pitivi.utils import time_to_string, Seeker
from pitivi.log.loggable import Loggable
-from pitivi.pipeline import PipelineError
from pitivi.ui.common import SPACING, hex_to_rgb
from pitivi.settings import GlobalSettings
from pitivi.ui.dynamic import TimeWidget
@@ -187,7 +183,6 @@ class PitiviViewer(gtk.VBox, Loggable):
state_change = pending == gst.STATE_VOID_PENDING
if state_change:
- self.internal.currentStateCb(self.pipeline, new)
self._currentStateCb(new)
def _disconnectFromPipeline(self):
@@ -247,7 +242,7 @@ class PitiviViewer(gtk.VBox, Loggable):
self.emit("activate-playback-controls", True)
def _getDefaultAction(self):
- return ViewAction()
+ return
def _externalWindowDeleteCb(self, window, event):
self.dock()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]