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