msmith - in flumotion/trunk: .
flumotion/component/producers/playlist
flumotion-commit at lists.fluendo.com
flumotion-commit at lists.fluendo.com
Mon May 14 18:07:15 CEST 2007
Author: msmith
Date: Mon May 14 18:07:12 2007
New Revision: 4942
Modified:
flumotion/trunk/ChangeLog
flumotion/trunk/flumotion/component/producers/playlist/playlist.py
flumotion/trunk/flumotion/component/producers/playlist/playlistparser.py
Log:
* flumotion/component/producers/playlist/playlist.py:
* flumotion/component/producers/playlist/playlistparser.py:
Make scheduling more consistent with design. Remove a race or two.
Modified: flumotion/trunk/ChangeLog
==============================================================================
--- flumotion/trunk/ChangeLog (original)
+++ flumotion/trunk/ChangeLog Mon May 14 18:07:12 2007
@@ -1,3 +1,9 @@
+2007-05-14 Michael Smith <msmith at fluendo.com>
+
+ * flumotion/component/producers/playlist/playlist.py:
+ * flumotion/component/producers/playlist/playlistparser.py:
+ Make scheduling more consistent with design. Remove a race or two.
+
2007-05-14 Andy Wingo <wingo at pobox.com>
* flumotion/component/base/scheduler.py (Event.__init__): Rework a
Modified: flumotion/trunk/flumotion/component/producers/playlist/playlist.py
==============================================================================
--- flumotion/trunk/flumotion/component/producers/playlist/playlist.py (original)
+++ flumotion/trunk/flumotion/component/producers/playlist/playlist.py Mon May 14 18:07:12 2007
@@ -236,13 +236,19 @@
start = 0
if self._hasVideo and item.hasVideo:
+ self.debug("Adding video source with start %d, duration %d, "
+ "offset %d", start, item.duration, item.offset)
item.vsrc = file_gnl_src(None, item.uri, self.videocaps,
start, item.duration, item.offset, 0)
self.videocomp.add(item.vsrc)
+ self.debug("Added")
if self._hasAudio and item.hasAudio:
+ self.debug("Adding audio source with start %d, duration %d, "
+ "offset %d", start, item.duration, item.offset)
item.asrc = file_gnl_src(None, item.uri, self.audiocaps,
start, item.duration, item.offset, 0)
self.audiocomp.add(item.asrc)
+ self.debug("Done scheduling")
def unscheduleItem(self, item):
self.debug("Unscheduling item at uri %s", item.uri)
@@ -273,6 +279,12 @@
self._createDefaultSources()
+ self.connect_feeders(pipeline)
+ return pipeline
+
+ def do_start(self, clocking):
+ self.link()
+
self.playlist = playlistparser.Playlist(self)
try:
if self._playlistfile:
@@ -280,11 +292,6 @@
except fxml.ParserError, e:
self.warning("Failed to parse playlist file: %r", e)
- self.connect_feeders(pipeline)
- return pipeline
-
- def do_start(self, clocking):
- self.link()
return defer.succeed(None)
def do_stop(self):
Modified: flumotion/trunk/flumotion/component/producers/playlist/playlistparser.py
==============================================================================
--- flumotion/trunk/flumotion/component/producers/playlist/playlistparser.py (original)
+++ flumotion/trunk/flumotion/component/producers/playlist/playlistparser.py Mon May 14 18:07:12 2007
@@ -46,7 +46,8 @@
return gnlsrc
class PlaylistItem(object, log.Loggable):
- def __init__(self, timestamp, uri, offset, duration):
+ def __init__(self, id, timestamp, uri, offset, duration):
+ self.id = id
self.timestamp = timestamp
self.uri = uri
self.offset = offset
@@ -62,6 +63,23 @@
self.asrc = None
self.next = None
+ self.prev = None
+
+ def setDuration(self, duration):
+ self.duration = duration
+ if self.asrc:
+ self.asrc.props.duration = duration
+ self.asrc.props.media_duration = duration
+ if self.vsrc:
+ self.vsrc.props.duration = duration
+ self.vsrc.props.media_duration = duration
+
+ def setTimestamp(self, timestamp):
+ self.timestamp = timestamp
+ if self.asrc:
+ self.asrc.props.start = timestamp
+ if self.vsrc:
+ self.vsrc.props.start = timestamp
class Playlist(object, log.Loggable):
def __init__(self, producer):
@@ -69,67 +87,106 @@
Create an initially empty playlist
"""
self.items = None # PlaylistItem linked list
+ self._itemsById = {}
self.producer = producer
self._pending_items = []
self._discovering = False
- def addItem(self, timestamp, uri, offset, duration, hasAudio, hasVideo):
+ def _getCurrentItem(self):
+ # TODO: improve this!
+ return None
+
+ def removeItems(self, id):
+ current = self._getCurrentItem()
+
+ items = self._itemsById[id]
+ for item in items:
+ if (current and item.timestamp < current.timestamp +
+ current.duration):
+ self.debug("Not removing current item!")
+ continue
+ if item.prev:
+ item.prev.next = item.next
+ if item.next:
+ item.next.prev = item.prev
+ self.producer.unscheduleItem(item)
+
+ del self._itemsById[id]
+
+
+ def addItem(self, id, timestamp, uri, offset, duration, hasAudio, hasVideo):
"""
Add an item to the playlist.
The duration of previous and this entry may be adjusted to make it fit.
"""
- newitem = PlaylistItem(timestamp, uri, offset, duration)
+ current = self._getCurrentItem()
+ if current and timestamp < current.timestamp + current.duration:
+ self.warning("New object at uri %s starts during current object, "
+ "cannot add")
+ return
+
+ newitem = PlaylistItem(id, timestamp, uri, offset, duration)
newitem.hasAudio = hasAudio
newitem.hasVideo = hasVideo
+ if id in self._itemsById:
+ self._itemsById[id].append(newitem)
+ else:
+ self._itemsById[id] = [newitem]
+
+ # prev starts strictly before the new item
+ # next starts after the new item, and ends after the end of the new item
prev = next = None
item = self.items
while item:
if item.timestamp < newitem.timestamp:
prev = item
- elif (not next and item.timestamp > newitem.timestamp and
- newitem.timestamp + newitem.duration > item.timestamp):
+ else:
+ break
+ item = item.next
+
+ if item:
+ item = item.next
+ while item:
+ if (item.timestamp + item.duration > newitem.timestamp):
next = item
break
item = item.next
- if prev and next and prev.next != next:
- # Then things between prev and next are to be deleted. Do so.
+ if prev:
+ # Then things between prev and next (next might be None) are to be
+ # deleted. Do so.
cur = prev.next
while cur != next:
self.producer.unscheduleItem(cur)
cur = cur.next
- elif prev and not next:
- cur = prev.next
- while cur:
- self.producer.unscheduleItem(cur)
- cur = cur.next
+ # update links.
if prev:
prev.next = newitem
+ newitem.prev = prev
else:
self.items = newitem
if next:
newitem.next = next
+ next.prev = newitem
# Duration adjustments -> Reflect into gnonlin timeline
if prev and prev.timestamp + prev.duration > newitem.timestamp:
self.debug("Changing duration of previous item from %d to %d",
prev.duration, newitem.timestamp - prev.timestamp)
- prev.duration = newitem.timestamp - prev.timestamp
- if prev.asrc:
- prev.asrc.props.duration = prev.duration
- prev.asrc.props.media_duration = prev.duration
- if prev.vsrc:
- prev.vsrc.props.duration = prev.duration
- prev.vsrc.props.media_duration = prev.duration
+ item.setDuration(newitem.timestamp - prev.timestamp)
+
if next and newitem.timestamp + newitem.duration > next.timestamp:
- self.debug("Changing duration of new item from %d to %d to fit",
- newitem.duration, next.timestamp - newitem.timestamp)
- newitem.duration = next.timestamp - newitem.timestamp
+ self.debug("Changing timestamp of next item from %d to %d to fit",
+ newitem.timestamp, newitem.timestamp + newitem.duration)
+ ts = newitem.timestamp + newitem.duration
+ duration = next.duration - (ts - next.timestamp)
+ next.setTimestamp(ts)
+ next.setDuration(duration)
# Then we need to actually add newitem into the gnonlin timeline
self.producer.scheduleItem(newitem)
@@ -149,7 +206,11 @@
file = StringIO(data)
self.parseFile(file)
- def parseFile(self, file):
+ def replaceFile(self, file, id):
+ self.removeItems(id)
+ self.parseFile(file, id)
+
+ def parseFile(self, file, id=None):
"""
Parse a playlist file. Adds the contents of the file to the existing
playlist, overwriting any existing entries for the same time period.
@@ -167,7 +228,7 @@
if child.nodeType == Node.ELEMENT_NODE and \
child.nodeName == 'entry':
self.debug("Parsing entry")
- self._parsePlaylistEntry(parser, child)
+ self._parsePlaylistEntry(parser, child, id)
# Now launch the discoverer for any pending items
if not self._discovering:
@@ -185,6 +246,7 @@
timestamp = item[1]
duration = item[2]
offset = item[3]
+ id = item[4]
hasA = disc.is_audio
hasV = disc.is_video
@@ -197,7 +259,8 @@
offset = 0
if duration > 0:
- self.addItem(timestamp, uri, offset, duration, hasA, hasV)
+ self.addItem(id, timestamp, uri, offset, duration,
+ hasA, hasV)
else:
self.warning("Duration of item is zero, not adding")
else:
@@ -221,7 +284,7 @@
disc.connect('discovered', _discovered)
disc.discover()
- def _parsePlaylistEntry(self, parser, entry):
+ def _parsePlaylistEntry(self, parser, entry, id):
mandatory = ['filename', 'time']
optional = ['duration', 'offset']
@@ -236,7 +299,7 @@
timestamp = self._parseTimestamp(timestamp)
- self._pending_items.append((filename, timestamp, duration, offset))
+ self._pending_items.append((filename, timestamp, duration, offset, id))
def _parseTimestamp(self, ts):
# Take TS in YYYY-MM-DDThh:mm:ssZ format, return timestamp in
More information about the flumotion-commit
mailing list