1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
6 # Copyright (C) 2012 Thibault Saunier <thibault.saunier@collabora.com>
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this program; if not, write to the
20 # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 # Boston, MA 02110-1301, USA.
23 # SPDX-License-Identifier: LGPL-2.0-or-later
29 from ..overrides import override
30 from ..module import get_introspection_module
32 from gi.repository import GLib
35 Gst = get_introspection_module('Gst')
39 if Gst._version == '0.10':
41 warn_msg = "You have imported the Gst 0.10 module. Because Gst 0.10 \
42 was not designed for use with introspection some of the \
43 interfaces and API will fail. As such this is not supported \
44 by the GStreamer development team and we encourage you to \
45 port your app to Gst 1 or greater. gst-python is the recommended \
46 python module to use with Gst 0.10"
48 warnings.warn(warn_msg, RuntimeWarning)
51 # Ensuring that PyGObject loads the URIHandler interface
52 # so we can force our own implementation soon enough (in gstmodule.c)
53 class URIHandler(Gst.URIHandler):
56 URIHandler = override(URIHandler)
57 __all__.append('URIHandler')
59 class Element(Gst.Element):
63 @raises: Gst.LinkError
65 for pair in pairwise(args):
66 if not pair[0].link(pair[1]):
68 'Failed to link {} and {}'.format(pair[0], pair[1]))
70 Element = override(Element)
71 __all__.append('Element')
75 def __init__(self, name=None):
76 Gst.Bin.__init__(self, name=name)
80 if not Gst.Bin.add(self, arg):
83 def make_and_add(self, factory_name, instance_name=None):
87 elem = Gst.ElementFactory.make(factory_name, instance_name)
90 'No such element: {}'.format(factory_name))
100 def __nonzero__(self):
101 return not self.is_empty()
103 def __new__(cls, *args):
105 return Caps.new_empty()
107 raise TypeError("wrong arguments when creating GstCaps object")
108 elif isinstance(args[0], str):
109 return Caps.from_string(args[0])
110 elif isinstance(args[0], Caps):
111 return args[0].copy()
112 elif isinstance(args[0], Structure):
113 res = Caps.new_empty()
114 res.append_structure(args[0])
116 elif isinstance(args[0], (list, tuple)):
117 res = Caps.new_empty()
119 res.append_structure(e)
122 raise TypeError("wrong arguments when creating GstCaps object")
124 def __init__(self, *args, **kwargs):
125 return super(Caps, self).__init__()
128 return self.to_string()
130 def __getitem__(self, index):
131 if index >= self.get_size():
132 raise IndexError('structure index out of range')
133 return self.get_structure(index)
136 return self.get_size()
138 Caps = override(Caps)
139 __all__.append('Caps')
142 def __init__(self, func):
145 def __call__(self, pad, parent, obj):
146 if isinstance(self.func, weakref.WeakMethod):
155 res = func(pad, parent, obj)
157 raise TypeError("Invalid method %s, 2 or 3 arguments required"
163 def __init__(self, *args, **kwargs):
164 super(Gst.Pad, self).__init__(*args, **kwargs)
166 def set_chain_function(self, func):
167 self.set_chain_function_full(PadFunc(func), None)
169 def set_event_function(self, func):
170 self.set_event_function_full(PadFunc(func), None)
172 def set_query_function(self, func):
173 self.set_query_function_full(PadFunc(func), None)
175 def query_caps(self, filter=None):
176 return Gst.Pad.query_caps(self, filter)
178 def set_caps(self, caps):
179 if not isinstance(caps, Gst.Caps):
180 raise TypeError("%s is not a Gst.Caps." % (type(caps)))
182 if not caps.is_fixed():
185 event = Gst.Event.new_caps(caps)
187 if self.direction == Gst.PadDirection.SRC:
188 res = self.push_event(event)
190 res = self.send_event(event)
195 ret = Gst.Pad.link(self, pad)
196 if ret != Gst.PadLinkReturn.OK:
201 __all__.append('Pad')
203 class GhostPad(Gst.GhostPad):
204 def __init__(self, name, target=None, direction=None):
205 if direction is None:
207 raise TypeError('you must pass at least one of target '
209 direction = target.props.direction
211 Gst.GhostPad.__init__(self, name=name, direction=direction)
213 if target is not None:
214 self.set_target(target)
216 def query_caps(self, filter=None):
217 return Gst.GhostPad.query_caps(self, filter)
219 GhostPad = override(GhostPad)
220 __all__.append('GhostPad')
222 class IteratorError(Exception):
224 __all__.append('IteratorError')
226 class AddError(Exception):
228 __all__.append('AddError')
230 class LinkError(Exception):
232 __all__.append('LinkError')
234 class MapError(Exception):
236 __all__.append('MapError')
239 class Iterator(Gst.Iterator):
242 result, value = self.next()
243 if result == Gst.IteratorResult.DONE:
246 if result != Gst.IteratorResult.OK:
247 raise IteratorError(result)
251 Iterator = override(Iterator)
252 __all__.append('Iterator')
255 class ElementFactory(Gst.ElementFactory):
258 def get_longname(self):
259 return self.get_metadata("long-name")
261 def get_description(self):
262 return self.get_metadata("description")
265 return self.get_metadata("klass")
268 def make(cls, factory_name, instance_name=None):
269 return Gst.ElementFactory.make(factory_name, instance_name)
271 class Pipeline(Gst.Pipeline):
272 def __init__(self, name=None):
273 Gst.Pipeline.__init__(self, name=name)
275 Pipeline = override(Pipeline)
276 __all__.append('Pipeline')
278 class Structure(Gst.Structure):
279 def __new__(cls, *args, **kwargs):
282 raise TypeError("wrong arguments when creating GstStructure, first argument"
283 " must be the structure name.")
284 return Structure.new_empty()
286 raise TypeError("wrong arguments when creating GstStructure object")
287 elif isinstance(args[0], str):
289 return Structure.from_string(args[0])[0]
290 struct = Structure.new_empty(args[0])
291 for k, v in kwargs.items():
295 elif isinstance(args[0], Structure):
296 return args[0].copy()
298 raise TypeError("wrong arguments when creating GstStructure object")
300 def __init__(self, *args, **kwargs):
303 def __getitem__(self, key):
304 return self.get_value(key)
308 def foreach(fid, value, unused1, udata):
309 keys.add(GLib.quark_to_string(fid))
312 self.foreach(foreach, None, None)
315 def __setitem__(self, key, value):
316 return self.set_value(key, value)
319 return self.to_string()
321 Structure = override(Structure)
322 __all__.append('Structure')
324 ElementFactory = override(ElementFactory)
325 __all__.append('ElementFactory')
327 class Fraction(Gst.Fraction):
328 def __init__(self, num, denom=1):
344 # Compute greatest common divisor
345 gcd = __gcd(num, denom)
357 self.type = "fraction"
360 return '<Gst.Fraction %s>' % (str(self))
363 return self.num / self.denom
365 def __eq__(self, other):
366 if isinstance(other, Fraction):
367 return self.num * other.denom == other.num * self.denom
370 def __ne__(self, other):
371 return not self.__eq__(other)
373 def __mul__(self, other):
374 if isinstance(other, Fraction):
375 return Fraction(self.num * other.num,
376 self.denom * other.denom)
377 elif isinstance(other, int):
378 return Fraction(self.num * other, self.denom)
379 raise TypeError("%s is not supported, use Gst.Fraction or int." %
384 def __truediv__(self, other):
385 if isinstance(other, Fraction):
386 return Fraction(self.num * other.denom,
387 self.denom * other.num)
388 elif isinstance(other, int):
389 return Fraction(self.num, self.denom * other)
390 return TypeError("%s is not supported, use Gst.Fraction or int." %
393 __div__ = __truediv__
395 def __rtruediv__(self, other):
396 if isinstance(other, int):
397 return Fraction(self.denom * other, self.num)
398 return TypeError("%s is not an int." % (type(other)))
400 __rdiv__ = __rtruediv__
403 return float(self.num) / float(self.denom)
406 return '%d/%d' % (self.num, self.denom)
408 Fraction = override(Fraction)
409 __all__.append('Fraction')
412 class IntRange(Gst.IntRange):
413 def __init__(self, r):
414 if not isinstance(r, range):
415 raise TypeError("%s is not a range." % (type(r)))
417 if (r.start >= r.stop):
418 raise TypeError("Range start must be smaller then stop")
420 if r.start % r.step != 0:
421 raise TypeError("Range start must be a multiple of the step")
423 if r.stop % r.step != 0:
424 raise TypeError("Range stop must be a multiple of the step")
429 return '<Gst.IntRange [%d,%d,%d]>' % (self.range.start,
430 self.range.stop, self.range.step)
433 if self.range.step == 1:
434 return '[%d,%d]' % (self.range.start, self.range.stop)
436 return '[%d,%d,%d]' % (self.range.start, self.range.stop,
439 def __eq__(self, other):
440 if isinstance(other, range):
441 return self.range == other
442 elif isinstance(other, IntRange):
443 return self.range == other.range
446 if sys.version_info >= (3, 0):
447 IntRange = override(IntRange)
448 __all__.append('IntRange')
451 class Int64Range(Gst.Int64Range):
452 def __init__(self, r):
453 if not isinstance(r, range):
454 raise TypeError("%s is not a range." % (type(r)))
456 if (r.start >= r.stop):
457 raise TypeError("Range start must be smaller then stop")
459 if r.start % r.step != 0:
460 raise TypeError("Range start must be a multiple of the step")
462 if r.stop % r.step != 0:
463 raise TypeError("Range stop must be a multiple of the step")
468 return '<Gst.Int64Range [%d,%d,%d]>' % (self.range.start,
469 self.range.stop, self.range.step)
472 if self.range.step == 1:
473 return '(int64)[%d,%d]' % (self.range.start, self.range.stop)
475 return '(int64)[%d,%d,%d]' % (self.range.start, self.range.stop,
478 def __eq__(self, other):
479 if isinstance(other, range):
480 return self.range == other
481 elif isinstance(other, IntRange):
482 return self.range == other.range
485 class Bitmask(Gst.Bitmask):
486 def __init__(self, v):
487 if not isinstance(v, int):
488 raise TypeError("%s is not an int." % (type(v)))
495 def __eq__(self, other):
496 return self.v == other
499 Bitmask = override(Bitmask)
500 __all__.append('Bitmask')
503 if sys.version_info >= (3, 0):
504 Int64Range = override(Int64Range)
505 __all__.append('Int64Range')
508 class DoubleRange(Gst.DoubleRange):
509 def __init__(self, start, stop):
510 self.start = float(start)
511 self.stop = float(stop)
514 raise TypeError("Range start must be smaller then stop")
517 return '<Gst.DoubleRange [%s,%s]>' % (str(self.start), str(self.stop))
520 return '(double)[%s,%s]' % (str(self.range.start), str(self.range.stop))
523 DoubleRange = override(DoubleRange)
524 __all__.append('DoubleRange')
527 class FractionRange(Gst.FractionRange):
528 def __init__(self, start, stop):
529 if not isinstance(start, Gst.Fraction):
530 raise TypeError("%s is not a Gst.Fraction." % (type(start)))
532 if not isinstance(stop, Gst.Fraction):
533 raise TypeError("%s is not a Gst.Fraction." % (type(stop)))
535 if (float(start) >= float(stop)):
536 raise TypeError("Range start must be smaller then stop")
542 return '<Gst.FractionRange [%s,%s]>' % (str(self.start),
546 return '(fraction)[%s,%s]' % (str(self.start), str(self.stop))
548 FractionRange = override(FractionRange)
549 __all__.append('FractionRange')
552 class ValueArray(Gst.ValueArray):
553 def __init__(self, array):
554 self.array = list(array)
556 def __getitem__(self, index):
557 return self.array[index]
559 def __setitem__(self, index, value):
560 self.array[index] = value
563 return len(self.array)
566 return '<' + ','.join(map(str,self.array)) + '>'
569 return '<Gst.ValueArray %s>' % (str(self))
571 ValueArray = override(ValueArray)
572 __all__.append('ValueArray')
575 class ValueList(Gst.ValueList):
576 def __init__(self, array):
577 self.array = list(array)
579 def __getitem__(self, index):
580 return self.array[index]
582 def __setitem__(self, index, value):
583 self.array[index] = value
586 return len(self.array)
589 return '{' + ','.join(map(str,self.array)) + '}'
592 return '<Gst.ValueList %s>' % (str(self))
594 ValueList = override(ValueList)
595 __all__.append('ValueList')
597 # From https://docs.python.org/3/library/itertools.html
600 def pairwise(iterable):
601 a, b = itertools.tee(iterable)
608 self.flags = Gst.MapFlags(0)
612 self.user_data = None
613 self.__parent__ = None
616 # Make it behave like a tuple similar to the PyGObject generated API for
617 # the `Gst.Buffer.map()` and friends.
618 for i in (self.__parent__ is not None, self):
622 if not self.__parent__:
623 raise MapError('MappingError', 'Mapping was not successful')
627 def __exit__(self, type, value, tb):
628 if not self.__parent__.unmap(self):
629 raise MapError('MappingError', 'Unmapping was not successful')
631 __all__.append("MapInfo")
633 class Buffer(Gst.Buffer):
635 def map_range(self, idx, length, flags):
637 if (_gi_gst.buffer_override_map_range(self, mapinfo, idx, length, int(flags))):
638 mapinfo.__parent__ = self
642 def map(self, flags):
644 if _gi_gst.buffer_override_map(self, mapinfo, int(flags)):
645 mapinfo.__parent__ = self
649 def unmap(self, mapinfo):
650 mapinfo.__parent__ = None
651 return _gi_gst.buffer_override_unmap(self, mapinfo)
653 Buffer = override(Buffer)
654 __all__.append('Buffer')
656 class Memory(Gst.Memory):
658 def map(self, flags):
660 if (_gi_gst.memory_override_map(self, mapinfo, int(flags))):
661 mapinfo.__parent__ = self
665 def unmap(self, mapinfo):
666 mapinfo.__parent__ = None
667 return _gi_gst.memory_override_unmap(self, mapinfo)
669 Memory = override(Memory)
670 __all__.append('Memory')
673 if time == Gst.CLOCK_TIME_NONE:
674 return "CLOCK_TIME_NONE"
676 return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60),
677 (time / (Gst.SECOND * 60)) % 60,
678 (time / Gst.SECOND) % 60,
680 __all__.append('TIME_ARGS')
682 from gi.overrides import _gi_gst
685 # maybe more python and less C some day if core turns a bit more introspection
686 # and binding friendly in the debug area
687 Gst.trace = _gi_gst.trace
688 Gst.log = _gi_gst.log
689 Gst.debug = _gi_gst.debug
690 Gst.info = _gi_gst.info
691 Gst.warning = _gi_gst.warning
692 Gst.error = _gi_gst.error
693 Gst.fixme = _gi_gst.fixme
694 Gst.memdump = _gi_gst.memdump
696 # Make sure PyGst is not usable if GStreamer has not been initialized
697 class NotInitialized(Exception):
699 __all__.append('NotInitialized')
701 def fake_method(*args):
702 raise NotInitialized("Please call Gst.init(argv) before using GStreamer")
705 real_functions = [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.init))]
708 for cname_klass in [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.Element)) or isinstance(o[1], type(Gst.Caps))]:
709 class_methods.append((cname_klass,
710 [(o, cname_klass[1].__dict__[o])
711 for o in cname_klass[1].__dict__
712 if isinstance(cname_klass[1].__dict__[o], type(Gst.init))]))
715 for fname, function in real_functions:
716 if fname not in ["init", "init_check", "deinit"]:
717 setattr(Gst, fname, function)
719 for cname_class, methods in class_methods:
720 for mname, method in methods:
721 setattr(cname_class[1], mname, method)
725 for fname, func in real_functions:
726 if fname not in ["init", "init_check", "deinit", "is_initialized"]:
727 setattr(Gst, fname, fake_method)
728 for cname_class, methods in class_methods:
729 for mname, method in methods:
730 setattr(cname_class[1], mname, fake_method)
736 if Gst.is_initialized():
739 return real_init(argv)
743 real_init_check = Gst.init_check
744 def init_check(argv):
746 if Gst.is_initialized():
749 return real_init_check(argv)
751 Gst.init_check = init_check
753 real_deinit = Gst.deinit
759 if not Gst.is_initialized():
760 raise NotInitialized("Gst.init_python should never be called before GStreamer itself is initialized")
765 Gst.init_python = init_python
767 if not Gst.is_initialized():