* morituri/common/gstreamer.py:
Add a cvar to stop going to playing. * morituri/image/image.py: Convert AudioLengthTask to GstPipelineTask. * morituri/test/test_image_image.py: Adapt to new typefind error we run in.
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2011-05-24 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* morituri/common/gstreamer.py:
|
||||
Add a cvar to stop going to playing.
|
||||
* morituri/image/image.py:
|
||||
Convert AudioLengthTask to GstPipelineTask.
|
||||
* morituri/test/test_image_image.py:
|
||||
Adapt to new typefind error we run in.
|
||||
|
||||
2011-05-23 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* morituri/common/gstreamer.py:
|
||||
|
||||
@@ -40,9 +40,13 @@ class GstPipelineTask(task.Task):
|
||||
|
||||
@cvar gst: the GStreamer module, so code does not have to import gst
|
||||
as a module in code everywhere to avoid option stealing.
|
||||
@var playing: whether the pipeline should be set to playing after
|
||||
paused. Some pipelines don't need to play for a task
|
||||
to be done (for example, querying length)
|
||||
"""
|
||||
|
||||
gst = None
|
||||
playing = True
|
||||
|
||||
### task.Task implementations
|
||||
def start(self, runner):
|
||||
@@ -100,8 +104,9 @@ class GstPipelineTask(task.Task):
|
||||
self.debug('set pipeline to PLAYING')
|
||||
return False
|
||||
|
||||
self.debug('scheduling setting pipeline to PLAYING')
|
||||
self.runner.schedule(0, playLater)
|
||||
if self.playing:
|
||||
self.debug('scheduling setting pipeline to PLAYING')
|
||||
self.runner.schedule(0, playLater)
|
||||
|
||||
def stop(self):
|
||||
self.debug('stopping')
|
||||
|
||||
@@ -26,7 +26,7 @@ Wrap on-disk CD images based on the .cue file.
|
||||
|
||||
import os
|
||||
|
||||
from morituri.common import task, log, common
|
||||
from morituri.common import task, log, common, gstreamer
|
||||
from morituri.image import cue, table
|
||||
|
||||
class Image(object, log.Loggable):
|
||||
@@ -133,17 +133,19 @@ class AccurateRipChecksumTask(task.MultiSeparateTask):
|
||||
self.checksums = [t.checksum for t in self.tasks]
|
||||
task.MultiSeparateTask.stop(self)
|
||||
|
||||
class AudioLengthTask(task.Task):
|
||||
class AudioLengthTask(gstreamer.GstPipelineTask):
|
||||
"""
|
||||
I calculate the length of a track in audio frames.
|
||||
|
||||
@ivar length: length of the decoded audio file, in audio frames.
|
||||
"""
|
||||
logCategory = 'AudioLengthTask'
|
||||
|
||||
description = 'Getting length of audio track'
|
||||
length = None
|
||||
|
||||
playing = False
|
||||
|
||||
|
||||
def __init__(self, path):
|
||||
"""
|
||||
@type path: unicode
|
||||
@@ -152,55 +154,32 @@ class AudioLengthTask(task.Task):
|
||||
|
||||
self._path = path
|
||||
|
||||
def start(self, runner):
|
||||
# here to avoid import gst eating our options
|
||||
import gst
|
||||
|
||||
task.Task.start(self, runner)
|
||||
self._pipeline = gst.parse_launch('''
|
||||
def getPipelineDesc(self):
|
||||
return '''
|
||||
filesrc location="%s" !
|
||||
decodebin ! audio/x-raw-int !
|
||||
fakesink name=sink''' %
|
||||
common.quoteParse(self._path).encode('utf-8'))
|
||||
self._bus = self._pipeline.get_bus()
|
||||
self._bus.add_signal_watch()
|
||||
self._bus.connect('message::error', self._error_cb)
|
||||
|
||||
self.debug('pausing')
|
||||
self._pipeline.set_state(gst.STATE_PAUSED)
|
||||
self.debug('waiting for ASYNC_DONE or ERROR')
|
||||
message = self._bus.timed_pop_filtered(gst.CLOCK_TIME_NONE,
|
||||
gst.MESSAGE_ASYNC_DONE | gst.MESSAGE_ERROR)
|
||||
if message.type == gst.MESSAGE_ERROR:
|
||||
self._error_cb(self._bus, message)
|
||||
self._pipeline.set_state(gst.STATE_NULL)
|
||||
return
|
||||
fakesink name=sink''' % \
|
||||
common.quoteParse(self._path).encode('utf-8')
|
||||
|
||||
def paused(self):
|
||||
self.debug('query duration')
|
||||
sink = self._pipeline.get_by_name('sink')
|
||||
sink = self.pipeline.get_by_name('sink')
|
||||
assert sink, 'Error constructing pipeline'
|
||||
|
||||
try:
|
||||
length, qformat = sink.query_duration(gst.FORMAT_DEFAULT)
|
||||
except gst.QueryError:
|
||||
length, qformat = sink.query_duration(self.gst.FORMAT_DEFAULT)
|
||||
except self.gst.QueryError:
|
||||
self.info('failed to query duration of %r' % self._path)
|
||||
raise
|
||||
|
||||
# wavparse 0.10.14 returns in bytes
|
||||
if qformat == gst.FORMAT_BYTES:
|
||||
if qformat == self.gst.FORMAT_BYTES:
|
||||
self.debug('query returned in BYTES format')
|
||||
length /= 4
|
||||
self.debug('total length of %r in samples: %d', self._path, length)
|
||||
self.length = length
|
||||
self._pipeline.set_state(gst.STATE_NULL)
|
||||
|
||||
self.stop()
|
||||
|
||||
def _error_cb(self, bus, msg):
|
||||
error, debug = msg.parse_error()
|
||||
self.debug('Got GStreamer error: %r, debug: %r' % (
|
||||
error.message, debug))
|
||||
self.setAndRaiseException(error)
|
||||
self.pipeline.set_state(self.gst.STATE_NULL)
|
||||
self.stop()
|
||||
|
||||
class ImageVerifyTask(task.MultiSeparateTask):
|
||||
|
||||
@@ -10,7 +10,7 @@ gobject.threads_init()
|
||||
import gst
|
||||
|
||||
from morituri.image import image
|
||||
from morituri.common import task, common, log
|
||||
from morituri.common import task, common, log, gstreamer
|
||||
from morituri.test import common as tcommon
|
||||
|
||||
log.init()
|
||||
@@ -93,11 +93,12 @@ class AudioLengthPathTestCase(tcommon.TestCase):
|
||||
t = image.AudioLengthTask(path)
|
||||
e = self.assertRaises(task.TaskException, self.runner.run,
|
||||
t, verbose=False)
|
||||
self.failUnless(isinstance(e.exception, gst.GError),
|
||||
"%r is not a gst.GError" % e.exceptionMessage)
|
||||
self.assertEquals(e.exception.domain, gst.STREAM_ERROR)
|
||||
self.failUnless(isinstance(e.exception, gstreamer.GstException),
|
||||
"%r is not a gstreamer.GstException" % e.exceptionMessage)
|
||||
self.assertEquals(e.exception.gerror.domain, gst.STREAM_ERROR)
|
||||
# our empty file triggers TYPE_NOT_FOUND
|
||||
self.assertEquals(e.exception.code, gst.STREAM_ERROR_TYPE_NOT_FOUND)
|
||||
self.assertEquals(e.exception.gerror.code,
|
||||
gst.STREAM_ERROR_TYPE_NOT_FOUND)
|
||||
os.unlink(path)
|
||||
|
||||
class NormalAudioLengthPathTestCase(AudioLengthPathTestCase):
|
||||
|
||||
Reference in New Issue
Block a user