From e9109d68f46d830262359a2248b377f81e94fef8 Mon Sep 17 00:00:00 2001 From: Joseph Spiros Date: Sun, 23 Jan 2011 22:07:34 -0500 Subject: [PATCH] Switched to using decodebin2 to do the demuxing and (optionally) decoding. --- hylia-transcoder.py | 133 ++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/hylia-transcoder.py b/hylia-transcoder.py index aa4c028..f0f18be 100755 --- a/hylia-transcoder.py +++ b/hylia-transcoder.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # encoding: utf-8 +# known issues: +# - gstreamer demuxes xvid as video/x-xvid, but mpegtsmuxer can only accept video/mpeg. capssetter doesn't fix this. +# - MPEG-4 video can't seem to be muxed in properly, anyway. +# - Doesn't seem to work with the PS3... + import sys, os, time, thread import glib, gobject, pygst import argparse @@ -12,47 +17,42 @@ loop = glib.MainLoop() class Main(object): - def __init__(self): + def __init__(self, parser, args): + self.parser = parser + self.args = args + self.transcoder = gst.Pipeline('transcoder') self.input_file = gst.element_factory_make('filesrc', 'input-file') + self.input_file.set_property('location', self.args.input) + self.decoder = gst.element_factory_make('decodebin2', 'decoder') + self.decoder.connect('autoplug-continue', self.decoder_autoplug_continue) self.decoder.connect('pad-added', self.decoder_pad_added) + self.decoder.connect('no-more-pads', self.decoder_no_more_pads) queues = [] self.video_input_queue = gst.element_factory_make('queue2', 'video-input-queue') queues.append(self.video_input_queue) - self.video_encoder = gst.element_factory_make('x264enc', 'video-encoder') - self.video_encoder.set_property('speed-preset', 1) - self.video_encoder.set_property('tune', 0x00000004) - #self.video_encoder.set_property('bitrate', 2048) - - h264parse = gst.element_factory_make('h264parse', 'h264parse') - h264parse.set_property('output-format', 1) self.video_output_queue = gst.element_factory_make('queue2', 'video-output-queue') queues.append(self.video_output_queue) self.audio_input_queue = gst.element_factory_make('queue2', 'audio-input-queue') queues.append(self.audio_input_queue) - audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') - self.audio_encoder = gst.element_factory_make('ffenc_mp2', 'audio-encoder') self.audio_output_queue = gst.element_factory_make('queue2', 'audio-output-queue') queues.append(self.audio_output_queue) - self.muxer = gst.element_factory_make('ffmux_mpegts', 'muxer') + self.muxer = gst.element_factory_make('mpegtsmux', 'muxer') self.output_file = gst.element_factory_make('filesink', 'output-file') + self.output_file.set_property('location', self.args.output) self.transcoder.add( self.input_file, self.decoder, self.video_input_queue, - self.video_encoder, - h264parse, self.video_output_queue, self.audio_input_queue, - audioconvert, - self.audio_encoder, self.audio_output_queue, self.muxer, self.output_file @@ -60,45 +60,61 @@ class Main(object): for queue in queues: queue.set_property('max-size-buffers', 0) - queue.set_property('max-size-bytes', 0) queue.set_property('max-size-time', 0) - gst.element_link_many( - self.input_file, - self.decoder - ) - - gst.element_link_many( - self.video_input_queue, - self.video_encoder, - h264parse, - self.video_output_queue, - self.muxer - ) - - gst.element_link_many( - self.audio_input_queue, - audioconvert, - self.audio_encoder, - self.audio_output_queue, - self.muxer - ) - - gst.element_link_many( - self.muxer, - self.output_file - ) + gst.element_link_many(self.input_file, self.decoder) bus = self.transcoder.get_bus() bus.add_signal_watch() bus.connect('message', self.on_message) + def decoder_autoplug_continue(self, decoder, pad, caps): + caps_string = caps.to_string() + if caps_string.startswith('video/x-h264'): + return False + elif caps_string.startswith('audio/x-ac3'): + return False + elif caps_string.startswith('audio/mpeg'): # could be AAC, MP3, MP2 + return False + return True + def decoder_pad_added(self, decoder, pad): - print pad.get_caps() - if pad.get_caps().to_string()[0:5] == 'video': + caps_string = pad.get_caps().to_string() + if caps_string.startswith('video'): pad.link(self.video_input_queue.get_pad('sink')) - elif pad.get_caps().to_string()[0:5] == 'audio': + if caps_string.startswith('video/x-h264'): + #h264parse = gst.element_factory_make('h264parse', 'h264parse') + #h264parse.set_property('output-format', 1) + #self.transcoder.add(h264parse) + #gst.element_link_many(self.video_input_queue, h264parse, self.video_output_queue, self.muxer) + gst.element_link_many(self.video_input_queue, self.video_output_queue, self.muxer) + #h264parse.set_state(gst.STATE_PLAYING) + else: + video_encoder = gst.element_factory_make('ffenc_mpeg4', 'video-encoder') + video_encoder.set_property('bitrate', (2048*1000)) + self.transcoder.add(video_encoder) + gst.element_link_many(self.video_input_queue, video_encoder, self.video_output_queue, self.muxer) + video_encoder.set_state(gst.STATE_PLAYING) + elif caps_string.startswith('audio'): pad.link(self.audio_input_queue.get_pad('sink')) + if caps_string.startswith('audio/x-ac3'): + ac3parse = gst.element_factory_make('ac3parse', 'ac3parse') + self.transcoder.add(ac3parse) + gst.element_link_many(self.audio_input_queue, ac3parse, self.audio_output_queue, self.muxer) + ac3parse.set_state(gst.STATE_PLAYING) + elif caps_string.startswith('audio/mpeg'): + gst.element_link_many(self.audio_input_queue, self.audio_output_queue, self.muxer) + else: + audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') + audio_encoder = gst.element_factory_make('ffenc_mp2', 'audio-encoder') + self.transcoder.add(audioconvert, audio_encoder) + gst.element_link_many(self.audio_input_queue, audioconvert, audio_encoder, self.audio_output_queue, self.muxer) + audioconvert.set_state(gst.STATE_PLAYING) + audio_encoder.set_state(gst.STATE_PLAYING) + + def decoder_no_more_pads(self, decoder): + gst.element_link_many(self.muxer, self.output_file) + self.transcoder.set_state(gst.STATE_PLAYING) def on_message(self, bus, message): t = message.type @@ -108,17 +124,14 @@ class Main(object): elif t == gst.MESSAGE_ERROR: self.transcoder.set_state(gst.STATE_NULL) err, debug = message.parse_error() - print "Error: %s" % err, debug + logging.debug("Error: %s" % err, debug) self.playmode = False - def start(self, args): - if os.path.isfile(args.input): - self.playmode = True - self.transcoder.get_by_name('input-file').set_property('location', args.input) - self.transcoder.get_by_name('output-file').set_property('location', args.output) - self.transcoder.set_state(gst.STATE_PLAYING) - while self.playmode: - time.sleep(1) + def start(self): + self.playmode = True + self.transcoder.set_state(gst.STATE_PAUSED) + while self.playmode: + time.sleep(1) time.sleep(1) loop.quit() @@ -129,10 +142,10 @@ if __name__ == "__main__": parser.add_argument('input', help='the path or URL of media to be transcoded') parser.add_argument('output', help='the path where transcoded data will be sent (defaults to /dev/null for testing)', nargs='?', default='/dev/null') args = parser.parse_args() - - print args - - mainclass = Main() - thread.start_new_thread(mainclass.start, (args,)) - gobject.threads_init() - loop.run() \ No newline at end of file + if os.path.isfile(args.input): + mainclass = Main(parser, args) + thread.start_new_thread(mainclass.start, ()) + gobject.threads_init() + loop.run() + else: + parser.error('Invalid input "%s"' % args.input) \ No newline at end of file -- 2.20.1