[transmageddon] Add audio engine
- From: Christian Fredrik Kalager Schaller <uraeus src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [transmageddon] Add audio engine
- Date: Sun, 20 Feb 2011 17:33:11 +0000 (UTC)
commit f13d4d0f82ac76529cfe30fa1eec5a18fc533bdb
Author: Christian Fredrik Kalager Schaller <christian schaller collabora co uk>
Date: Sun Feb 20 17:32:48 2011 +0000
Add audio engine
src/transcoder_engine_audio.py | 253 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 253 insertions(+), 0 deletions(-)
---
diff --git a/src/transcoder_engine_audio.py b/src/transcoder_engine_audio.py
new file mode 100644
index 0000000..09713be
--- /dev/null
+++ b/src/transcoder_engine_audio.py
@@ -0,0 +1,253 @@
+# Transmageddon
+# Copyright (C) 2009 Christian Schaller <uraeus gnome 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 librarmy 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 os
+import codecfinder
+import presets
+
+try:
+ import gobject; gobject.threads_init()
+ import pygst
+ import glib
+ pygst.require("0.10")
+ import gst
+except Exception, e:
+ print "failed to import required modules"
+ print e
+ sys.exit(1)
+
+class Transcoder(gobject.GObject):
+
+ __gsignals__ = {
+ 'ready-for-querying' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
+ 'got-eos' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
+ 'got-error' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
+ }
+
+ def __init__(self, FILECHOSEN, FILENAME, DESTDIR, CONTAINERCHOICE, AUDIOCODECVALUE, ACHANNELS,
+ OUTPUTNAME, TIMESTAMP, AUDIOPASSTOGGLE):
+ gobject.GObject.__init__(self)
+
+ # Choose plugin based on Container name
+ print "Containerchoice is " + str(CONTAINERCHOICE)
+ if CONTAINERCHOICE != "No container":
+ containercaps = codecfinder.containermap[CONTAINERCHOICE]
+ print "containercaps is " + str(containercaps)
+ self.ContainerFormatPlugin = codecfinder.get_muxer_element(containercaps)
+
+ # Choose plugin based on Codec Name
+ # or switch to remuxing mode if any of the values are set to 'pastr'
+ self.stoptoggle=False
+ self.audiocaps = AUDIOCODECVALUE
+ self.audiopasstoggle = AUDIOPASSTOGGLE
+ self.doaudio= False
+ if self.audiopasstoggle == False:
+ self.AudioEncoderPlugin = codecfinder.get_audio_encoder_element(self.audiocaps)
+ self.achannels = ACHANNELS
+ self.outputfilename = OUTPUTNAME
+ self.timestamp = TIMESTAMP
+ self.vbox = {}
+ self.containerchoice = CONTAINERCHOICE
+ # Create transcoding pipeline
+ self.pipeline = gst.Pipeline("TranscodingPipeline")
+ self.pipeline.set_state(gst.STATE_PAUSED)
+
+ self.uridecoder = gst.element_factory_make("uridecodebin", "uridecoder")
+ self.uridecoder.set_property("uri", FILECHOSEN)
+ self.uridecoder.connect("pad-added", self.OnDynamicPad)
+
+ self.gstmultiqueue = gst.element_factory_make("multiqueue")
+ self.multiqueueaudiosinkpad = self.gstmultiqueue.get_request_pad("sink0")
+ self.multiqueueaudiosrcpad = self.gstmultiqueue.get_pad("src0")
+ self.pipeline.add(self.gstmultiqueue)
+
+ self.remuxcaps = gst.Caps()
+ if self.audiopasstoggle:
+ self.remuxcaps.append(self.audiocaps)
+ if not self.audiopasstoggle:
+ self.remuxcaps.append_structure(gst.Structure("audio/x-raw-float"))
+ self.remuxcaps.append_structure(gst.Structure("audio/x-raw-int"))
+
+ if (self.audiopasstoggle):
+
+ self.uridecoder.set_property("caps", self.remuxcaps)
+ self.pipeline.add(self.uridecoder)
+
+ if self.containerchoice != "No container":
+ print "self.containerformatplugin is " + str(self.ContainerFormatPlugin)
+ self.containermuxer = gst.element_factory_make(self.ContainerFormatPlugin, "audiocontainermuxer")
+ print " successful container muxer creation" + str(self.containermuxer)
+ audiointersect = ("EMPTY")
+ factory = gst.registry_get_default().lookup_feature(self.ContainerFormatPlugin)
+ for x in factory.get_static_pad_templates():
+ if (x.direction == gst.PAD_SINK):
+ sourcecaps = x.get_caps()
+ if audiointersect == ("EMPTY"):
+ audiointersect = sourcecaps.intersect(gst.caps_from_string(self.audiocaps))
+ if audiointersect != ("EMPTY"):
+ self.containermuxeraudiosinkpad = self.containermuxer.get_request_pad(x.name_template)
+ self.pipeline.add(self.containermuxer)
+ #else:
+ # factory = gst.registry_get_default().lookup_feature(self.audioencoder)
+ # for x in factory.get_static_pad_templates():
+ # if (x.direction == gst.PAD_SINK):
+ # self.audioencodersinkpad = self.audioencoder.get_request_pad(x.name_template)
+
+ # Add a tag setting Transmageddon as the application used for creating file if supported by format
+ GstTagSetterType = gobject.type_from_name("GstTagSetter")
+ if GstTagSetterType in gobject.type_interfaces(self.containermuxer):
+ taglist=gst.TagList()
+ taglist[gst.TAG_APPLICATION_NAME] = "Transmageddon"
+ self.containermuxer.merge_tags(taglist, gst.TAG_MERGE_APPEND)
+
+ self.transcodefileoutput = gst.element_factory_make("filesink", "transcodefileoutput")
+ self.transcodefileoutput.set_property("location", (DESTDIR+"/"+self.outputfilename))
+ self.pipeline.add(self.transcodefileoutput)
+
+ self.uridecoder.set_state(gst.STATE_PAUSED)
+ # print "setting uridcodebin to paused"
+ self.BusMessages = self.BusWatcher()
+
+ self.uridecoder.connect("no-more-pads", self.noMorePads) # we need to wait on this one before going further
+ # print "connecting to no-more-pads
+
+ def noMorePads(self, dbin):
+ self.transcodefileoutput.set_state(gst.STATE_PAUSED)
+ if self.containerchoice != "No container":
+ self.containermuxer.set_state(gst.STATE_PAUSED)
+ glib.idle_add(self.idlePlay)
+ # print "No More pads received"
+
+ def idlePlay(self):
+ self.Pipeline("playing")
+ # print "gone to playing"
+ return False
+
+ def BusWatcher(self):
+ bus = self.pipeline.get_bus()
+ bus.add_watch(self.on_message)
+
+ def on_message(self, bus, message):
+ mtype = message.type
+ # print mtype
+ if mtype == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ print err
+ print debug
+ gst.DEBUG_BIN_TO_DOT_FILE (self.pipeline, gst.DEBUG_GRAPH_SHOW_ALL, 'transmageddon.dot')
+ elif mtype == gst.MESSAGE_ASYNC_DONE:
+ self.emit('ready-for-querying')
+ elif mtype == gst.MESSAGE_EOS:
+ self.emit('got-eos')
+ self.pipeline.set_state(gst.STATE_NULL)
+ elif mtype == gst.MESSAGE_APPLICATION:
+ print "I am getting the appliation message"
+ self.pipeline.set_state(gst.STATE_NULL)
+ self.pipeline.remove(self.uridecoder)
+ return True
+
+ def list_compat(self, a1, b1):
+ for x1 in a1:
+ if not x1 in b1:
+ return False
+ return True
+
+ def OnDynamicPad(self, dbin, sink_pad):
+ c = sink_pad.get_caps().to_string()
+ if c.startswith("audio/"):
+ if self.stoptoggle==True:
+ bus = self.pipeline.get_bus()
+ bus.post(gst.message_new_application(self.pipeline, gst.Structure('STOP TRANSCODER')))
+ return
+ # First check for passthough mode
+ if self.audiopasstoggle is False:
+ self.audioconverter = gst.element_factory_make("audioconvert")
+ self.pipeline.add(self.audioconverter)
+ self.audioencoder = gst.element_factory_make(self.AudioEncoderPlugin)
+ self.pipeline.add(self.audioencoder)
+
+ self.audioresampler = gst.element_factory_make("audioresample")
+ self.pipeline.add(self.audioresampler)
+ sink_pad.link(self.audioconverter.get_pad("sink"))
+
+ self.audioconverter.link(self.audioresampler)
+ self.audioresampler.link(self.audioencoder)
+
+ self.audioconverter.set_state(gst.STATE_PAUSED)
+ self.audioresampler.set_state(gst.STATE_PAUSED)
+ self.audioencoder.set_state(gst.STATE_PAUSED)
+ self.gstmultiqueue.set_state(gst.STATE_PAUSED)
+ if self.containerchoice != "No container":
+ self.audioencoder.get_static_pad("src").link(self.multiqueueaudiosinkpad)
+ self.multiqueueaudiosrcpad.link(self.containermuxeraudiosinkpad)
+ self.containermuxer.link(self.transcodefileoutput)
+ else:
+ self.audioencoder.link(self.transcodefileoutput)
+ else:
+ # This code is for handling passthrough mode.
+ # TODO: dynamically plug correct parser. Iterate on parsers and intersect.
+ # No parser if output is framed
+ parsedcaps = gst.caps_from_string(self.audiocaps+",parsed=true")
+ framedcaps = gst.caps_from_string(self.audiocaps+",framed=true")
+ if (sink_pad.get_caps().is_subset(parsedcaps)) or (sink_pad.get_caps().is_subset(framedcaps)):
+ sink_pad.link(self.multiqueueaudiosinkpad)
+ self.multiqueueaudiosrcpad.link(self.containermuxeraudiosinkpad)
+ self.gstmultiqueue.set_state(gst.STATE_PAUSED)
+ else:
+ flist = gst.registry_get_default().get_feature_list(gst.ElementFactory)
+ parsers = []
+ self.aparserelement = False
+ for fact in flist:
+ # print "fact is " + str(fact)
+ if self.list_compat(["Codec", "Parser","Audio"], fact.get_klass().split('/')):
+ parsers.append(fact.get_name())
+ for x in parsers:
+ parser = x
+ factory = gst.registry_get_default().lookup_feature(str(x))
+ sinkcaps = [x.get_caps() for x in factory.get_static_pad_templates() if x.direction == gst.PAD_SRC]
+ parseintersect = ("EMPTY")
+ for caps in sinkcaps:
+ if parseintersect == ("EMPTY"):
+ parseintersect = caps.intersect(gst.caps_from_string(self.audiocaps))
+ if parseintersect != ("EMPTY"):
+ self.aparserelement = parser
+ if self.aparserelement == False:
+ error_message="noaudioparser"
+ self.emit("got-error", error_message)
+ self.stoptoggle=True
+ return
+ self.audioparse = gst.element_factory_make(self.aparserelement)
+ self.pipeline.add(self.audioparse)
+
+ # print "audiopad " + str(self.multiqueueaudiosinkpad)
+ sink_pad.link(self.audioparse.get_static_pad("sink"))
+ self.audioparse.get_static_pad("src").link(self.multiqueueaudiosinkpad)
+ if CONTAINERCHOICE != "None":
+ self.multiqueueaudiosrcpad.link(self.containermuxeraudiosinkpad)
+ self.containermuxer.link(self.transcodefileoutput)
+ else:
+ self.multiqueueaudiosrcpad.link(self.transcodefileoutput)
+ self.audioparse.set_state(gst.STATE_PAUSED)
+ self.gstmultiqueue.set_state(gst.STATE_PAUSED)
+
+ def Pipeline (self, state):
+ if state == ("playing"):
+ self.pipeline.set_state(gst.STATE_PLAYING)
+ elif state == ("null"):
+ self.pipeline.set_state(gst.STATE_NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]