From 71f58a44b4093c3657e8ae8671c28e4864717270 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 20 Oct 2006 09:27:43 +0000 Subject: [PATCH] examples/: Closes #362290 and #362272 Original commit message from CVS: * examples/audioconcat.py: * examples/cp.py: Port to 0.10 by Jason Gerard DeRose Closes #362290 and #362272 * examples/bps.py: Indentation fixes by Jason Gerard DeRose Closes #362011 Also small fix for Usage string --- ChangeLog | 11 ++ examples/audioconcat.py | 268 +++++++++++++++++++++++++--------------- examples/bps.py | 4 +- examples/cp.py | 25 +++- 4 files changed, 198 insertions(+), 110 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ae8f252ab..14caf8f6b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-10-20 Edward Hervey + + * examples/audioconcat.py: + * examples/cp.py: + Port to 0.10 by Jason Gerard DeRose + Closes #362290 and #362272 + * examples/bps.py: + Indentation fixes by Jason Gerard DeRose + Closes #362011 + Also small fix for Usage string + 2006-10-16 Tim-Philipp Müller * gst/gst.defs: diff --git a/examples/audioconcat.py b/examples/audioconcat.py index 3797a31b1f..306b24f68e 100644 --- a/examples/audioconcat.py +++ b/examples/audioconcat.py @@ -2,129 +2,191 @@ # -*- Mode: Python -*- # vi:si:et:sw=4:sts=4:ts=4 -# audio concat tool -# takes in one or more audio files and creates one audio file of the combination - +# audioconcat.py - Concatenates multiple audio files to single ogg/vorbis file # Uses the gnonlin elements (http://gnonlin.sf.net/) +# Copyright (C) 2005 Edward Hervey +# 2006 Jason Gerard DeRose +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# -import os import sys + import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') import gst +from gst.extend.discoverer import Discoverer -from gstfile import Discoverer, time_to_string -class AudioSource(gst.Bin): - """A bin for audio sources with proper audio converters""" - def __init__(self, filename, caps): - gst.Bin.__init__(self) - self.filename = filename - self.outcaps = caps +class AudioDec(gst.Bin): + '''Decodes audio file, outputs at specified caps''' - self.filesrc = gst.element_factory_make("filesrc") - self.filesrc.set_property("location", self.filename) - self.dbin = gst.element_factory_make("decodebin") - self.ident = gst.element_factory_make("identity") - self.audioconvert = gst.element_factory_make("audioconvert") - self.audioscale = gst.element_factory_make("audioscale") - - self.add_many(self.filesrc, self.dbin, self.ident, - self.audioconvert, self.audioscale) - self.filesrc.link(self.dbin) - self.audioconvert.link(self.audioscale) - self.audioscale.link(self.ident, caps) - self.add_ghost_pad(self.ident.get_pad("src"), "src") - - self.dbin.connect("new-decoded-pad", self._new_decoded_pad_cb) + def __init__(self, location, caps): + gst.Bin.__init__(self) - def _new_decoded_pad_cb(self, dbin, pad, is_last): - if not "audio" in pad.get_caps().to_string(): - return - pad.link(self.audioconvert.get_pad("sink")) + # Create elements + src = gst.element_factory_make('filesrc') + dec = gst.element_factory_make('decodebin') + conv = gst.element_factory_make('audioconvert') + rsmpl = gst.element_factory_make('audioresample') + ident = gst.element_factory_make('identity') -gobject.type_register(AudioSource) + # Set 'location' property on filesrc + src.set_property('location', location) -class AudioConcat(gst.Thread): - """A Gstreamer thread that concatenates a series of audio files to another audio file""" + # Connect handler for 'new-decoded-pad' signal + dec.connect('new-decoded-pad', self.__on_new_decoded_pad) - def __init__(self, infiles, outfile, audioenc="rawvorbisenc", muxer="oggmux"): - gst.Thread.__init__(self) - self.infiles = infiles - self.outfile = outfile - self.audioenc = gst.element_factory_make(audioenc) - if not self.audioenc: - raise NameError, str(audioenc + " audio encoder is not available") - self.muxer = gst.element_factory_make(muxer) - if not self.muxer: - raise NameError, str(muxer + " muxer is not available") - self.filesink = gst.element_factory_make("filesink") - self.filesink.set_property("location", self.outfile) + # Add elements to bin + self.add(src, dec, conv, rsmpl, ident) - self.timeline = gst.element_factory_make("gnltimeline") - self.audiocomp = gst.element_factory_make("gnlcomposition", "audiocomp") + # Link *some* elements + # This is completed in self.__on_new_decoded_pad() + src.link(dec) + conv.link(rsmpl) + rsmpl.link(ident, caps) - self.audioconvert = gst.element_factory_make("audioconvert") - self.add_many(self.timeline, self.audioconvert, - self.audioenc, self.muxer, self.filesink) + # Reference used in self.__on_new_decoded_pad() + self.__apad = conv.get_pad('sink') - ## identity perfect stream check ! - identity = gst.element_factory_make("identity") - identity.set_property("check-perfect", True) - self.add(identity) - - #self.audioconvert.link(self.audioenc) - if not self.audioconvert.link(identity): - print "couldn't link audioconv -> ident" - if not identity.link(self.audioenc): - print "couldn't link ident -> audioenc" - self.audioenc.link(self.muxer) - self.muxer.link(self.filesink) + # Add ghost pad + self.add_pad(gst.GhostPad('src', ident.get_pad('src'))) - self.timeline.add(self.audiocomp) - caps = gst.caps_from_string("audio/x-raw-int,channels=2,rate=44100,depth=16") - pos = 0L - for infile in self.infiles: - d = Discoverer(infile) - if not d.audiolength: - continue - print "file", infile, "has length", time_to_string(d.audiolength) - asource = AudioSource(infile, caps) - gnlsource = gst.element_factory_make("gnlsource") - gnlsource.set_property("element", asource) - gnlsource.set_property("media-start", 0L) - gnlsource.set_property("media-stop", d.audiolength) - gnlsource.set_property("start", pos) - gnlsource.set_property("stop", pos + d.audiolength) - self.audiocomp.add(gnlsource) - pos += d.audiolength + def __on_new_decoded_pad(self, element, pad, last): + caps = pad.get_caps() + name = caps[0].get_name() + print '\n__on_new_decoded_pad:', name + if 'audio' in name: + if not self.__apad.is_linked(): # Only link once + pad.link(self.__apad) - self.timeline.get_pad("src_audiocomp").link(self.audioconvert.get_pad("sink")) - timelineprobe = gst.Probe(False, self.timelineprobe) - self.timeline.get_pad("src_audiocomp").add_probe(timelineprobe) - def timelineprobe(self, probe, data): - if isinstance(data, gst.Buffer): - print "timeline outputs buffer", data.timestamp, data.duration - else: - print "timeline ouputs event", data.type - return True -gobject.type_register(AudioConcat) -def eos_cb(pipeline): - sys.exit() +class AudioConcat: + '''Concatenates multiple audio files to single ogg/vorbis file''' -if __name__ == "__main__": - if len(sys.argv) < 3: - print "Usage : %s " % sys.argv[0] - print "\tCreates an ogg file from all the audio input files" - sys.exit() - if not gst.element_factory_make("gnltimeline"): - print "You need the gnonlin elements installed (http://gnonlin.sf.net/)" - sys.exit() - concat = AudioConcat(sys.argv[1:-1], sys.argv[-1]) - concat.connect("eos", eos_cb) - concat.set_state(gst.STATE_PLAYING) - gst.main() + caps = gst.caps_from_string('audio/x-raw-float, rate=44100, channels=2, endianness=1234, width=32') + + def __init__(self, infiles, outfile): + # These are used in iteration through infiles + self.infiles = infiles + self.i = 0 + self.start = 0L + + # The pipeline + self.pipeline = gst.Pipeline() + + # Create bus and connect 'eos' and 'error' handlers + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.connect('message::eos', self.on_eos) + self.bus.connect('message::error', self.on_error) + + # Create elements + self.comp = gst.element_factory_make('gnlcomposition') + self.enc = gst.element_factory_make('vorbisenc') + self.mux = gst.element_factory_make('oggmux') + self.sink = gst.element_factory_make('filesink') + + # Connect handler for 'pad-added' signal + self.comp.connect('pad-added', self.on_pad_added) + + # Set 'location' property on filesink + self.sink.set_property('location', outfile) + + # Add elements to pipeline + self.pipeline.add(self.comp, self.enc, self.mux, self.sink) + + # Link *some* elements + # This in completed in self.on_pad_added() + gst.element_link_many(self.enc, self.mux, self.sink) + + # Reference used in self.on_pad_added() + self.apad = self.enc.get_pad('sink') + + # The MainLoop + self.mainloop = gobject.MainLoop() + + # Iterate through infiles + gobject.idle_add(self.discover) + self.mainloop.run() + + + def discover(self): + infile = self.infiles[self.i] + discoverer = Discoverer(infile) + discoverer.connect('discovered', self.on_discovered, infile) + discoverer.discover() + return False # Don't repeat idle call + + + def on_discovered(self, discoverer, ismedia, infile): + print '\non_discovered:', infile + discoverer.print_info() + if discoverer.is_audio: + dec = AudioDec(infile, self.caps) + src = gst.element_factory_make('gnlsource') + src.add(dec) + src.set_property('media-start', 0L) + src.set_property('media-duration', discoverer.audiolength) + src.set_property('start', self.start) + src.set_property('duration', discoverer.audiolength) + self.comp.add(src) + self.start += discoverer.audiolength + self.i += 1 + if self.i < len(self.infiles): + gobject.idle_add(self.discover) + else: + if self.start > 0: # At least 1 infile is_audio and audiolength > 0 + self.pipeline.set_state(gst.STATE_PLAYING) + else: + self.mainloop.quit() + + + def on_pad_added(self, element, pad): + caps = pad.get_caps() + name = caps[0].get_name() + print '\non_pad_added:', name + if name == 'audio/x-raw-float': + if not self.apad.is_linked(): # Only link once + pad.link(self.apad) + + + def on_eos(self, bus, msg): + print '\non_eos' + self.mainloop.quit() + + + def on_error(self, bus, msg): + error = msg.parse_error() + print '\non_error:', error[1] + self.mainloop.quit() + + + + +if __name__ == '__main__': + if len(sys.argv) >= 3: + AudioConcat(sys.argv[1:-1], sys.argv[-1]) + else: + print 'Usage: %s ' % sys.argv[0] + print 'Example: %s song1.mp3 song2.ogg output.ogg' % sys.argv[0] diff --git a/examples/bps.py b/examples/bps.py index 4ecd48daff..888fcdb78b 100755 --- a/examples/bps.py +++ b/examples/bps.py @@ -111,8 +111,8 @@ def main(args): buffers = int(args[1]) if buffers < 1: - print 'buffers must be higher than 0' - return + print 'buffers must be higher than 0' + return bps.run(buffers) diff --git a/examples/cp.py b/examples/cp.py index 0330fe3d4e..025b30f162 100755 --- a/examples/cp.py +++ b/examples/cp.py @@ -26,15 +26,27 @@ import sys +import gobject +gobject.threads_init() + +import pygst +pygst.require('0.10') import gst + +mainloop = gobject.MainLoop() + +def on_eos(bus, msg): + mainloop.quit() + def filter(input, output): "A GStreamer copy pipeline which can add arbitrary filters" # create a new bin to hold the elements bin = gst.parse_launch('filesrc name=source ! ' + - 'statistics silent=false buffer-update-freq=1 ' + - 'update_on_eos=true ! ' + + # This 'statistics' element is depreciated in 0.10 + #'statistics silent=false buffer-update-freq=1 ' + + #'update_on_eos=true ! ' + 'filesink name=sink') filesrc = bin.get_by_name('source') filesrc.set_property('location', input) @@ -42,12 +54,15 @@ def filter(input, output): filesink = bin.get_by_name('sink') filesink.set_property('location', output) + bus = bin.get_bus() + bus.add_signal_watch() + bus.connect('message::eos', on_eos) + # start playing - bin.set_state(gst.STATE_PLAYING); + bin.set_state(gst.STATE_PLAYING) try: - while bin.iterate(): - pass + mainloop.run() except KeyboardInterrupt: pass