#!/usr/bin/env python
# audio concat tool
# takes in one or more audio files and creates one audio file of the combination
# Uses the gnonlin elements (http://gnonlin.sf.net/)
import os
import sys
import gobject
import gst
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
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 _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"))
gobject.type_register(AudioSource)
class AudioConcat(gst.Thread):
"""A Gstreamer thread that concatenates a series of audio files to another audio file"""
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)
self.timeline = gst.element_factory_make("gnltimeline")
self.audiocomp = gst.element_factory_make("gnlcomposition", "audiocomp")
self.audioconvert = gst.element_factory_make("audioconvert")
self.add_many(self.timeline, self.audioconvert,
self.audioenc, self.muxer, self.filesink)
## 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)
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
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()
if __name__ == "__main__":
if len(sys.argv) < 3:
print "Usage : %s