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

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

  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 Fluendo, S.L. (www.fluendo.com). 
  6  # All rights reserved. 
  7   
  8  # This file may be distributed and/or modified under the terms of 
  9  # the GNU General Public License version 2 as published by 
 10  # the Free Software Foundation. 
 11  # This file is distributed without any warranty; without even the implied 
 12  # warranty of merchantability or fitness for a particular purpose. 
 13  # See "LICENSE.GPL" in the source distribution for more information. 
 14   
 15  # Licensees having purchased or holding a valid Flumotion Advanced 
 16  # Streaming Server license may use this file in accordance with the 
 17  # Flumotion Advanced Streaming Server Commercial License Agreement. 
 18  # See "LICENSE.Flumotion" in the source distribution for more information. 
 19   
 20  # Headers in this file shall remain intact. 
 21   
 22  import gst 
 23  import gobject 
 24  from twisted.internet import reactor 
 25   
 26  from flumotion.component import feedcomponent 
 27   
 28  __version__ = "$Rev$" 
 29   
 30  GST_DEINTERLACER = "deinterlace" 
 31  FF_DEINTERLACER = "ffdeinterlace" 
 32  PASSTHROUGH_DEINTERLACER = "identity" 
 33   
 34  DEINTERLACE_MODE = [ 
 35      "auto", 
 36      "interlaced", 
 37      "disabled"] 
 38   
 39  DEINTERLACE_METHOD = { 
 40      # deinterlace2 methods 
 41      "tomsmocomp": GST_DEINTERLACER, 
 42      "greedyh": GST_DEINTERLACER, 
 43      "greedyl": GST_DEINTERLACER, 
 44      "vfir": GST_DEINTERLACER, 
 45      "linear": GST_DEINTERLACER, 
 46      "linearblend": GST_DEINTERLACER, 
 47      "scalerbob": GST_DEINTERLACER, 
 48      "weave": GST_DEINTERLACER, 
 49      "weavetff": GST_DEINTERLACER, 
 50      "weavebff": GST_DEINTERLACER, 
 51      # ffmpeg methods 
 52      "ffmpeg": FF_DEINTERLACER} 
 53   
 54   
