python: Add a Gst.init_python function to be called from plugins
[platform/upstream/gstreamer.git] / subprojects / gst-python / gi / overrides / Gst.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 # vim: tabstop=4 shiftwidth=4 expandtab
3 #
4 #       Gst.py
5 #
6 # Copyright (C) 2012 Thibault Saunier <thibault.saunier@collabora.com>
7 #
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.
12 #
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.
17 #
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 #
23 # SPDX-License-Identifier: LGPL-2.0-or-later
24
25 import sys
26 import inspect
27 import itertools
28 import weakref
29 from ..overrides import override
30 from ..module import get_introspection_module
31
32 from gi.repository import GLib
33
34
35 Gst = get_introspection_module('Gst')
36
37 __all__ = []
38
39 if Gst._version == '0.10':
40     import warnings
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"
47
48     warnings.warn(warn_msg, RuntimeWarning)
49
50
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):
54     pass
55
56 URIHandler = override(URIHandler)
57 __all__.append('URIHandler')
58
59 class Element(Gst.Element):
60     @staticmethod
61     def link_many(*args):
62         '''
63         @raises: Gst.LinkError
64         '''
65         for pair in pairwise(args):
66             if not pair[0].link(pair[1]):
67                 raise LinkError(
68                     'Failed to link {} and {}'.format(pair[0], pair[1]))
69
70 Element = override(Element)
71 __all__.append('Element')
72
73
74 class Bin(Gst.Bin):
75     def __init__(self, name=None):
76         Gst.Bin.__init__(self, name=name)
77
78     def add(self, *args):
79         for arg in args:
80             if not Gst.Bin.add(self, arg):
81                 raise AddError(arg)
82
83     def make_and_add(self, factory_name, instance_name=None):
84         '''
85         @raises: Gst.AddError
86         '''
87         elem = Gst.ElementFactory.make(factory_name, instance_name)
88         if not elem:
89             raise AddError(
90                 'No such element: {}'.format(factory_name))
91         self.add(elem)
92         return elem
93
94
95 Bin = override(Bin)
96 __all__.append('Bin')
97
98 class Caps(Gst.Caps):
99
100     def __nonzero__(self):
101         return not self.is_empty()
102
103     def __new__(cls, *args):
104         if not args:
105             return Caps.new_empty()
106         elif len(args) > 1:
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])
115             return res
116         elif isinstance(args[0], (list, tuple)):
117             res = Caps.new_empty()
118             for e in args[0]:
119                 res.append_structure(e)
120             return res
121
122         raise TypeError("wrong arguments when creating GstCaps object")
123
124     def __init__(self, *args, **kwargs):
125         return super(Caps, self).__init__()
126
127     def __str__(self):
128         return self.to_string()
129
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)
134
135     def __len__(self):
136         return self.get_size()
137
138 Caps = override(Caps)
139 __all__.append('Caps')
140
141 class PadFunc:
142     def __init__(self, func):
143         self.func = func
144
145     def __call__(self, pad, parent, obj):
146         if isinstance(self.func, weakref.WeakMethod):
147             func = self.func()
148         else:
149             func = self.func
150
151         try:
152             res = func(pad, obj)
153         except TypeError:
154             try:
155                 res = func(pad, parent, obj)
156             except TypeError:
157                 raise TypeError("Invalid method %s, 2 or 3 arguments required"
158                                 % func)
159
160         return res
161
162 class Pad(Gst.Pad):
163     def __init__(self, *args, **kwargs):
164         super(Gst.Pad, self).__init__(*args, **kwargs)
165
166     def set_chain_function(self, func):
167         self.set_chain_function_full(PadFunc(func), None)
168
169     def set_event_function(self, func):
170         self.set_event_function_full(PadFunc(func), None)
171
172     def set_query_function(self, func):
173         self.set_query_function_full(PadFunc(func), None)
174
175     def query_caps(self, filter=None):
176         return Gst.Pad.query_caps(self, filter)
177
178     def set_caps(self, caps):
179         if not isinstance(caps, Gst.Caps):
180             raise TypeError("%s is not a Gst.Caps." % (type(caps)))
181
182         if not caps.is_fixed():
183             return False
184
185         event = Gst.Event.new_caps(caps)
186
187         if self.direction == Gst.PadDirection.SRC:
188             res = self.push_event(event)
189         else:
190             res = self.send_event(event)
191
192         return res
193
194     def link(self, pad):
195         ret = Gst.Pad.link(self, pad)
196         if ret != Gst.PadLinkReturn.OK:
197             raise LinkError(ret)
198         return ret
199
200 Pad = override(Pad)
201 __all__.append('Pad')
202
203 class GhostPad(Gst.GhostPad):
204     def __init__(self, name, target=None, direction=None):
205         if direction is None:
206             if target is None:
207                 raise TypeError('you must pass at least one of target '
208                                 'and direction')
209             direction = target.props.direction
210
211         Gst.GhostPad.__init__(self, name=name, direction=direction)
212         self.construct()
213         if target is not None:
214             self.set_target(target)
215
216     def query_caps(self, filter=None):
217         return Gst.GhostPad.query_caps(self, filter)
218
219 GhostPad = override(GhostPad)
220 __all__.append('GhostPad')
221
222 class IteratorError(Exception):
223     pass
224 __all__.append('IteratorError')
225
226 class AddError(Exception):
227     pass
228 __all__.append('AddError')
229
230 class LinkError(Exception):
231     pass
232 __all__.append('LinkError')
233
234 class MapError(Exception):
235     pass
236 __all__.append('MapError')
237
238
239 class Iterator(Gst.Iterator):
240     def __iter__(self):
241         while True:
242             result, value = self.next()
243             if result == Gst.IteratorResult.DONE:
244                 break
245
246             if result != Gst.IteratorResult.OK:
247                 raise IteratorError(result)
248
249             yield value
250
251 Iterator = override(Iterator)
252 __all__.append('Iterator')
253
254
255 class ElementFactory(Gst.ElementFactory):
256
257     # ElementFactory
258     def get_longname(self):
259         return self.get_metadata("long-name")
260
261     def get_description(self):
262         return self.get_metadata("description")
263
264     def get_klass(self):
265         return self.get_metadata("klass")
266
267     @classmethod
268     def make(cls, factory_name, instance_name=None):
269         return Gst.ElementFactory.make(factory_name, instance_name)
270
271 class Pipeline(Gst.Pipeline):
272     def __init__(self, name=None):
273         Gst.Pipeline.__init__(self, name=name)
274
275 Pipeline = override(Pipeline)
276 __all__.append('Pipeline')
277
278 class Structure(Gst.Structure):
279     def __new__(cls, *args, **kwargs):
280         if not args:
281             if kwargs:
282                 raise TypeError("wrong arguments when creating GstStructure, first argument"
283                                 " must be the structure name.")
284             return Structure.new_empty()
285         elif len(args) > 1:
286             raise TypeError("wrong arguments when creating GstStructure object")
287         elif isinstance(args[0], str):
288             if not kwargs:
289                 return Structure.from_string(args[0])[0]
290             struct = Structure.new_empty(args[0])
291             for k, v in kwargs.items():
292                 struct[k] = v
293
294             return struct
295         elif isinstance(args[0], Structure):
296             return args[0].copy()
297
298         raise TypeError("wrong arguments when creating GstStructure object")
299
300     def __init__(self, *args, **kwargs):
301         pass
302
303     def __getitem__(self, key):
304         return self.get_value(key)
305
306     def keys(self):
307         keys = set()
308         def foreach(fid, value, unused1, udata):
309             keys.add(GLib.quark_to_string(fid))
310             return True
311
312         self.foreach(foreach, None, None)
313         return keys
314
315     def __setitem__(self, key, value):
316         return self.set_value(key, value)
317
318     def __str__(self):
319         return self.to_string()
320
321 Structure = override(Structure)
322 __all__.append('Structure')
323
324 ElementFactory = override(ElementFactory)
325 __all__.append('ElementFactory')
326
327 class Fraction(Gst.Fraction):
328     def __init__(self, num, denom=1):
329         def __gcd(a, b):
330             while b != 0:
331                 tmp = a
332                 a = b
333                 b = tmp % b
334             return abs(a)
335
336         def __simplify():
337             num = self.num
338             denom = self.denom
339
340             if num < 0:
341                 num = -num
342                 denom = -denom
343
344             # Compute greatest common divisor
345             gcd = __gcd(num, denom)
346             if gcd != 0:
347                 num /= gcd
348                 denom /= gcd
349
350             self.num = num
351             self.denom = denom
352
353         self.num = num
354         self.denom = denom
355
356         __simplify()
357         self.type = "fraction"
358
359     def __repr__(self):
360         return '<Gst.Fraction %s>' % (str(self))
361
362     def __value__(self):
363         return self.num / self.denom
364
365     def __eq__(self, other):
366         if isinstance(other, Fraction):
367             return self.num * other.denom == other.num * self.denom
368         return False
369
370     def __ne__(self, other):
371         return not self.__eq__(other)
372
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." %
380                 (type(other)))
381
382     __rmul__ = __mul__
383
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." %
391                 (type(other)))
392
393     __div__ = __truediv__
394
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)))
399
400     __rdiv__ = __rtruediv__
401
402     def __float__(self):
403         return float(self.num) / float(self.denom)
404
405     def __str__(self):
406         return '%d/%d' % (self.num, self.denom)
407
408 Fraction = override(Fraction)
409 __all__.append('Fraction')
410
411
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)))
416
417         if (r.start >= r.stop):
418             raise TypeError("Range start must be smaller then stop")
419
420         if r.start % r.step != 0:
421             raise TypeError("Range start must be a multiple of the step")
422
423         if r.stop % r.step != 0:
424             raise TypeError("Range stop must be a multiple of the step")
425
426         self.range = r
427
428     def __repr__(self):
429         return '<Gst.IntRange [%d,%d,%d]>' % (self.range.start,
430                 self.range.stop, self.range.step)
431
432     def __str__(self):
433         if self.range.step == 1:
434             return '[%d,%d]' % (self.range.start, self.range.stop)
435         else:
436             return '[%d,%d,%d]' % (self.range.start, self.range.stop,
437                     self.range.step)
438
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
444         return False
445
446 if sys.version_info >= (3, 0):
447     IntRange = override(IntRange)
448     __all__.append('IntRange')
449
450
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)))
455
456         if (r.start >= r.stop):
457             raise TypeError("Range start must be smaller then stop")
458
459         if r.start % r.step != 0:
460             raise TypeError("Range start must be a multiple of the step")
461
462         if r.stop % r.step != 0:
463             raise TypeError("Range stop must be a multiple of the step")
464
465         self.range = r
466
467     def __repr__(self):
468         return '<Gst.Int64Range [%d,%d,%d]>' % (self.range.start,
469                 self.range.stop, self.range.step)
470
471     def __str__(self):
472         if self.range.step == 1:
473             return '(int64)[%d,%d]' % (self.range.start, self.range.stop)
474         else:
475             return '(int64)[%d,%d,%d]' % (self.range.start, self.range.stop,
476                     self.range.step)
477
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
483         return False
484
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)))
489
490         self.v = int(v)
491
492     def __str__(self):
493         return hex(self.v)
494
495     def __eq__(self, other):
496         return self.v == other
497
498
499 Bitmask = override(Bitmask)
500 __all__.append('Bitmask')
501
502
503 if sys.version_info >= (3, 0):
504     Int64Range = override(Int64Range)
505     __all__.append('Int64Range')
506
507
508 class DoubleRange(Gst.DoubleRange):
509     def __init__(self, start, stop):
510         self.start = float(start)
511         self.stop = float(stop)
512
513         if (start >= stop):
514             raise TypeError("Range start must be smaller then stop")
515
516     def __repr__(self):
517         return '<Gst.DoubleRange [%s,%s]>' % (str(self.start), str(self.stop))
518
519     def __str__(self):
520         return '(double)[%s,%s]' % (str(self.range.start), str(self.range.stop))
521
522
523 DoubleRange = override(DoubleRange)
524 __all__.append('DoubleRange')
525
526
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)))
531
532         if not isinstance(stop, Gst.Fraction):
533             raise TypeError("%s is not a Gst.Fraction." % (type(stop)))
534
535         if (float(start) >= float(stop)):
536             raise TypeError("Range start must be smaller then stop")
537
538         self.start = start
539         self.stop = stop
540
541     def __repr__(self):
542         return '<Gst.FractionRange [%s,%s]>' % (str(self.start),
543                 str(self.stop))
544
545     def __str__(self):
546         return '(fraction)[%s,%s]' % (str(self.start), str(self.stop))
547
548 FractionRange = override(FractionRange)
549 __all__.append('FractionRange')
550
551
552 class ValueArray(Gst.ValueArray):
553     def __init__(self, array):
554         self.array = list(array)
555
556     def __getitem__(self, index):
557         return self.array[index]
558
559     def __setitem__(self, index, value):
560         self.array[index] = value
561
562     def __len__(self):
563         return len(self.array)
564
565     def __str__(self):
566         return '<' + ','.join(map(str,self.array)) + '>'
567
568     def __repr__(self):
569         return '<Gst.ValueArray %s>' % (str(self))
570
571 ValueArray = override(ValueArray)
572 __all__.append('ValueArray')
573
574
575 class ValueList(Gst.ValueList):
576     def __init__(self, array):
577         self.array = list(array)
578
579     def __getitem__(self, index):
580         return self.array[index]
581
582     def __setitem__(self, index, value):
583         self.array[index] = value
584
585     def __len__(self):
586         return len(self.array)
587
588     def __str__(self):
589         return '{' + ','.join(map(str,self.array)) + '}'
590
591     def __repr__(self):
592         return '<Gst.ValueList %s>' % (str(self))
593
594 ValueList = override(ValueList)
595 __all__.append('ValueList')
596
597 # From https://docs.python.org/3/library/itertools.html
598
599
600 def pairwise(iterable):
601     a, b = itertools.tee(iterable)
602     next(b, None)
603     return zip(a, b)
604
605 class MapInfo:
606     def __init__(self):
607         self.memory = None
608         self.flags = Gst.MapFlags(0)
609         self.size = 0
610         self.maxsize = 0
611         self.data = None
612         self.user_data = None
613         self.__parent__ = None
614
615     def __iter__(self):
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):
619             yield i
620
621     def __enter__(self):
622         if not self.__parent__:
623             raise MapError('MappingError', 'Mapping was not successful')
624
625         return self
626
627     def __exit__(self, type, value, tb):
628         if not self.__parent__.unmap(self):
629             raise MapError('MappingError', 'Unmapping was not successful')
630
631 __all__.append("MapInfo")
632
633 class Buffer(Gst.Buffer):
634
635     def map_range(self, idx, length, flags):
636         mapinfo = MapInfo()
637         if (_gi_gst.buffer_override_map_range(self, mapinfo, idx, length, int(flags))):
638             mapinfo.__parent__ = self
639
640         return mapinfo
641
642     def map(self, flags):
643         mapinfo = MapInfo()
644         if _gi_gst.buffer_override_map(self, mapinfo, int(flags)):
645             mapinfo.__parent__ = self
646
647         return mapinfo
648
649     def unmap(self, mapinfo):
650         mapinfo.__parent__ = None
651         return _gi_gst.buffer_override_unmap(self, mapinfo)
652
653 Buffer = override(Buffer)
654 __all__.append('Buffer')
655
656 class Memory(Gst.Memory):
657
658     def map(self, flags):
659         mapinfo = MapInfo()
660         if (_gi_gst.memory_override_map(self, mapinfo, int(flags))):
661             mapinfo.__parent__ = self
662
663         return mapinfo
664
665     def unmap(self, mapinfo):
666         mapinfo.__parent__ = None
667         return _gi_gst.memory_override_unmap(self, mapinfo)
668
669 Memory = override(Memory)
670 __all__.append('Memory')
671
672 def TIME_ARGS(time):
673     if time == Gst.CLOCK_TIME_NONE:
674         return "CLOCK_TIME_NONE"
675
676     return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60),
677                                   (time / (Gst.SECOND * 60)) % 60,
678                                   (time / Gst.SECOND) % 60,
679                                   time % Gst.SECOND)
680 __all__.append('TIME_ARGS')
681
682 from gi.overrides import _gi_gst
683 _gi_gst
684
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
695
696 # Make sure PyGst is not usable if GStreamer has not been initialized
697 class NotInitialized(Exception):
698     pass
699 __all__.append('NotInitialized')
700
701 def fake_method(*args):
702     raise NotInitialized("Please call Gst.init(argv) before using GStreamer")
703
704
705 real_functions = [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.init))]
706
707 class_methods = []
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))]))
713
714 def init_pygst():
715     for fname, function in real_functions:
716         if fname not in ["init", "init_check", "deinit"]:
717             setattr(Gst, fname, function)
718
719     for cname_class, methods in class_methods:
720         for mname, method in methods:
721             setattr(cname_class[1], mname, method)
722
723
724 def deinit_pygst():
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)
731
732 real_init = Gst.init
733 def init(argv):
734     init_pygst()
735
736     if Gst.is_initialized():
737         return True
738
739     return real_init(argv)
740
741 Gst.init = init
742
743 real_init_check = Gst.init_check
744 def init_check(argv):
745     init_pygst()
746     if Gst.is_initialized():
747         return True
748
749     return real_init_check(argv)
750
751 Gst.init_check = init_check
752
753 real_deinit = Gst.deinit
754 def deinit():
755     deinit_pygst()
756     return real_deinit()
757
758 def init_python():
759     if not Gst.is_initialized():
760         raise NotInitialized("Gst.init_python should never be called before GStreamer itself is initialized")
761
762     init_pygst()
763
764 Gst.deinit = deinit
765 Gst.init_python = init_python
766
767 if not Gst.is_initialized():
768     deinit_pygst()