Package flumotion :: Package component :: Package producers :: Package playlist :: Module singledecodebin
[hide private]

Source Code for Module flumotion.component.producers.playlist.singledecodebin

  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   
 23  # Originally part of PiTiVi, 
 24  # Copyright (C) 2005-2007 Edward Hervey <bilboed@bilboed.com>, 
 25  # Relicensed under the above dual license with his permission. 
 26   
 27  """ 
 28  Single-stream queue-less decodebin 
 29  """ 
 30   
 31  import gobject 
 32  import gst 
 33   
34 -def is_raw(caps):
35 """ returns True if the caps are RAW """ 36 rep = caps.to_string() 37 valid = ["video/x-raw", "audio/x-raw", "text/plain", "text/x-pango-markup"] 38 for val in valid: 39 if rep.startswith(val): 40 return True 41 return False
42
43 -class SingleDecodeBin(gst.Bin):
44 45 __gsttemplates__ = ( 46 gst.PadTemplate ("sinkpadtemplate", 47 gst.PAD_SINK, 48 gst.PAD_ALWAYS, 49 gst.caps_new_any()), 50 gst.PadTemplate ("srcpadtemplate", 51 gst.PAD_SRC, 52 gst.PAD_SOMETIMES, 53 gst.caps_new_any()) 54 )
55 - def __init__(self, caps=None, uri=None, *args, **kwargs):
56 gst.Bin.__init__(self, *args, **kwargs) 57 if not caps: 58 caps = gst.caps_new_any() 59 self.caps = caps 60 self.typefind = gst.element_factory_make("typefind", "internal-typefind") 61 self.add(self.typefind) 62 63 self.uri = uri 64 if self.uri and gst.uri_is_valid(self.uri): 65 self.urisrc = gst.element_make_from_uri(gst.URI_SRC, uri, "urisrc") 66 self.log("created urisrc %s / %r" % (self.urisrc.get_name(), 67 self.urisrc)) 68 self.add(self.urisrc) 69 self.urisrc.link(self.typefind) 70 else: 71 self._sinkpad = gst.GhostPad("sink", self.typefind.get_pad("sink")) 72 self._sinkpad.set_active(True) 73 self.add_pad(self._sinkpad) 74 75 self.typefind.connect("have_type", self._typefindHaveTypeCb) 76 77 self._srcpad = None 78 79 self._dynamics = [] 80 81 self._validelements = [] #added elements 82 83 self._factories = self._getSortedFactoryList()
84 85 86 ## internal methods 87
88 - def _controlDynamicElement(self, element):
89 self.log("element:%s" % element.get_name()) 90 self._dynamics.append(element) 91 element.connect("pad-added", self._dynamicPadAddedCb) 92 element.connect("no-more-pads", self._dynamicNoMorePadsCb)
93
94 - def _getSortedFactoryList(self):
95 """ 96 Returns the list of demuxers, decoders and parsers available, sorted 97 by rank 98 """ 99 def myfilter(fact): 100 if fact.get_rank() < 64 : 101 return False 102 klass = fact.get_klass() 103 if not ("Demuxer" in klass or "Decoder" in klass or "Parse" in klass): 104 return False 105 return True
106 reg = gst.registry_get_default() 107 res = [x for x in reg.get_feature_list(gst.ElementFactory) if myfilter(x)] 108 res.sort(lambda a, b: int(b.get_rank() - a.get_rank())) 109 return res
110
111 - def _findCompatibleFactory(self, caps):
112 """ 113 Returns a list of factories (sorted by rank) which can take caps as 114 input. Returns empty list if none are compatible 115 """ 116 self.debug("caps:%s" % caps.to_string()) 117 res = [] 118 for factory in self._factories: 119 for template in factory.get_static_pad_templates(): 120 if template.direction == gst.PAD_SINK: 121 intersect = caps.intersect(template.static_caps.get()) 122 if not intersect.is_empty(): 123 res.append(factory) 124 break 125 self.debug("returning %r" % res) 126 return res
127 158
159 - def _tryToLink1(self, source, pad, factories):
160 """ 161 Tries to link one of the factories' element to the given pad. 162 163 Returns the element that was successfully linked to the pad. 164 """ 165 self.debug("source:%s, pad:%s , factories:%r" % (source.get_name(), 166 pad.get_name(), 167 factories)) 168 result = None 169 for factory in factories: 170 element = factory.create() 171 if not element: 172 self.warning("weren't able to create element from %r" % factory) 173 continue 174 175 sinkpad = element.get_pad("sink") 176 if not sinkpad: 177 continue 178 179 self.add(element) 180 try: 181 pad.link(sinkpad) 182 except: 183 element.set_state(gst.STATE_NULL) 184 self.remove(element) 185 continue 186 187 self._closeLink(element) 188 element.set_state(gst.STATE_PAUSED) 189 190 result = element 191 break 192 193 return result
194 228
229 - def _wrapUp(self, element, pad):
230 """ 231 Ghost the given pad of element. 232 Remove non-used elements. 233 """ 234 235 if self._srcpad: 236 return 237 self._markValidElements(element) 238 self._removeUnusedElements(self.typefind) 239 self.log("ghosting pad %s" % pad.get_name) 240 self._srcpad = gst.GhostPad("src", pad) 241 self._srcpad.set_active(True) 242 self.add_pad(self._srcpad) 243 self.post_message(gst.message_new_state_dirty(self))
244
245 - def _markValidElements(self, element):
246 """ 247 Mark this element and upstreams as valid 248 """ 249 self.log("element:%s" % element.get_name()) 250 if element == self.typefind: 251 return 252 self._validelements.append(element) 253 # find upstream element 254 pad = list(element.sink_pads())[0] 255 parent = pad.get_peer().get_parent() 256 self._markValidElements(parent)
257
258 - def _removeUnusedElements(self, element):
259 """ 260 Remove unused elements connected to srcpad(s) of element 261 """ 262 self.log("element:%s" % element) 263 for pad in element.src_pads(): 264 if pad.is_linked(): 265 peer = pad.get_peer().get_parent() 266 self._removeUnusedElements(peer) 267 if not peer in self._validelements: 268 self.log("removing %s" % peer.get_name()) 269 pad.unlink(pad.get_peer()) 270 peer.set_state(gst.STATE_NULL) 271 self.remove(peer)
272
273 - def _cleanUp(self):
274 self.log("") 275 if self._srcpad: 276 self.remove_pad(self._srcpad) 277 self._srcpad = None 278 for element in self._validelements: 279 element.set_state(gst.STATE_NULL) 280 self.remove(element) 281 self._validelements = []
282 283 ## Overrides 284
285 - def do_change_state(self, transition):
286 self.debug("transition:%r" % transition) 287 res = gst.Bin.do_change_state(self, transition) 288 if transition in [gst.STATE_CHANGE_PAUSED_TO_READY, gst.STATE_CHANGE_READY_TO_NULL]: 289 self._cleanUp() 290 return res
291 292 ## Signal callbacks 293
294 - def _typefindHaveTypeCb(self, typefind, probability, caps):
295 self.debug("probability:%d, caps:%s" % (probability, caps.to_string())) 296 self._closePadLink(typefind, typefind.get_pad("src"), caps)
297 298 ## Dynamic element Callbacks 299
300 - def _dynamicPadAddedCb(self, element, pad):
301 self.log("element:%s, pad:%s" % (element.get_name(), pad.get_name())) 302 if not self._srcpad: 303 self._closePadLink(element, pad, pad.get_caps())
304
305 - def _dynamicNoMorePadsCb(self, element):
306 self.log("element:%s" % element.get_name())
307 308 gobject.type_register(SingleDecodeBin) 309