Beispiel #1
0
    def _pipelineInit(self, factory, sbin):
        self.spacing = 0

        self.audioSink = ExtractionSink()
        self.audioSink.set_stopped_cb(self._finishSegment)
        # This audiorate element ensures that the extracted raw-data
        # timeline matches the timestamps used for seeking, even if the
        # audio source has gaps or other timestamp abnormalities.
        audiorate = gst.element_factory_make("audiorate")
        conv = gst.element_factory_make("audioconvert")
        q = gst.element_factory_make("queue")
        self.audioPipeline = pipeline({
            sbin: audiorate,
            audiorate: conv,
            conv: q,
            q: self.audioSink,
            self.audioSink: None})
        bus = self.audioPipeline.get_bus()
        bus.add_signal_watch()
        bus.connect("message::error", self._busMessageErrorCb)
        self._donecb_id = bus.connect("message::async-done",
                                      self._busMessageAsyncDoneCb)

        self.audioPipeline.set_state(gst.STATE_PAUSED)
Beispiel #2
0
class RandomAccessAudioExtractor(RandomAccessExtractor):

    """
    L{Extractor} for random access audio streams.

    Closely inspired by L{RandomAccessAudioPreviewer}.

    """

    def __init__(self, factory, stream_):
        self._queue = deque()
        RandomAccessExtractor.__init__(self, factory, stream_)
        self._ready = False

    def _pipelineInit(self, factory, sbin):
        self.spacing = 0

        self.audioSink = ExtractionSink()
        self.audioSink.set_stopped_cb(self._finishSegment)
        # This audiorate element ensures that the extracted raw-data
        # timeline matches the timestamps used for seeking, even if the
        # audio source has gaps or other timestamp abnormalities.
        audiorate = gst.element_factory_make("audiorate")
        conv = gst.element_factory_make("audioconvert")
        q = gst.element_factory_make("queue")
        self.audioPipeline = pipeline({
            sbin: audiorate,
            audiorate: conv,
            conv: q,
            q: self.audioSink,
            self.audioSink: None})
        bus = self.audioPipeline.get_bus()
        bus.add_signal_watch()
        bus.connect("message::error", self._busMessageErrorCb)
        self._donecb_id = bus.connect("message::async-done",
                                      self._busMessageAsyncDoneCb)

        self.audioPipeline.set_state(gst.STATE_PAUSED)
        # The audiopipeline.set_state() method does not take effect
        # immediately, but the extraction process (and in particular
        # self._startSegment) will not work properly until
        # self.audioPipeline reaches the desired state (STATE_PAUSED).
        # To ensure that this is the case, we wait until the ASYNC_DONE
        # message is received before setting self._ready = True,
        # which enables extraction to proceed.

    def _busMessageErrorCb(self, bus, message):
        error, debug = message.parse_error()
        self.error("Event bus error: %s; %s", error, debug)

        return gst.BUS_PASS

    def _busMessageAsyncDoneCb(self, bus, message):
        self.debug("Pipeline is ready for seeking")
        bus.disconnect(self._donecb_id)  # Don't call me again
        self._ready = True
        if self._queue:  # Someone called .extract() before we were ready
            self._run()

    def _startSegment(self, timestamp, duration):
        self.debug("processing segment with timestamp=%i and duration=%i",
                   timestamp, duration)
        res = self.audioPipeline.seek(1.0,
            gst.FORMAT_TIME,
            gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
            gst.SEEK_TYPE_SET, timestamp,
            gst.SEEK_TYPE_SET, timestamp + duration)
        if not res:
            self.warning("seek failed %s", timestamp)
        self.audioPipeline.set_state(gst.STATE_PLAYING)

        return res

    def _finishSegment(self):
        self.audioSink.extractee.finalize()
        self.audioSink.reset()
        self._queue.popleft()
        # If there's more to do, keep running
        if self._queue:
            self._run()

    def extract(self, extractee, start, duration):
        stopped = not self._queue
        self._queue.append((extractee, start, duration))
        if stopped and self._ready:
            self._run()
        # if self._ready is False, self._run() will be called from
        # self._busMessageDoneCb().

    def _run(self):
        # Control flows in a cycle:
        # _run -> _startSegment -> busMessageSegmentDoneCb -> _finishSegment -> _run
        # This forms a loop that extracts an entire segment (i.e. satisfies an
        # extract request) in each cycle. The cycle
        # runs until the queue of Extractees empties.  If the cycle is not
        # running, extract() will kick it off again.
        extractee, start, duration = self._queue[0]
        self.audioSink.set_extractee(extractee)
        self._startSegment(start, duration)