Package flumotion :: Package component :: Package effects :: Package audioconvert :: Module audioconvert
[hide private]

Source Code for Module flumotion.component.effects.audioconvert.audioconvert

  1  # -*- Mode: Python -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  import sys 
 19   
 20  import gobject 
 21  import gst 
 22   
 23  from flumotion.common.i18n import gettexter 
 24  from flumotion.component import feedcomponent 
 25  from flumotion.common import gstreamer 
 26   
 27  __version__ = "$Rev$" 
 28  T_ = gettexter() 
 29   
 30  DEFAULT_TOLERANCE = 20000000 # 20ms 
 31   
 32   
33 -class AudioconvertBin(gst.Bin):
34 """ 35 I am a GStreamer bin that can convert an an audio stream, changing its 36 samplerate and the number of channels 37 """ 38 logCategory = "audiorate" 39 RATE_CAPS = ', rate=%d' 40 CHANNELS_CAPS = ', channels=%d' 41 CAPS_TEMPLATE = ("audio/x-raw-int %(extra_caps)s ;" 42 "audio/x-raw-float %(extra_caps)s") 43 44 __gproperties__ = { 45 'channels': (gobject.TYPE_UINT, 'channels', 46 'Audio channels', 1, 8, 2, 47 gobject.PARAM_READWRITE), 48 'samplerate': (gobject.TYPE_UINT, 'samplerate', 49 'Audio samplerate', 1, 200000, 44100, 50 gobject.PARAM_READWRITE), 51 'tolerance': (gobject.TYPE_UINT, 'tolerance', 52 'Correct imperfect timestamps when it exeeds the ' 53 'tolerance', 0, sys.maxint, DEFAULT_TOLERANCE, 54 gobject.PARAM_READWRITE)} 55
56 - def __init__(self, channels=None, samplerate=None, 57 tolerance=DEFAULT_TOLERANCE):
58 gst.Bin.__init__(self) 59 self._samplerate = samplerate 60 self._samplerate_caps = '' 61 self._channels = channels 62 self._channels_caps = '' 63 64 if self._use_audiorate(): 65 self._audiorate = gst.element_factory_make("audiorate") 66 self._audiorate.set_property("skip-to-first", True) 67 else: 68 self._audiorate = gst.element_factory_make("identity") 69 self._audiorate.set_property("silent", True) 70 71 self._audioconv = gst.element_factory_make("audioconvert") 72 73 resampler = 'audioresample' 74 if gstreamer.element_factory_exists('legacyresample'): 75 resampler = 'legacyresample' 76 self._audioresample = gst.element_factory_make(resampler) 77 78 self._capsfilter = gst.element_factory_make("capsfilter") 79 self._identity = gst.parse_launch("identity silent=true") 80 self.add(self._audiorate) 81 self.add(self._audioconv) 82 self.add(self._audioresample) 83 self.add(self._capsfilter) 84 self.add(self._identity) 85 86 self._audiorate.link(self._audioconv) 87 self._audioconv.link(self._audioresample) 88 self._audioresample.link(self._capsfilter) 89 self._capsfilter.link(self._identity) 90 91 # Create source and sink pads 92 self._sinkPad = gst.GhostPad('sink', self._audiorate.get_pad('sink')) 93 self._srcPad = gst.GhostPad('src', self._identity.get_pad('src')) 94 self.add_pad(self._sinkPad) 95 self.add_pad(self._srcPad) 96 97 self._sinkPad.set_event_function(self.eventfunc) 98 99 self._setSamplerate(samplerate) 100 self._setChannels(channels) 101 self._setTolerance(tolerance)
102
103 - def _use_audiorate(self):
104 return gstreamer.element_factory_has_property('audiorate', 105 'skip-to-first')
106
107 - def _getCapsString(self):
108 extra_caps = ' '.join([self._samplerate_caps, self._channels_caps]) 109 return self.CAPS_TEMPLATE % dict(extra_caps=extra_caps)
110
111 - def _setChannels(self, channels):
112 self._channels = channels 113 self._channels_caps = '' 114 if self._channels is not None: 115 self._channels_caps = self.CHANNELS_CAPS % channels 116 self._capsfilter.set_property('caps', gst.Caps(self._getCapsString()))
117
118 - def _setSamplerate(self, samplerate):
119 self._samplerate = samplerate 120 self._samplerate_caps = '' 121 if self._samplerate is not None: 122 self._samplerate_caps = self.RATE_CAPS % samplerate 123 self._capsfilter.set_property('caps', gst.Caps(self._getCapsString()))
124
125 - def _setTolerance(self, tolerance):
126 self._tolerance = tolerance 127 if gstreamer.element_has_property(self._audiorate, 'tolerance'): 128 self._audiorate.set_property('tolerance', self._tolerance) 129 else: 130 self.warning("The 'tolerance' property could not be set in the " 131 "audiorate element.")
132
133 - def do_set_property(self, property, value):
134 if property.name == 'channels': 135 self._setChannels(value) 136 if property.name == 'samplerate': 137 self._setSamplerate(value) 138 if property.name == 'tolerance': 139 self._setTolerance(value) 140 else: 141 raise AttributeError('unknown property %s' % property.name)
142
143 - def do_get_property(self, property):
144 if property.name == 'channels': 145 return self._channels 146 if property.name == 'samplerate': 147 return self._samplerate 148 if property.name == 'tolerance': 149 return self._tolerance 150 else: 151 raise AttributeError('unknown property %s' % property.name)
152
153 - def eventfunc(self, pad, event):
154 self.debug("Received event %r from %s" % (event, event.src)) 155 if gstreamer.event_is_flumotion_reset(event) and self._use_audiorate(): 156 self._audiorate.set_state(gst.STATE_READY) 157 self._audiorate.set_state(gst.STATE_PLAYING) 158 return self._srcPad.push_event(event)
159 160
161 -class Audioconvert(feedcomponent.PostProcEffect):
162 """ 163 I am an effect that can be added to any component that changes the 164 samplerate of the audio output. 165 """ 166 logCategory = "audioconvert-effect" 167
168 - def __init__(self, name, sourcePad, pipeline, channels=None, 169 samplerate=None, tolerance=DEFAULT_TOLERANCE, 170 use_audiorate=True):
171 """ 172 @param element: the video source element on which the post 173 processing effect will be added 174 @param sourcePad: source pad used for linking the effect 175 @param pipeline: the pipeline of the element 176 @param channels: number of output channels 177 @param samplerate: output samplerate 178 @param tolerance: tolerance to correct imperfect timestamps 179 """ 180 feedcomponent.PostProcEffect.__init__(self, name, sourcePad, 181 AudioconvertBin(channels, samplerate, tolerance), 182 pipeline)
183
184 - def effect_setTolerance(self, tolerance):
185 self.effectBin.set_property("tolerance", tolerance) 186 return tolerance
187
188 - def effect_getTolerance(self):
189 return self.effectBin.get_property('tolerance')
190
191 - def effect_setSamplerate(self, samplerate):
192 self.effectBin.set_property("samplerate", samplerate) 193 return samplerate
194
195 - def effect_getSamplerate(self):
196 return self.effectBin.get_property('samplerate')
197
198 - def effect_setChannels(self, channels):
199 self.effectBin.set_property("channels", channels) 200 return channels
201
202 - def effect_getChannels(self):
203 return self.effectBin.get_property('channels')
204