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 """
28 Single-stream queue-less decodebin
29 """
30
31 import gobject
32 import gst
33
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
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 = []
82
83 self._factories = self._getSortedFactoryList()
84
85
86
87
93
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
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
129 """
130 Inspects element and tries to connect something on the srcpads.
131 If there are dynamic pads, it sets up a signal handler to
132 continue autoplugging when they become available.
133 """
134 to_connect = []
135 dynamic = False
136 templates = element.get_pad_template_list()
137 for template in templates:
138 if not template.direction == gst.PAD_SRC:
139 continue
140 if template.presence == gst.PAD_ALWAYS:
141 pad = element.get_pad(template.name_template)
142 to_connect.append(pad)
143 elif template.presence == gst.PAD_SOMETIMES:
144 pad = element.get_pad(template.name_template)
145 if pad:
146 to_connect.append(pad)
147 else:
148 dynamic = True
149 else:
150 self.log("Template %s is a request pad, ignoring" % pad.name_template)
151
152 if dynamic:
153 self.debug("%s is a dynamic element" % element.get_name())
154 self._controlDynamicElement(element)
155
156 for pad in to_connect:
157 self._closePadLink(element, pad, pad.get_caps())
158
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
196 """
197 Finds the list of elements that could connect to the pad.
198 If the pad has the desired caps, it will create a ghostpad.
199 If no compatible elements could be found, the search will stop.
200 """
201 self.debug("element:%s, pad:%s, caps:%s" % (element.get_name(),
202 pad.get_name(),
203 caps.to_string()))
204 if caps.is_empty():
205 self.log("unknown type")
206 return
207 if caps.is_any():
208 self.log("type is not know yet, waiting")
209 return
210 if caps.intersect(self.caps):
211
212 if not self._srcpad:
213 self._wrapUp(element, pad)
214 elif is_raw(caps):
215 self.log("We hit a raw caps which isn't the wanted one")
216
217
218 else:
219
220 if len(caps) > 1:
221 self.log("many possible types, delaying")
222 return
223 facts = self._findCompatibleFactory(caps)
224 if not facts:
225 self.log("unknown type")
226 return
227 self._tryToLink1(element, pad, facts)
228
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
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
254 pad = list(element.sink_pads())[0]
255 parent = pad.get_peer().get_parent()
256 self._markValidElements(parent)
257
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
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
284
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
293
295 self.debug("probability:%d, caps:%s" % (probability, caps.to_string()))
296 self._closePadLink(typefind, typefind.get_pad("src"), caps)
297
298
299
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
306 self.log("element:%s" % element.get_name())
307
308 gobject.type_register(SingleDecodeBin)
309