aa4c028e69bd9ca9616b6c656f52f1b57130c99d
[~jspiros/hylia-transcoder.git] / hylia-transcoder.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3
4 import sys, os, time, thread
5 import glib, gobject, pygst
6 import argparse
7 pygst.require('0.10')
8 import gst
9
10
11 loop = glib.MainLoop()
12
13
14 class Main(object):
15         def __init__(self):
16                 self.transcoder = gst.Pipeline('transcoder')
17                 
18                 self.input_file = gst.element_factory_make('filesrc', 'input-file')
19                 self.decoder = gst.element_factory_make('decodebin2', 'decoder')
20                 self.decoder.connect('pad-added', self.decoder_pad_added)
21                 
22                 queues = []
23                 
24                 self.video_input_queue = gst.element_factory_make('queue2', 'video-input-queue')
25                 queues.append(self.video_input_queue)
26                 self.video_encoder = gst.element_factory_make('x264enc', 'video-encoder')
27                 self.video_encoder.set_property('speed-preset', 1)
28                 self.video_encoder.set_property('tune', 0x00000004)
29                 #self.video_encoder.set_property('bitrate', 2048)
30                 
31                 h264parse = gst.element_factory_make('h264parse', 'h264parse')
32                 h264parse.set_property('output-format', 1)
33                 self.video_output_queue = gst.element_factory_make('queue2', 'video-output-queue')
34                 queues.append(self.video_output_queue)
35                 
36                 self.audio_input_queue = gst.element_factory_make('queue2', 'audio-input-queue')
37                 queues.append(self.audio_input_queue)
38                 audioconvert = gst.element_factory_make('audioconvert', 'audioconvert')
39                 self.audio_encoder = gst.element_factory_make('ffenc_mp2', 'audio-encoder')
40                 self.audio_output_queue = gst.element_factory_make('queue2', 'audio-output-queue')
41                 queues.append(self.audio_output_queue)
42                 
43                 self.muxer = gst.element_factory_make('ffmux_mpegts', 'muxer')
44                 self.output_file = gst.element_factory_make('filesink', 'output-file')
45                 
46                 self.transcoder.add(
47                         self.input_file,
48                         self.decoder,
49                         self.video_input_queue,
50                         self.video_encoder,
51                         h264parse,
52                         self.video_output_queue,
53                         self.audio_input_queue,
54                         audioconvert,
55                         self.audio_encoder,
56                         self.audio_output_queue,
57                         self.muxer,
58                         self.output_file
59                 )
60                 
61                 for queue in queues:
62                         queue.set_property('max-size-buffers', 0)
63                         queue.set_property('max-size-bytes', 0)
64                         queue.set_property('max-size-time', 0)
65                 
66                 gst.element_link_many(
67                         self.input_file,
68                         self.decoder
69                 )
70                 
71                 gst.element_link_many(
72                         self.video_input_queue,
73                         self.video_encoder,
74                         h264parse,
75                         self.video_output_queue,
76                         self.muxer
77                 )
78                 
79                 gst.element_link_many(
80                         self.audio_input_queue,
81                         audioconvert,
82                         self.audio_encoder,
83                         self.audio_output_queue,
84                         self.muxer
85                 )
86                 
87                 gst.element_link_many(
88                         self.muxer,
89                         self.output_file
90                 )
91                 
92                 bus = self.transcoder.get_bus()
93                 bus.add_signal_watch()
94                 bus.connect('message', self.on_message)
95         
96         def decoder_pad_added(self, decoder, pad):
97                 print pad.get_caps()
98                 if pad.get_caps().to_string()[0:5] == 'video':
99                         pad.link(self.video_input_queue.get_pad('sink'))
100                 elif pad.get_caps().to_string()[0:5] == 'audio':
101                         pad.link(self.audio_input_queue.get_pad('sink'))
102         
103         def on_message(self, bus, message):
104                 t = message.type
105                 if t == gst.MESSAGE_EOS:
106                         self.transcoder.set_state(gst.STATE_NULL)
107                         self.playmode = False
108                 elif t == gst.MESSAGE_ERROR:
109                         self.transcoder.set_state(gst.STATE_NULL)
110                         err, debug = message.parse_error()
111                         print "Error: %s" % err, debug
112                         self.playmode = False
113         
114         def start(self, args):
115                 if os.path.isfile(args.input):
116                         self.playmode = True
117                         self.transcoder.get_by_name('input-file').set_property('location', args.input)
118                         self.transcoder.get_by_name('output-file').set_property('location', args.output)
119                         self.transcoder.set_state(gst.STATE_PLAYING)
120                         while self.playmode:
121                                 time.sleep(1)
122                 
123                 time.sleep(1)
124                 loop.quit()
125
126
127 if __name__ == "__main__":
128         parser = argparse.ArgumentParser(description='Hylia intelligent media transcoder.')
129         parser.add_argument('input', help='the path or URL of media to be transcoded')
130         parser.add_argument('output', help='the path where transcoded data will be sent (defaults to /dev/null for testing)', nargs='?', default='/dev/null')
131         args = parser.parse_args()
132         
133         print args
134         
135         mainclass = Main()
136         thread.start_new_thread(mainclass.start, (args,))
137         gobject.threads_init()
138         loop.run()