summaryrefslogtreecommitdiff
path: root/examples/audioconcat.py
blob: 3797a31b1ff1398b22c2c5ad1189dd6682672797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python
# -*- 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

# 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 <input file(s)> <output file>" % 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()