home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/env python
- # -*- Mode: Python -*-
- # vi:si:et:sw=4:sts=4:ts=4
-
- # audioconcat.py - Concatenates multiple audio files to single ogg/vorbis file
- # Uses the gnonlin elements (http://gnonlin.sf.net/)
- # Copyright (C) 2005 Edward Hervey <edward@fluendo.com>
- # 2006 Jason Gerard DeRose <jderose@jasonderose.org>
- #
- # 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 sys
-
- import gobject
- gobject.threads_init()
-
- import pygst
- pygst.require('0.10')
- import gst
- from gst.extend.discoverer import Discoverer
-
-
-
- class AudioDec(gst.Bin):
- '''Decodes audio file, outputs at specified caps'''
-
- def __init__(self, location, caps):
- gst.Bin.__init__(self)
-
- # 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')
-
- # Set 'location' property on filesrc
- src.set_property('location', location)
-
- # Connect handler for 'new-decoded-pad' signal
- dec.connect('new-decoded-pad', self.__on_new_decoded_pad)
-
- # Add elements to bin
- self.add(src, dec, conv, rsmpl, ident)
-
- # Link *some* elements
- # This is completed in self.__on_new_decoded_pad()
- src.link(dec)
- conv.link(rsmpl)
- rsmpl.link(ident, caps)
-
- # Reference used in self.__on_new_decoded_pad()
- self.__apad = conv.get_pad('sink')
-
- # Add ghost pad
- self.add_pad(gst.GhostPad('src', ident.get_pad('src')))
-
-
- 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)
-
-
-
-
- class AudioConcat:
- '''Concatenates multiple audio files to single ogg/vorbis file'''
-
- 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 <input_file(s)> <output_file>' % sys.argv[0]
- print 'Example: %s song1.mp3 song2.ogg output.ogg' % sys.argv[0]
-