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