229
235
compatible_stream = None
230
236
self.debug("stream %r", output_stream)
231
238
if output_stream is not None:
232
self.debug("streams %r", self.output_streams)
233
for stream in self.output_streams:
234
if output_stream.isCompatible(stream):
235
compatible_stream = stream
239
self.debug("output_streams:%r", self.output_streams)
240
stream_map = match_stream_groups_map([output_stream], self.output_streams)
241
if output_stream not in stream_map:
242
self.warning("stream not available in map %r", stream_map)
243
raise ObjectFactoryError("can not create stream")
238
if compatible_stream is None:
239
raise ObjectFactoryError('can not create stream')
245
compatible_stream = stream_map[output_stream]
241
247
if self.max_bins != -1 and self.current_bins == self.max_bins:
242
248
raise ObjectFactoryError('no bins available')
244
250
bin = self._makeBin(compatible_stream)
245
251
bin.factory = self
246
if not bin in self.bins:
247
self.bins.append(bin)
252
self.bins.append(bin)
248
253
self.current_bins += 1
249
254
self.emit('bin-created', bin)
253
def _makeBin(self, output_stream=None):
254
raise NotImplementedError()
256
258
def releaseBin(self, bin):
258
260
Release a bin created with L{makeBin}.
263
265
bin.set_state(gst.STATE_NULL)
264
266
self._releaseBin(bin)
267
self.debug("Finally releasing %r", bin)
265
268
self.current_bins -= 1
267
self.bins.remove(bin)
269
self.bins.remove(bin)
268
270
self.emit('bin-released', bin)
273
def _makeBin(self, output_stream):
274
if output_stream is None:
275
return self._makeDefaultBin()
277
return self._makeStreamBin(output_stream)
279
def _makeDefaultBin(self):
281
Return a bin that decodes all the available streams.
283
This is generally used to get an overview of the source media before
284
splitting it in separate streams.
286
bin = gst.Bin("%s" % self.name)
287
src = gst.element_make_from_uri(gst.URI_SRC, self.uri)
289
dbin = gst.element_factory_make("decodebin2")
291
dbin = gst.element_factory_make("decodebin")
295
dbin.connect("new-decoded-pad", self._binNewDecodedPadCb, bin)
296
dbin.connect("removed-decoded-pad", self._binRemovedDecodedPadCb, bin)
301
def _binNewDecodedPadCb(self, unused_dbin, pad, unused_is_last, bin):
302
ghost_pad = gst.GhostPad(pad.get_name(), pad)
303
ghost_pad.set_active(True)
304
bin.add_pad(ghost_pad)
306
def _binRemovedDecodedPadCb(self, unused_dbin, pad, bin):
307
ghost_pad = bin.get_pad(pad.get_name())
308
bin.remove_pad(ghost_pad)
271
310
def _releaseBin(self, bin):
272
# default implementation does nothing
312
# bin is a bin returned from makeDefaultBin
313
bin.decodebin.disconnect_by_func(self._binNewDecodedPadCb)
314
bin.decodebin.disconnect_by_func(self._binRemovedDecodedPadCb)
316
# bin is a stream bin
317
bin.decodebin.disconnect_by_func(self._singlePadAddedCb)
318
bin.decodebin.disconnect_by_func(self._singlePadRemovedCb)
322
if hasattr(bin, "volume"):
323
# only audio bins have a volume element
324
for elt in [bin.aconv, bin.ares, bin.volume]:
325
elt.set_state(gst.STATE_NULL)
331
if hasattr(bin, "ghostpad"):
332
# singledecodebin found something on this pad
333
bin.ghostpad.set_active(False)
334
bin.remove_pad(bin.ghostpad)
337
def _makeStreamBin(self, output_stream):
338
self.debug("output_stream:%r", output_stream)
340
b.decodebin = self.singleDecodeBinClass(uri=self.uri, caps=output_stream.caps,
341
stream=output_stream)
342
b.decodebin.connect("pad-added", self._singlePadAddedCb, b)
343
b.decodebin.connect("pad-removed", self._singlePadRemovedCb, b)
345
if isinstance(output_stream, AudioStream):
346
self.debug("Adding volume element")
347
# add a volume element
348
b.aconv = gst.element_factory_make("audioconvert", "internal-aconv")
349
b.ares = gst.element_factory_make("audioresample", "internal-audioresample")
350
b.volume = gst.element_factory_make("volume", "internal-volume")
351
b.add(b.volume, b.ares, b.aconv)
352
gst.element_link_many(b.aconv, b.ares, b.volume)
353
b.aconv.sync_state_with_parent()
354
b.ares.sync_state_with_parent()
355
b.volume.sync_state_with_parent()
360
def _singlePadAddedCb(self, dbin, pad, topbin):
361
self.debug("dbin:%r, pad:%r, topbin:%r", dbin, pad, topbin)
362
if hasattr(topbin, "volume"):
363
pad.link(topbin.aconv.get_pad("sink"))
364
topbin.ghostpad = gst.GhostPad("src", topbin.volume.get_pad("src"))
366
topbin.ghostpad = gst.GhostPad("src", pad)
367
topbin.ghostpad.set_active(True)
368
topbin.add_pad(topbin.ghostpad)
370
def _singlePadRemovedCb(self, dbin, pad, topbin):
371
self.debug("dbin:%r, pad:%r, topbin:%r", dbin, pad, topbin)
372
topbin.remove_pad(topbin.ghostpad)
374
if hasattr(topbin, "volume"):
375
pad.unlink(topbin.aconv.get_pad("sink"))
376
for elt in [topbin.volume, topbin.aconv, topbin.ares]:
377
elt.set_state(gst.STATE_NULL)
378
for elt in [topbin.volume, topbin.aconv, topbin.ares]:
275
384
def addInputStream(self, stream):
276
385
raise AssertionError("source factories can't have input streams")
534
639
return offset_length
536
641
abs_offset_length = property(_getAbsOffsetLength)
538
class URISourceFactoryMixin(object):
540
Abstract mixin for sources that access an URI.
543
# make this an attribute to inject it from tests
544
singleDecodeBinClass = SingleDecodeBin
546
def __init__(self, uri):
548
self.displayname = os.path.basename(unquote(uri))
550
def _makeBin(self, output_stream):
551
if output_stream is None:
552
return self._makeDefaultBin()
554
return self._makeStreamBin(output_stream)
556
def _makeDefaultBin(self):
558
Return a bin that decodes all the available streams.
560
This is generally used to get an overview of the source media before
561
splitting it in separate streams.
563
bin = gst.Bin("%s" % self.name)
564
src = gst.element_make_from_uri(gst.URI_SRC, self.uri)
566
dbin = gst.element_factory_make("decodebin2")
568
dbin = gst.element_factory_make("decodebin")
572
dbin.connect("new-decoded-pad", self._binNewDecodedPadCb, bin)
573
dbin.connect("removed-decoded-pad", self._binRemovedDecodedPadCb, bin)
578
def _binNewDecodedPadCb(self, unused_dbin, pad, unused_is_last, bin):
579
ghost_pad = gst.GhostPad(pad.get_name(), pad)
580
ghost_pad.set_active(True)
581
bin.add_pad(ghost_pad)
583
def _binRemovedDecodedPadCb(self, unused_dbin, pad, bin):
584
ghost_pad = bin.get_pad(pad.get_name())
585
bin.remove_pad(ghost_pad)
587
def _makeStreamBin(self, output_stream):
588
return self.singleDecodeBinClass(uri=self.uri, caps=output_stream.caps,
589
stream=output_stream)
591
class LiveURISourceFactory(URISourceFactoryMixin, LiveSourceFactory):
593
Factory for live sources accessible at a given URI.
595
@see L{LiveSourceFactory}.
597
def __init__(self, uri, name='', displayname='', default_duration=None):
598
URISourceFactoryMixin.__init__(self, uri)
599
LiveSourceFactory.__init__(self, name, displayname, default_duration)