55 -class DeinterlaceBin(gst.Bin):
56 """ 57 I am a GStreamer bin that can deinterlace a video stream from its 58 source pad using different methods. 59 """ 60 logCategory = "deinterlace" 61 DEFAULT_MODE = 'auto' 62 DEFAULT_METHOD = 'ffmpeg' 63 64 __gproperties__ = { 65 'keep-framerate': (gobject.TYPE_BOOLEAN, 'keeps the input framerate', 66 'keeps in the output the same framerate as in the output ' 67 'even if the deinterlacer changes it', 68 True, gobject.PARAM_READWRITE), 69 'mode': (gobject.TYPE_STRING, 'deinterlace mode', 70 'mode used to deinterlace incoming frames', 71 'auto', gobject.PARAM_READWRITE), 72 'method': (gobject.TYPE_STRING, 'deinterlace method', 73 'method/algorithm used to deinterlace incoming frames', 74 'ffmpeg', gobject.PARAM_READWRITE)} 75
76 - def __init__(self, mode, method):
77 gst.Bin.__init__(self) 78 79 self.keepFR = True 80 self.deinterlacerName = None 81 self._interlaced = False 82 self._passthrough = False 83 84 # Create elements 85 self._colorspace = gst.element_factory_make("ffmpegcolorspace") 86 self._deinterlacer = gst.element_factory_make(PASSTHROUGH_DEINTERLACER) 87 self._videorate = gst.element_factory_make("videorate") 88 self._capsfilter = gst.element_factory_make("capsfilter") 89 90 # Add elements to the bin 91 self.add(self._colorspace, self._deinterlacer, self._videorate, 92 self._capsfilter) 93 94 # Link elements 95 self._colorspace.link(self._deinterlacer) 96 self._deinterlacer.link(self._videorate) 97 self._videorate.link(self._capsfilter) 98 99 # Create source and sink pads 100 self._sinkPad = gst.GhostPad('sink', self._colorspace.get_pad('sink')) 101 self._srcPad = gst.GhostPad('src', self._capsfilter.get_pad('src')) 102 self.add_pad(self._sinkPad) 103 self.add_pad(self._srcPad) 104 105 # Store deinterlacer's sink and source peer pads 106 self._sinkPeerPad = self._colorspace.get_pad('src') 107 self._srcPeerPad = self._videorate.get_pad('sink') 108 109 # Add setcaps callback in the sink pad 110 self._sinkPad.set_setcaps_function(self._sinkSetCaps) 111 112 # Set the mode and method in the deinterlacer 113 self._setMethod(method) 114 self._setMode(mode)
115
116 - def _sinkSetCaps(self, pad, caps):
117 struct = caps[0] 118 # Set in the source pad the same framerate as in the sink pad 119 if self.keepFR: 120 try: 121 framerate = struct['framerate'] 122 except KeyError: 123 framerate = gst.Fraction(25, 1) 124 fr = '%s/%s' % (framerate.num, framerate.denom) 125 self._capsfilter.set_property('caps', gst.Caps( 126 'video/x-raw-yuv, framerate=%s;' 127 'video/x-raw-rgb, framerate=%s' % (fr, fr))) 128 # Detect if it's an interlaced stream using the 'interlaced' field 129 try: 130 interlaced = struct['interlaced'] 131 except KeyError: 132 interlaced = False 133 if interlaced == self._interlaced: 134 return True 135 else: 136 self.debug("Input is%sinterlaced" % 137 (interlaced and " " or " not ")) 138 self._interlaced = interlaced 139 # If we are in 'auto' mode and the interlaced field has changed, 140 # switch to the appropiate deinterlacer 141 if self.mode == 'auto': 142 if self._interlaced == True and self._passthrough: 143 self._replaceDeinterlacer(self._sinkPeerPad, 144 self.deinterlacerName) 145 elif self._interlaced == False: 146 self._replaceDeinterlacer(self._sinkPeerPad, 147 PASSTHROUGH_DEINTERLACER) 148 return True
149
150 - def _replaceDeinterlacer(self, blockPad, deinterlacerName):
151 152 def unlinkAndReplace(Pad, blocked, deinterlacerName): 153 oldDeinterlacer = self._deinterlacer 154 self._deinterlacer = gst.element_factory_make(deinterlacerName) 155 if deinterlacerName == GST_DEINTERLACER: 156 self._deinterlacer.set_property("method", self.method) 157 self._deinterlacer.set_state(gst.STATE_PLAYING) 158 self.add(self._deinterlacer) 159 # unlink the sink and source pad of the old deinterlacer 160 self._colorspace.unlink(oldDeinterlacer) 161 oldDeinterlacer.unlink(self._videorate) 162 # remove the old deinterlacer from the bin 163 oldDeinterlacer.set_state(gst.STATE_NULL) 164 self.remove(oldDeinterlacer) 165 self._colorspace.link(self._deinterlacer) 166 self._deinterlacer.link(self._videorate) 167 reactor.callFromThread(self._sinkPeerPad.set_blocked, False) 168 self.debug("%s has been replaced succesfully" % 169 self.deinterlacerName) 170 self.deinterlacerName = deinterlacerName
171 172 # We might be called from the streaming thread 173 self.debug("Replacing %s deinterlacer with %s:%s" % 174 (self.deinterlacerName, deinterlacerName, self.method)) 175 reactor.callFromThread(blockPad.set_blocked_async, 176 True, unlinkAndReplace, deinterlacerName)
177
178 - def _setMode(self, mode):
179 if mode not in DEINTERLACE_MODE: 180 raise AttributeError('unknown mode %s' % mode) 181 182 self.mode = mode 183 184 # If the new mode is 'disabled' use the passthrough deinterlacer 185 if self.mode == 'disabled': 186 self._passthrough = True 187 self._replaceDeinterlacer(self._sinkPeerPad, 188 PASSTHROUGH_DEINTERLACER) 189 # If the new mode is 'interlaced' force deinterlacing by replacing 190 # the deinterlacer if it was the passthrough one 191 elif self.mode == 'interlaced': 192 if self._passthrough: 193 self._replaceDeinterlacer(self._sinkPeerPad, 194 self.deinterlacerName) 195 self._passthrough = False 196 # If the new mode is 'auto' replace the deinterlacer if the old one is 197 # passthough and the input content is interlaced 198 elif self.mode == 'auto': 199 if self._interlaced and self._passthrough: 200 self._passthrough = False 201 self._replaceDeinterlacer(self._sinkPeerPad, 202 self.deinterlacerName)
203
204 - def _setMethod(self, method):
205 if method not in DEINTERLACE_METHOD: 206 raise AttributeError('unknown mode %s' % method) 207 208 self.method = method 209 deinterlacerName = DEINTERLACE_METHOD[method] 210 if self.deinterlacerName == deinterlacerName: 211 # If the deinterlacer is 'deinterlace2', change 212 # the method property in the component 213 if self.deinterlacerName == GST_DEINTERLACER \ 214 and not self._passthrough: 215 self.debug("Changed method to %s" % method) 216 self._deinterlacer.set_property("method", method) 217 return 218 219 if not self._passthrough: 220 # Replace the deinterlacer 221 self._replaceDeinterlacer(self._sinkPeerPad, deinterlacerName)
222
223 - def do_set_property(self, property, value):
224 if property.name == 'mode': 225 if value != self.mode: 226 self._setMode(value) 227 elif property.name == 'method': 228 if value != self.method: 229 self._setMethod(value) 230 elif property.name == 'keep-framerate': 231 self.keepFR = value 232 else: 233 raise AttributeError('uknown property %s' % property.name)
234
235 - def do_get_property(self, property):
236 if property.name == 'mode': 237 return self.mode 238 elif property.name == 'method': 239 return self.method 240 elif property.name == 'keep-framerate': 241 return self.keepFR 242 else: 243 raise AttributeError('uknown property %s' % property.name)
244 245
246 -class Deinterlace(feedcomponent.PostProcEffect):
247 """ 248 I am an effect that can be added to any component that has a deinterlacer 249 component and a way of changing the deinterlace method. 250 """ 251 logCategory = "deinterlace" 252
253 - def __init__(self, name, sourcePad, pipeline, mode, method):
254 """ 255 @param element: the video source element on which the post 256 processing effect will be added 257 @param pipeline: the pipeline of the element 258 @param mode: deinterlace mode 259 @param methid: deinterlace method 260 """ 261 feedcomponent.PostProcEffect.__init__(self, name, sourcePad, 262 DeinterlaceBin(mode, method), pipeline)
263
264 - def setUIState(self, state):
265 feedcomponent.Effect.setUIState(self, state) 266 if state: 267 for k in 'mode', 'method': 268 state.addKey('deinterlace-%s' % k, 269 self.effectBin.get_property(k))
270
271 - def effect_setMethod(self, method):
272 """ 273 Sets the deinterlacing method 274 275 @param value: the method to set to deinterlace 276 277 @return: the actual method set to deinterlace 278 """ 279 self.effectBin.set_property('method', method) 280 self.info('Changing deinterlacing method to %s', method) 281 # notify admin clients 282 self.uiState.set('deinterlace-method', method) 283 return method
284
285 - def effect_getMethod(self):
286 """ 287 Gets the deinterlacing method 288 289 @return: the method set for deinterlacing 290 @rtype: string 291 """ 292 return self.effectBin.get_property('method')
293
294 - def effect_setMode(self, mode):
295 """ 296 Sets the deinterlacing mode 297 298 @param value: the method to set to deinterlace 299 300 @return: the actual method set to deinterlace 301 """ 302 self.effectBin.set_property('mode', mode) 303 self.info('Changing deinterlacing mode to %s', mode) 304 # notify admin clients 305 self.uiState.set('deinterlace-mode', mode) 306 return mode
307
308 - def effect_getMode(self, mode):
309 """ 310 GetSets the deinterlacing method 311 312 @param value: the method used for deinterlacing 313 314 Returns: the actual method used to deinterlace 315 """ 316 return self.effectBin.get_property('mode')
317