1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 """
27 Single-stream queue-less decodebin
28 """
29
30 import gobject
31 import gst
32
33 __version__ = "$Rev$"
34
35
37 while pad:
38 if pad.props.direction == gst.PAD_SRC \
39 and isinstance(pad, gst.GhostPad):
40 pad = pad.get_target()
41 continue
42
43 if pad.props.direction == gst.PAD_SINK:
44 pad = pad.get_peer()
45 continue
46
47 element = pad.get_parent()
48 if isinstance(element, gst.Pad):
49
50 element = element.get_parent()
51
52 if element is None:
53 pad = None
54 continue
55
56 element_factory = element.get_factory()
57 element_klass = element_factory.get_klass()
58
59 if 'Demuxer' in element_klass:
60 return element, pad
61
62 sink_pads = list(element.sink_pads())
63 if len(sink_pads) > 1:
64 if element_factory.get_name() == 'multiqueue':
65 pad = element.get_pad(pad.get_name().replace('src', 'sink'))
66 else:
67 raise Exception('boom!')
68
69 elif len(sink_pads) == 0:
70 pad = None
71 else:
72 pad = sink_pads[0]
73
74 return None, None
75
76
78 log.debug("stream", "%r" % decoder)
79 klass = decoder.get_factory().get_klass()
80 parts = klass.split('/', 2)
81 if len(parts) != 3:
82 return None
83
84 return parts[2].lower()
85
86
88 lst = []
89 while pad:
90 demuxer, pad = find_upstream_demuxer_and_pad(pad)
91 if (demuxer, pad) != (None, None):
92 lst.append([demuxer.get_factory().get_name(), pad.get_name()])
93
94
95 try:
96 pad = list(demuxer.sink_pads())[0]
97 except IndexError:
98 pad = None
99
100 return lst
101
102
104 """ returns True if the caps are RAW """
105 rep = caps.to_string()
106 valid = ["video/x-raw", "audio/x-raw", "text/plain", "text/x-pango-markup"]
107 for val in valid:
108 if rep.startswith(val):
109 return True
110 return False
111
112
114 """
115 A variant of decodebin.
116
117 * Only outputs one stream
118 * Doesn't contain any internal queue
119 """
120
121 QUEUE_SIZE = 1 * gst.SECOND
122
123 __gsttemplates__ = (
124 gst.PadTemplate("sinkpadtemplate", gst.PAD_SINK, gst.PAD_ALWAYS,
125 gst.caps_new_any()),
126 gst.PadTemplate("srcpadtemplate", gst.PAD_SRC, gst.PAD_SOMETIMES,
127 gst.caps_new_any()))
128
129 - def __init__(self, caps=None, uri=None, stream=None, *args, **kwargs):
130 gst.Bin.__init__(self, *args, **kwargs)
131
132 if not caps:
133 caps = gst.caps_new_any()
134 self.caps = caps
135 self.stream = stream
136 self.typefind = gst.element_factory_make("typefind",
137 "internal-typefind")
138 self.add(self.typefind)
139
140 self.uri = uri
141 if self.uri and gst.uri_is_valid(self.uri):
142 self.urisrc = gst.element_make_from_uri(gst.URI_SRC, uri, "urisrc")
143 self.log("created urisrc %s / %r" % (self.urisrc.get_name(),
144 self.urisrc))
145 self.add(self.urisrc)
146 self.urisrc.link(self.typefind)
147 else:
148 self._sinkpad = gst.GhostPad("sink", self.typefind.get_pad("sink"))
149 self._sinkpad.set_active(True)
150 self.add_pad(self._sinkpad)
151
152 self.typefind.connect("have_type", self._typefindHaveTypeCb)
153
154 self._srcpad = None
155
156 self._dynamics = []
157
158 self._validelements = []
159
160 self._factories = self._getSortedFactoryList()
161
162
163
164
170
172 """
173 Returns the list of demuxers, decoders and parsers available, sorted
174 by rank
175 """
176
177 def _myfilter(fact):
178 if fact.get_rank() < 64:
179 return False
180 klass = fact.get_klass()
181 if not ("Demuxer" in klass or "Decoder" in klass \
182 or "Parse" in klass):
183 return False
184 return True
185 reg = gst.registry_get_default()
186 res = [x for x in reg.get_feature_list(gst.ElementFactory) \
187 if _myfilter(x)]
188 res.sort(lambda a, b: int(b.get_rank() - a.get_rank()))
189 return res
190
192 """
193 Returns a list of factories (sorted by rank) which can take caps as
194 input. Returns empty list if none are compatible
195 """
196 self.debug("caps:%s" % caps.to_string())
197 res = []
198 for factory in self._factories:
199 for template in factory.get_static_pad_templates():
200 if template.direction == gst.PAD_SINK:
201 intersect = caps.intersect(template.static_caps.get())
202 if not intersect.is_empty():
203 res.append(factory)
204 break
205 self.debug("returning %r" % res)
206 return res
207
209 """
210 Inspects element and tries to connect something on the srcpads.
211 If there are dynamic pads, it sets up a signal handler to
212 continue autoplugging when they become available.
213 """
214 to_connect = []
215 dynamic = False
216 templates = element.get_pad_template_list()
217 for template in templates:
218 if not template.direction == gst.PAD_SRC:
219 continue
220 if template.presence == gst.PAD_ALWAYS:
221 pad = element.get_pad(template.name_template)
222 to_connect.append(pad)
223 elif template.presence == gst.PAD_SOMETIMES:
224 pad = element.get_pad(template.name_template)
225 if pad:
226 to_connect.append(pad)
227 else:
228 dynamic = True
229 else:
230 self.log("Template %s is a request pad, ignoring" % (
231 pad.name_template))
232
233 if dynamic:
234 self.debug("%s is a dynamic element" % element.get_name())
235 self._controlDynamicElement(element)
236
237 for pad in to_connect:
238 self._closePadLink(element, pad, pad.get_caps())
239
241 if not 'Demux' in element.get_factory().get_klass():
242 return False
243
244 potential_src_pads = 0
245 for template in element.get_pad_template_list():
246 if template.direction != gst.PAD_SRC:
247 continue
248
249 if template.presence == gst.PAD_REQUEST or \
250 "%" in template.name_template:
251 potential_src_pads += 2
252 break
253 else:
254 potential_src_pads += 1
255
256 return potential_src_pads > 1
257
259 queue = gst.element_factory_make("queue")
260 queue.props.max_size_time = self.QUEUE_SIZE
261 self.add(queue)
262 queue.sync_state_with_parent()
263 pad.link(queue.get_pad("sink"))
264 pad = queue.get_pad("src")
265
266 return pad
267
269 """
270 Tries to link one of the factories' element to the given pad.
271
272 Returns the element that was successfully linked to the pad.
273 """
274 self.debug("source:%s, pad:%s , factories:%r" % (source.get_name(),
275 pad.get_name(),
276 factories))
277
278 if self._isDemuxer(source):
279 pad = self._plugDecodingQueue(pad)
280
281 result = None
282 for factory in factories:
283 element = factory.create()
284 if not element:
285 self.warning("weren't able to create element from %r" % (
286 factory))
287 continue
288
289 sinkpad = element.get_pad("sink")
290 if not sinkpad:
291 continue
292
293 self.add(element)
294 element.set_state(gst.STATE_READY)
295 try:
296 pad.link(sinkpad)
297 except:
298 element.set_state(gst.STATE_NULL)
299 self.remove(element)
300 continue
301
302 self._closeLink(element)
303 element.set_state(gst.STATE_PAUSED)
304
305 result = element
306 break
307
308 return result
309
311 """
312 Finds the list of elements that could connect to the pad.
313 If the pad has the desired caps, it will create a ghostpad.
314 If no compatible elements could be found, the search will stop.
315 """
316 self.debug("element:%s, pad:%s, caps:%s" % (element.get_name(),
317 pad.get_name(),
318 caps.to_string()))
319 if caps.is_empty():
320 self.log("unknown type")
321 return
322 if caps.is_any():
323 self.log("type is not know yet, waiting")
324 return
325
326 if caps.intersect(self.caps) and (self.stream is None or
327 (self.stream.pad_id == get_pad_id(pad))):
328
329 if not self._srcpad:
330 self._wrapUp(element, pad)
331 elif is_raw(caps):
332 self.log("We hit a raw caps which isn't the wanted one")
333
334
335 else:
336
337 if len(caps) > 1:
338 self.log("many possible types, delaying")
339 return
340 facts = self._findCompatibleFactory(caps)
341 if not facts:
342 self.log("unknown type")
343 return
344 self._tryToLink1(element, pad, facts)
345
347 """
348 Ghost the given pad of element.
349 Remove non-used elements.
350 """
351
352 if self._srcpad:
353 return
354 self._markValidElements(element)
355 self._removeUnusedElements(self.typefind)
356 self.log("ghosting pad %s" % pad.get_name())
357 self._srcpad = gst.GhostPad("src", pad)
358 self._srcpad.set_active(True)
359 self.add_pad(self._srcpad)
360 self.post_message(gst.message_new_state_dirty(self))
361
363 """
364 Mark this element and upstreams as valid
365 """
366 self.log("element:%s" % element.get_name())
367 if element == self.typefind:
368 return
369 self._validelements.append(element)
370
371 pad = list(element.sink_pads())[0]
372 parent = pad.get_peer().get_parent()
373 self._markValidElements(parent)
374
376 """
377 Remove unused elements connected to srcpad(s) of element
378 """
379 self.log("element:%r" % element)
380 for pad in element.src_pads():
381 if pad.is_linked():
382 peer = pad.get_peer().get_parent()
383 self._removeUnusedElements(peer)
384 if not peer in self._validelements:
385 self.log("removing %s" % peer.get_name())
386 pad.unlink(pad.get_peer())
387 peer.set_state(gst.STATE_NULL)
388 self.remove(peer)
389
391 self.log("")
392 if self._srcpad:
393 self.remove_pad(self._srcpad)
394 self._srcpad = None
395 for element in self._validelements:
396 element.set_state(gst.STATE_NULL)
397 self.remove(element)
398 self._validelements = []
399
400
401
403 self.debug("transition:%r" % transition)
404 res = gst.Bin.do_change_state(self, transition)
405 if transition == gst.STATE_CHANGE_PAUSED_TO_READY:
406 self._cleanUp()
407 return res
408
409
410
412 self.debug("probability:%d, caps:%s" % (probability, caps.to_string()))
413 self._closePadLink(typefind, typefind.get_pad("src"), caps)
414
415
416
418 self.log("element:%s, pad:%s" % (element.get_name(), pad.get_name()))
419 if not self._srcpad:
420 self._closePadLink(element, pad, pad.get_caps())
421
423 self.log("element:%s" % element.get_name())
424
425 gobject.type_register(SingleDecodeBin)
426