2012-08-08 17:59:09 +00:00
|
|
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
|
|
|
# vim: tabstop=4 shiftwidth=4 expandtab
|
|
|
|
#
|
|
|
|
# Gst.py
|
|
|
|
#
|
|
|
|
# Copyright (C) 2012 Thibault Saunier <thibault.saunier@collabora.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this program; if not, write to the
|
2013-11-25 17:01:48 +00:00
|
|
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2013-12-12 11:20:12 +00:00
|
|
|
# Boston, MA 02110-1301, USA.
|
2012-08-08 17:59:09 +00:00
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 3, or (at your option)
|
|
|
|
# any later version.
|
|
|
|
|
|
|
|
import sys
|
2015-03-18 12:53:55 +00:00
|
|
|
from inspect import signature
|
2012-08-08 17:59:09 +00:00
|
|
|
from ..overrides import override
|
|
|
|
from ..importer import modules
|
2015-04-15 17:55:16 +00:00
|
|
|
from inspect import getmembers
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
|
|
|
|
if sys.version_info >= (3, 0):
|
|
|
|
_basestring = str
|
|
|
|
_callable = lambda c: hasattr(c, '__call__')
|
|
|
|
else:
|
|
|
|
_basestring = basestring
|
|
|
|
_callable = callable
|
|
|
|
|
|
|
|
Gst = modules['Gst']._introspection_module
|
|
|
|
__all__ = []
|
|
|
|
|
|
|
|
if Gst._version == '0.10':
|
|
|
|
import warnings
|
|
|
|
warn_msg = "You have imported the Gst 0.10 module. Because Gst 0.10 \
|
|
|
|
was not designed for use with introspection some of the \
|
|
|
|
interfaces and API will fail. As such this is not supported \
|
|
|
|
by the GStreamer development team and we encourage you to \
|
|
|
|
port your app to Gst 1 or greater. gst-python is the recomended \
|
|
|
|
python module to use with Gst 0.10"
|
|
|
|
|
|
|
|
warnings.warn(warn_msg, RuntimeWarning)
|
|
|
|
|
2012-11-04 16:02:24 +00:00
|
|
|
class Bin(Gst.Bin):
|
|
|
|
def __init__(self, name=None):
|
|
|
|
Gst.Bin.__init__(self, name=name)
|
|
|
|
|
|
|
|
def add(self, *args):
|
|
|
|
for arg in args:
|
|
|
|
if not Gst.Bin.add(self, arg):
|
|
|
|
raise AddError(arg)
|
|
|
|
|
|
|
|
Bin = override(Bin)
|
|
|
|
__all__.append('Bin')
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
class Caps(Gst.Caps):
|
|
|
|
|
2014-03-15 14:45:43 +00:00
|
|
|
def __nonzero__(self):
|
|
|
|
return not self.is_empty()
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
def __new__(cls, *kwargs):
|
|
|
|
if not kwargs:
|
|
|
|
return Caps.new_empty()
|
|
|
|
elif len(kwargs) > 1:
|
|
|
|
raise TypeError("wrong arguments when creating GstCaps object")
|
|
|
|
elif isinstance(kwargs[0], str):
|
|
|
|
return Caps.from_string(kwargs[0])
|
|
|
|
elif isinstance(kwargs[0], Caps):
|
|
|
|
return kwargs[0].copy()
|
|
|
|
|
|
|
|
raise TypeError("wrong arguments when creating GstCaps object")
|
|
|
|
|
2014-05-22 20:48:09 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
return super(Caps, self).__init__()
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.to_string()
|
|
|
|
|
2012-10-15 07:00:03 +00:00
|
|
|
def __getitem__(self, index):
|
|
|
|
if index >= self.get_size():
|
|
|
|
raise IndexError('structure index out of range')
|
|
|
|
return self.get_structure(index)
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return self.get_size()
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
Caps = override(Caps)
|
|
|
|
__all__.append('Caps')
|
|
|
|
|
2012-11-04 16:00:14 +00:00
|
|
|
class Pad(Gst.Pad):
|
2014-06-06 08:30:07 +00:00
|
|
|
def __init__(self):
|
|
|
|
self._real_chain_func = None
|
|
|
|
self._real_event_func = None
|
2015-03-18 12:53:55 +00:00
|
|
|
self._real_query_func = None
|
2014-06-06 08:30:07 +00:00
|
|
|
|
|
|
|
def _chain_override(self, pad, parent, buf):
|
|
|
|
return self._real_chain_func(pad, buf)
|
|
|
|
|
2015-03-18 12:53:55 +00:00
|
|
|
def _event_override(self, pad, parent, event):
|
|
|
|
return self._real_event_func(pad, event)
|
|
|
|
|
|
|
|
def _query_override(self, pad, parent, query):
|
|
|
|
query.mini_object.refcount -= 1
|
|
|
|
n_params = len(signature(self._real_query_func).parameters)
|
|
|
|
if n_params == 2:
|
|
|
|
res = self._real_query_func(pad, query)
|
|
|
|
elif n_params == 3:
|
|
|
|
res = self._real_query_func(pad, parent, query)
|
|
|
|
else:
|
|
|
|
raise TypeError("Invalid query method %s, 2 or 3 arguments requiered"
|
|
|
|
% self._real_query_func)
|
|
|
|
query.mini_object.refcount += 1
|
|
|
|
|
|
|
|
return res
|
2014-06-06 08:30:07 +00:00
|
|
|
|
|
|
|
def set_chain_function(self, func):
|
|
|
|
self._real_chain_func = func
|
|
|
|
self.set_chain_function_full(self._chain_override, None)
|
|
|
|
|
|
|
|
def set_event_function(self, func):
|
|
|
|
self._real_event_func = func
|
|
|
|
self.set_event_function_full(self._event_override, None)
|
|
|
|
|
2015-03-18 12:53:55 +00:00
|
|
|
def set_query_function(self, func):
|
|
|
|
self._real_query_func = func
|
|
|
|
self.set_query_function_full(self._chain_override, None)
|
|
|
|
|
|
|
|
def set_query_function_full(self, func, udata):
|
|
|
|
self._real_query_func = func
|
|
|
|
self._real_set_query_function_full(self._query_override, None)
|
|
|
|
|
2012-11-04 16:00:14 +00:00
|
|
|
def query_caps(self, filter=None):
|
|
|
|
return Gst.Pad.query_caps(self, filter)
|
|
|
|
|
|
|
|
def link(self, pad):
|
|
|
|
ret = Gst.Pad.link(self, pad)
|
|
|
|
if ret != Gst.PadLinkReturn.OK:
|
|
|
|
raise LinkError(ret)
|
|
|
|
return ret
|
|
|
|
|
2015-03-18 12:53:55 +00:00
|
|
|
Pad._real_set_query_function_full = Gst.Pad.set_query_function_full
|
2012-11-04 16:00:14 +00:00
|
|
|
Pad = override(Pad)
|
|
|
|
__all__.append('Pad')
|
|
|
|
|
2012-10-24 18:47:07 +00:00
|
|
|
class GhostPad(Gst.GhostPad):
|
|
|
|
def __init__(self, name, target=None, direction=None):
|
|
|
|
if direction is None:
|
|
|
|
if target is None:
|
|
|
|
raise TypeError('you must pass at least one of target'
|
2015-03-18 12:53:55 +00:00
|
|
|
'and direction')
|
2012-10-24 18:47:07 +00:00
|
|
|
direction = target.props.direction
|
|
|
|
|
|
|
|
Gst.GhostPad.__init__(self, name=name, direction=direction)
|
|
|
|
self.construct()
|
|
|
|
if target is not None:
|
|
|
|
self.set_target(target)
|
|
|
|
|
2012-11-04 16:00:14 +00:00
|
|
|
def query_caps(self, filter=None):
|
|
|
|
return Gst.GhostPad.query_caps(self, filter)
|
|
|
|
|
2012-10-24 18:47:07 +00:00
|
|
|
GhostPad = override(GhostPad)
|
|
|
|
__all__.append('GhostPad')
|
|
|
|
|
2012-10-15 07:10:25 +00:00
|
|
|
class IteratorError(Exception):
|
|
|
|
pass
|
|
|
|
__all__.append('IteratorError')
|
|
|
|
|
2012-10-15 07:12:33 +00:00
|
|
|
class AddError(Exception):
|
|
|
|
pass
|
|
|
|
__all__.append('AddError')
|
|
|
|
|
2012-10-15 07:13:44 +00:00
|
|
|
class LinkError(Exception):
|
|
|
|
pass
|
|
|
|
__all__.append('LinkError')
|
|
|
|
|
2012-10-15 07:10:25 +00:00
|
|
|
class Iterator(Gst.Iterator):
|
|
|
|
def __iter__(self):
|
|
|
|
while True:
|
|
|
|
result, value = self.next()
|
|
|
|
if result == Gst.IteratorResult.DONE:
|
|
|
|
break
|
|
|
|
|
|
|
|
if result != Gst.IteratorResult.OK:
|
|
|
|
raise IteratorError(result)
|
|
|
|
|
|
|
|
yield value
|
|
|
|
|
|
|
|
Iterator = override(Iterator)
|
|
|
|
__all__.append('Iterator')
|
|
|
|
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
class ElementFactory(Gst.ElementFactory):
|
|
|
|
|
|
|
|
# ElementFactory
|
|
|
|
def get_longname(self):
|
|
|
|
return self.get_metadata("long-name")
|
|
|
|
|
|
|
|
def get_description(self):
|
|
|
|
return self.get_metadata("description")
|
|
|
|
|
|
|
|
def get_klass(self):
|
|
|
|
return self.get_metadata("klass")
|
|
|
|
|
2012-10-15 07:15:21 +00:00
|
|
|
@classmethod
|
|
|
|
def make(cls, factory_name, instance_name=None):
|
|
|
|
return Gst.ElementFactory.make(factory_name, instance_name)
|
2012-10-15 07:12:33 +00:00
|
|
|
|
|
|
|
class Pipeline(Gst.Pipeline):
|
|
|
|
def __init__(self, name=None):
|
|
|
|
Gst.Pipeline.__init__(self, name=name)
|
|
|
|
|
|
|
|
Pipeline = override(Pipeline)
|
|
|
|
__all__.append('Pipeline')
|
|
|
|
|
2012-11-22 06:11:45 +00:00
|
|
|
class Structure(Gst.Structure):
|
|
|
|
def __getitem__(self, key):
|
|
|
|
return self.get_value(key)
|
2015-03-18 12:53:55 +00:00
|
|
|
|
2012-12-07 17:18:21 +00:00
|
|
|
def __setitem__(self, key, value):
|
|
|
|
return self.set_value(key, value)
|
|
|
|
|
2012-11-22 06:11:45 +00:00
|
|
|
Structure = override(Structure)
|
|
|
|
__all__.append('Structure')
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
ElementFactory = override(ElementFactory)
|
|
|
|
__all__.append('ElementFactory')
|
|
|
|
|
|
|
|
class Fraction(Gst.Fraction):
|
|
|
|
def __init__(self, num, denom=1):
|
|
|
|
def __gcd(a, b):
|
|
|
|
while b != 0:
|
|
|
|
tmp = a
|
|
|
|
a = b
|
|
|
|
b = tmp % b
|
|
|
|
return abs(a)
|
|
|
|
|
|
|
|
def __simplify():
|
|
|
|
num = self.num
|
|
|
|
denom = self.denom
|
|
|
|
|
|
|
|
if num < 0:
|
|
|
|
num = -num
|
|
|
|
denom = -denom
|
|
|
|
|
|
|
|
# Compute greatest common divisor
|
|
|
|
gcd = __gcd(num, denom)
|
|
|
|
if gcd != 0:
|
|
|
|
num /= gcd
|
|
|
|
denom /= gcd
|
|
|
|
|
|
|
|
self.num = num
|
|
|
|
self.denom = denom
|
|
|
|
|
|
|
|
self.num = num
|
|
|
|
self.denom = denom
|
|
|
|
|
|
|
|
__simplify()
|
|
|
|
self.type = "fraction"
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '<Gst.Fraction %d/%d>' % (self.num, self.denom)
|
|
|
|
|
|
|
|
def __value__(self):
|
|
|
|
return self.num / self.denom
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
if isinstance(other, Fraction):
|
|
|
|
return self.num * other.denom == other.num * self.denom
|
|
|
|
return False
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self.__eq__(other)
|
|
|
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
if isinstance(other, Fraction):
|
|
|
|
return Fraction(self.num * other.num,
|
|
|
|
self.denom * other.denom)
|
|
|
|
elif isinstance(other, int):
|
|
|
|
return Fraction(self.num * other, self.denom)
|
|
|
|
raise TypeError
|
|
|
|
|
|
|
|
__rmul__ = __mul__
|
|
|
|
|
2014-03-23 09:34:10 +00:00
|
|
|
def __truediv__(self, other):
|
2012-08-08 17:59:09 +00:00
|
|
|
if isinstance(other, Fraction):
|
|
|
|
return Fraction(self.num * other.denom,
|
|
|
|
self.denom * other.num)
|
|
|
|
elif isinstance(other, int):
|
|
|
|
return Fraction(self.num, self.denom * other)
|
|
|
|
return TypeError
|
|
|
|
|
2014-03-23 09:34:10 +00:00
|
|
|
__div__ = __truediv__
|
|
|
|
|
|
|
|
def __rtruediv__(self, other):
|
2012-08-08 17:59:09 +00:00
|
|
|
if isinstance(other, int):
|
|
|
|
return Fraction(self.denom * other, self.num)
|
|
|
|
return TypeError
|
|
|
|
|
2014-03-23 09:34:10 +00:00
|
|
|
__rdiv__ = __rtruediv__
|
|
|
|
|
2012-08-08 17:59:09 +00:00
|
|
|
def __float__(self):
|
|
|
|
return float(self.num) / float(self.denom)
|
|
|
|
|
|
|
|
Fraction = override(Fraction)
|
|
|
|
__all__.append('Fraction')
|
|
|
|
|
2013-12-03 22:49:11 +00:00
|
|
|
def TIME_ARGS(time):
|
|
|
|
if time == Gst.CLOCK_TIME_NONE:
|
|
|
|
return "CLOCK_TIME_NONE"
|
|
|
|
|
|
|
|
return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60),
|
|
|
|
(time / (Gst.SECOND * 60)) % 60,
|
|
|
|
(time / Gst.SECOND) % 60,
|
|
|
|
time % Gst.SECOND)
|
|
|
|
__all__.append('TIME_ARGS')
|
|
|
|
|
2014-04-01 07:53:21 +00:00
|
|
|
from . import _gi_gst
|
2012-08-20 02:40:06 +00:00
|
|
|
_gi_gst
|
2012-08-08 17:59:09 +00:00
|
|
|
|
2012-09-27 12:41:29 +00:00
|
|
|
# maybe more python and less C some day if core turns a bit more introspection
|
|
|
|
# and binding friendly in the debug area
|
|
|
|
Gst.log = _gi_gst.log
|
|
|
|
Gst.debug = _gi_gst.debug
|
|
|
|
Gst.info = _gi_gst.info
|
|
|
|
Gst.warning = _gi_gst.warning
|
|
|
|
Gst.error = _gi_gst.error
|
|
|
|
Gst.fixme = _gi_gst.fixme
|
|
|
|
Gst.memdump = _gi_gst.memdump
|
2015-04-15 17:55:16 +00:00
|
|
|
|
|
|
|
# Make sure PyGst is not usable if GStreamer has not been initialized
|
|
|
|
class NotInitalized(Exception):
|
|
|
|
pass
|
|
|
|
__all__.append('NotInitalized')
|
|
|
|
|
|
|
|
def fake_method(*args):
|
|
|
|
raise NotInitalized("Please call Gst.init(argv) before using GStreamer")
|
|
|
|
|
|
|
|
|
|
|
|
real_functions = [o for o in getmembers(Gst) if isinstance(o[1], type(Gst.init))]
|
|
|
|
|
|
|
|
class_methods = []
|
|
|
|
for cname_klass in [o for o in getmembers(Gst) if isinstance(o[1], type(Gst.Element)) or isinstance(o[1], type(Gst.Caps))]:
|
|
|
|
class_methods.append((cname_klass,
|
|
|
|
[(o, cname_klass[1].__dict__[o])
|
|
|
|
for o in cname_klass[1].__dict__
|
|
|
|
if isinstance(cname_klass[1].__dict__[o], type(Gst.init))]))
|
|
|
|
|
|
|
|
def init_pygst():
|
|
|
|
for fname, function in real_functions:
|
|
|
|
if fname not in ["init", "init_check", "deinit"]:
|
|
|
|
setattr(Gst, fname, function)
|
|
|
|
|
|
|
|
for cname_class, methods in class_methods:
|
|
|
|
for mname, method in methods:
|
|
|
|
setattr(cname_class[1], mname, method)
|
|
|
|
|
|
|
|
|
|
|
|
def deinit_pygst():
|
|
|
|
for fname, func in real_functions:
|
|
|
|
if fname not in ["init", "init_check", "deinit"]:
|
|
|
|
setattr(Gst, fname, fake_method)
|
|
|
|
for cname_class, methods in class_methods:
|
|
|
|
for mname, method in methods:
|
|
|
|
setattr(cname_class[1], mname, fake_method)
|
|
|
|
|
|
|
|
real_init = Gst.init
|
|
|
|
def init(argv):
|
|
|
|
init_pygst()
|
|
|
|
return real_init(argv)
|
|
|
|
Gst.init = init
|
|
|
|
|
|
|
|
real_init_check = Gst.init_check
|
|
|
|
def init_check(argv):
|
|
|
|
init_pygst()
|
|
|
|
return real_init_check(argv)
|
|
|
|
Gst.init_check = init_check
|
|
|
|
|
|
|
|
real_deinit = Gst.deinit
|
|
|
|
def deinit():
|
|
|
|
deinit_pygst()
|
|
|
|
return real_deinit()
|
|
|
|
|
|
|
|
Gst.deinit = deinit
|
|
|
|
|
|
|
|
deinit_pygst()
|