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.
22 # This program is free software; you can redistribute it and/or modify
23 # it under the terms of the GNU General Public License as published by
24 # the Free Software Foundation; either version 3, or (at your option)
31 from ..overrides import override
32 from ..module import get_introspection_module
34 from gi.repository import GLib
37 Gst = get_introspection_module('Gst')
41 if Gst._version == '0.10':
43 warn_msg = "You have imported the Gst 0.10 module. Because Gst 0.10 \
44 was not designed for use with introspection some of the \
45 interfaces and API will fail. As such this is not supported \
46 by the GStreamer development team and we encourage you to \
47 port your app to Gst 1 or greater. gst-python is the recommended \
48 python module to use with Gst 0.10"
50 warnings.warn(warn_msg, RuntimeWarning)
53 class Element(Gst.Element):
57 @raises: Gst.LinkError
59 for pair in pairwise(args):
60 if not pair[0].link(pair[1]):
62 'Failed to link {} and {}'.format(pair[0], pair[1]))
64 Element = override(Element)
65 __all__.append('Element')
69 def __init__(self, name=None):
70 Gst.Bin.__init__(self, name=name)
74 if not Gst.Bin.add(self, arg):
77 def make_and_add(self, factory_name, instance_name=None):
81 elem = Gst.ElementFactory.make(factory_name, instance_name)
84 'No such element: {}'.format(factory_name))
94 def __nonzero__(self):
95 return not self.is_empty()
97 def __new__(cls, *args):
99 return Caps.new_empty()
101 raise TypeError("wrong arguments when creating GstCaps object")
102 elif isinstance(args[0], str):
103 return Caps.from_string(args[0])
104 elif isinstance(args[0], Caps):
105 return args[0].copy()
106 elif isinstance(args[0], Structure):
107 res = Caps.new_empty()
108 res.append_structure(args[0])
110 elif isinstance(args[0], (list, tuple)):
111 res = Caps.new_empty()
113 res.append_structure(e)
116 raise TypeError("wrong arguments when creating GstCaps object")
118 def __init__(self, *args, **kwargs):
119 return super(Caps, self).__init__()
122 return self.to_string()
124 def __getitem__(self, index):
125 if index >= self.get_size():
126 raise IndexError('structure index out of range')
127 return self.get_structure(index)
130 return self.get_size()
132 Caps = override(Caps)
133 __all__.append('Caps')
136 def __init__(self, func):
139 def __call__(self, pad, parent, obj):
140 if isinstance(self.func, weakref.WeakMethod):
149 res = func(pad, parent, obj)
151 raise TypeError("Invalid method %s, 2 or 3 arguments required"
157 def __init__(self, *args, **kwargs):
158 super(Gst.Pad, self).__init__(*args, **kwargs)
160 def set_chain_function(self, func):
161 self.set_chain_function_full(PadFunc(func), None)
163 def set_event_function(self, func):
164 self.set_event_function_full(PadFunc(func), None)
166 def set_query_function(self, func):
167 self.set_query_function_full(PadFunc(func), None)
169 def query_caps(self, filter=None):
170 return Gst.Pad.query_caps(self, filter)
172 def set_caps(self, caps):
173 if not isinstance(caps, Gst.Caps):
174 raise TypeError("%s is not a Gst.Caps." % (type(caps)))
176 if not caps.is_fixed():
179 event = Gst.Event.new_caps(caps)
181 if self.direction == Gst.PadDirection.SRC:
182 res = self.push_event(event)
184 res = self.send_event(event)
189 ret = Gst.Pad.link(self, pad)
190 if ret != Gst.PadLinkReturn.OK:
195 __all__.append('Pad')
197 class GhostPad(Gst.GhostPad):
198 def __init__(self, name, target=None, direction=None):
199 if direction is None:
201 raise TypeError('you must pass at least one of target '
203 direction = target.props.direction
205 Gst.GhostPad.__init__(self, name=name, direction=direction)
207 if target is not None:
208 self.set_target(target)
210 def query_caps(self, filter=None):
211 return Gst.GhostPad.query_caps(self, filter)
213 GhostPad = override(GhostPad)
214 __all__.append('GhostPad')
216 class IteratorError(Exception):
218 __all__.append('IteratorError')
220 class AddError(Exception):
222 __all__.append('AddError')
224 class LinkError(Exception):
226 __all__.append('LinkError')
228 class MapError(Exception):
230 __all__.append('MapError')
233 class Iterator(Gst.Iterator):
236 result, value = self.next()
237 if result == Gst.IteratorResult.DONE:
240 if result != Gst.IteratorResult.OK:
241 raise IteratorError(result)
245 Iterator = override(Iterator)
246 __all__.append('Iterator')
249 class ElementFactory(Gst.ElementFactory):
252 def get_longname(self):
253 return self.get_metadata("long-name")
255 def get_description(self):
256 return self.get_metadata("description")
259 return self.get_metadata("klass")
262 def make(cls, factory_name, instance_name=None):
263 return Gst.ElementFactory.make(factory_name, instance_name)
265 class Pipeline(Gst.Pipeline):
266 def __init__(self, name=None):
267 Gst.Pipeline.__init__(self, name=name)
269 Pipeline = override(Pipeline)
270 __all__.append('Pipeline')
272 class Structure(Gst.Structure):
273 def __new__(cls, *args, **kwargs):
276 raise TypeError("wrong arguments when creating GstStructure, first argument"
277 " must be the structure name.")
278 return Structure.new_empty()
280 raise TypeError("wrong arguments when creating GstStructure object")
281 elif isinstance(args[0], str):
283 return Structure.from_string(args[0])[0]
284 struct = Structure.new_empty(args[0])
285 for k, v in kwargs.items():
289 elif isinstance(args[0], Structure):
290 return args[0].copy()
292 raise TypeError("wrong arguments when creating GstStructure object")
294 def __init__(self, *args, **kwargs):
297 def __getitem__(self, key):
298 return self.get_value(key)
302 def foreach(fid, value, unused1, udata):
303 keys.add(GLib.quark_to_string(fid))
306 self.foreach(foreach, None, None)
309 def __setitem__(self, key, value):
310 return self.set_value(key, value)
313 return self.to_string()
315 Structure = override(Structure)
316 __all__.append('Structure')
318 ElementFactory = override(ElementFactory)
319 __all__.append('ElementFactory')
321 class Fraction(Gst.Fraction):
322 def __init__(self, num, denom=1):
338 # Compute greatest common divisor
339 gcd = __gcd(num, denom)
351 self.type = "fraction"
354 return '<Gst.Fraction %s>' % (str(self))
357 return self.num / self.denom
359 def __eq__(self, other):
360 if isinstance(other, Fraction):
361 return self.num * other.denom == other.num * self.denom
364 def __ne__(self, other):
365 return not self.__eq__(other)
367 def __mul__(self, other):
368 if isinstance(other, Fraction):
369 return Fraction(self.num * other.num,
370 self.denom * other.denom)
371 elif isinstance(other, int):
372 return Fraction(self.num * other, self.denom)
373 raise TypeError("%s is not supported, use Gst.Fraction or int." %
378 def __truediv__(self, other):
379 if isinstance(other, Fraction):
380 return Fraction(self.num * other.denom,
381 self.denom * other.num)
382 elif isinstance(other, int):
383 return Fraction(self.num, self.denom * other)
384 return TypeError("%s is not supported, use Gst.Fraction or int." %
387 __div__ = __truediv__
389 def __rtruediv__(self, other):
390 if isinstance(other, int):
391 return Fraction(self.denom * other, self.num)
392 return TypeError("%s is not an int." % (type(other)))
394 __rdiv__ = __rtruediv__
397 return float(self.num) / float(self.denom)
400 return '%d/%d' % (self.num, self.denom)
402 Fraction = override(Fraction)
403 __all__.append('Fraction')
406 class IntRange(Gst.IntRange):
407 def __init__(self, r):
408 if not isinstance(r, range):
409 raise TypeError("%s is not a range." % (type(r)))
411 if (r.start >= r.stop):
412 raise TypeError("Range start must be smaller then stop")
414 if r.start % r.step != 0:
415 raise TypeError("Range start must be a multiple of the step")
417 if r.stop % r.step != 0:
418 raise TypeError("Range stop must be a multiple of the step")
423 return '<Gst.IntRange [%d,%d,%d]>' % (self.range.start,
424 self.range.stop, self.range.step)
427 if self.range.step == 1:
428 return '[%d,%d]' % (self.range.start, self.range.stop)
430 return '[%d,%d,%d]' % (self.range.start, self.range.stop,
433 def __eq__(self, other):
434 if isinstance(other, range):
435 return self.range == other
436 elif isinstance(other, IntRange):
437 return self.range == other.range
440 if sys.version_info >= (3, 0):
441 IntRange = override(IntRange)
442 __all__.append('IntRange')
445 class Int64Range(Gst.Int64Range):
446 def __init__(self, r):
447 if not isinstance(r, range):
448 raise TypeError("%s is not a range." % (type(r)))
450 if (r.start >= r.stop):
451 raise TypeError("Range start must be smaller then stop")
453 if r.start % r.step != 0:
454 raise TypeError("Range start must be a multiple of the step")
456 if r.stop % r.step != 0:
457 raise TypeError("Range stop must be a multiple of the step")
462 return '<Gst.Int64Range [%d,%d,%d]>' % (self.range.start,
463 self.range.stop, self.range.step)
466 if self.range.step == 1:
467 return '(int64)[%d,%d]' % (self.range.start, self.range.stop)
469 return '(int64)[%d,%d,%d]' % (self.range.start, self.range.stop,
472 def __eq__(self, other):
473 if isinstance(other, range):
474 return self.range == other
475 elif isinstance(other, IntRange):
476 return self.range == other.range
479 class Bitmask(Gst.Bitmask):
480 def __init__(self, v):
481 if not isinstance(v, int):
482 raise TypeError("%s is not an int." % (type(v)))
489 def __eq__(self, other):
490 return self.v == other
493 Bitmask = override(Bitmask)
494 __all__.append('Bitmask')
497 if sys.version_info >= (3, 0):
498 Int64Range = override(Int64Range)
499 __all__.append('Int64Range')
502 class DoubleRange(Gst.DoubleRange):
503 def __init__(self, start, stop):
504 self.start = float(start)
505 self.stop = float(stop)
508 raise TypeError("Range start must be smaller then stop")
511 return '<Gst.DoubleRange [%s,%s]>' % (str(self.start), str(self.stop))
514 return '(double)[%s,%s]' % (str(self.range.start), str(self.range.stop))
517 DoubleRange = override(DoubleRange)
518 __all__.append('DoubleRange')
521 class FractionRange(Gst.FractionRange):
522 def __init__(self, start, stop):
523 if not isinstance(start, Gst.Fraction):
524 raise TypeError("%s is not a Gst.Fraction." % (type(start)))
526 if not isinstance(stop, Gst.Fraction):
527 raise TypeError("%s is not a Gst.Fraction." % (type(stop)))
529 if (float(start) >= float(stop)):
530 raise TypeError("Range start must be smaller then stop")
536 return '<Gst.FractionRange [%s,%s]>' % (str(self.start),
540 return '(fraction)[%s,%s]' % (str(self.start), str(self.stop))
542 FractionRange = override(FractionRange)
543 __all__.append('FractionRange')
546 class ValueArray(Gst.ValueArray):
547 def __init__(self, array):
548 self.array = list(array)
550 def __getitem__(self, index):
551 return self.array[index]
553 def __setitem__(self, index, value):
554 self.array[index] = value
557 return len(self.array)
560 return '<' + ','.join(map(str,self.array)) + '>'
563 return '<Gst.ValueArray %s>' % (str(self))
565 ValueArray = override(ValueArray)
566 __all__.append('ValueArray')
569 class ValueList(Gst.ValueList):
570 def __init__(self, array):
571 self.array = list(array)
573 def __getitem__(self, index):
574 return self.array[index]
576 def __setitem__(self, index, value):
577 self.array[index] = value
580 return len(self.array)
583 return '{' + ','.join(map(str,self.array)) + '}'
586 return '<Gst.ValueList %s>' % (str(self))
588 ValueList = override(ValueList)
589 __all__.append('ValueList')
591 # From https://docs.python.org/3/library/itertools.html
594 def pairwise(iterable):
595 a, b = itertools.tee(iterable)
602 self.flags = Gst.MapFlags(0)
606 self.user_data = None
607 self.__parent__ = None
612 def __exit__(self, type, value, tb):
613 self.__parent__.unmap(self)
615 __all__.append("MapInfo")
617 class Buffer(Gst.Buffer):
619 def map_range(self, idx, length, flags):
621 if (_gi_gst.buffer_override_map_range(self, mapinfo, idx, length, int(flags))):
622 mapinfo.__parent__ = self
624 raise MapError('MappingError','Buffer mapping was not successfull')
626 def map(self, flags):
628 if _gi_gst.buffer_override_map(self, mapinfo, int(flags)):
629 mapinfo.__parent__ = self
631 raise MapError('MappingError','Buffer mapping was not successfull')
633 def unmap(self, mapinfo):
634 mapinfo.__parent__ = None
635 if _gi_gst.buffer_override_unmap(self, mapinfo) is not True:
636 raise MapError('UnmappingError','Buffer unmapping was not successfull')
638 Buffer = override(Buffer)
639 __all__.append('Buffer')
641 class Memory(Gst.Memory):
643 def map(self, flags):
645 if (_gi_gst.memory_override_map(self, mapinfo, int(flags))):
646 mapinfo.__parent__ = self
648 raise MapError('MappingError','Memory mapping was not successfull')
650 def unmap(self, mapinfo):
651 mapinfo.__parent__ = None
652 if _gi_gst.memory_override_unmap(self, mapinfo) is not True:
653 raise MapError('UnmappingError','Memory unmapping was not successfull')
655 Memory = override(Memory)
656 __all__.append('Memory')
659 if time == Gst.CLOCK_TIME_NONE:
660 return "CLOCK_TIME_NONE"
662 return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60),
663 (time / (Gst.SECOND * 60)) % 60,
664 (time / Gst.SECOND) % 60,
666 __all__.append('TIME_ARGS')
668 from gi.overrides import _gi_gst
671 # maybe more python and less C some day if core turns a bit more introspection
672 # and binding friendly in the debug area
673 Gst.trace = _gi_gst.trace
674 Gst.log = _gi_gst.log
675 Gst.debug = _gi_gst.debug
676 Gst.info = _gi_gst.info
677 Gst.warning = _gi_gst.warning
678 Gst.error = _gi_gst.error
679 Gst.fixme = _gi_gst.fixme
680 Gst.memdump = _gi_gst.memdump
682 # Make sure PyGst is not usable if GStreamer has not been initialized
683 class NotInitialized(Exception):
685 __all__.append('NotInitialized')
687 def fake_method(*args):
688 raise NotInitialized("Please call Gst.init(argv) before using GStreamer")
691 real_functions = [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.init))]
694 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))]:
695 class_methods.append((cname_klass,
696 [(o, cname_klass[1].__dict__[o])
697 for o in cname_klass[1].__dict__
698 if isinstance(cname_klass[1].__dict__[o], type(Gst.init))]))
701 for fname, function in real_functions:
702 if fname not in ["init", "init_check", "deinit"]:
703 setattr(Gst, fname, function)
705 for cname_class, methods in class_methods:
706 for mname, method in methods:
707 setattr(cname_class[1], mname, method)
711 for fname, func in real_functions:
712 if fname not in ["init", "init_check", "deinit", "is_initialized"]:
713 setattr(Gst, fname, fake_method)
714 for cname_class, methods in class_methods:
715 for mname, method in methods:
716 setattr(cname_class[1], mname, fake_method)
721 return real_init(argv)
724 real_init_check = Gst.init_check
725 def init_check(argv):
727 return real_init_check(argv)
728 Gst.init_check = init_check
730 real_deinit = Gst.deinit
737 if not Gst.is_initialized():