gstreamer-python 1.27.90__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gstreamer_python/Lib/girepository-1.0/GdkPixbuf-2.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/HarfBuzz-0.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Json-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Pango-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/PangoCairo-1.0.typelib +0 -0
- gstreamer_python/Lib/girepository-1.0/Soup-3.0.typelib +0 -0
- gstreamer_python/Lib/gstreamer-1.0/gstpython.dll +0 -0
- gstreamer_python/Lib/site-packages/PyGObject-3.50.2.dist-info/METADATA +21 -0
- gstreamer_python/Lib/site-packages/cairo/__init__.py +25 -0
- gstreamer_python/Lib/site-packages/cairo/__init__.pyi +5889 -0
- gstreamer_python/Lib/site-packages/cairo/_cairo.cp313-win_amd64.pyd +0 -0
- gstreamer_python/Lib/site-packages/cairo/include/py3cairo.h +266 -0
- gstreamer_python/Lib/site-packages/cairo/py.typed +0 -0
- gstreamer_python/Lib/site-packages/gi/__init__.py +197 -0
- gstreamer_python/Lib/site-packages/gi/_constants.py +47 -0
- gstreamer_python/Lib/site-packages/gi/_error.py +55 -0
- gstreamer_python/Lib/site-packages/gi/_gi.cp313-win_amd64.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/_gi_cairo.cp313-win_amd64.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/_gtktemplate.py +307 -0
- gstreamer_python/Lib/site-packages/gi/_option.py +379 -0
- gstreamer_python/Lib/site-packages/gi/_ossighelper.py +275 -0
- gstreamer_python/Lib/site-packages/gi/_propertyhelper.py +402 -0
- gstreamer_python/Lib/site-packages/gi/_signalhelper.py +249 -0
- gstreamer_python/Lib/site-packages/gi/docstring.py +205 -0
- gstreamer_python/Lib/site-packages/gi/events.py +674 -0
- gstreamer_python/Lib/site-packages/gi/importer.py +153 -0
- gstreamer_python/Lib/site-packages/gi/module.py +269 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GES.py +94 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GIMarshallingTests.py +72 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GLib.py +882 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GObject.py +692 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gdk.py +444 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GdkPixbuf.py +53 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gio.py +655 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gst.py +1273 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstAnalytics.py +106 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstApp.py +50 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstAudio.py +18 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstPbutils.py +99 -0
- gstreamer_python/Lib/site-packages/gi/overrides/GstVideo.py +17 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Gtk.py +1707 -0
- gstreamer_python/Lib/site-packages/gi/overrides/Pango.py +58 -0
- gstreamer_python/Lib/site-packages/gi/overrides/__init__.py +357 -0
- gstreamer_python/Lib/site-packages/gi/overrides/_gi_gst.cp313-win_amd64.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/overrides/_gi_gst_analytics.cp313-win_amd64.pyd +0 -0
- gstreamer_python/Lib/site-packages/gi/overrides/keysyms.py +53 -0
- gstreamer_python/Lib/site-packages/gi/pygtkcompat.py +26 -0
- gstreamer_python/Lib/site-packages/gi/repository/__init__.py +28 -0
- gstreamer_python/Lib/site-packages/gi/types.py +350 -0
- gstreamer_python/Lib/site-packages/pycairo-1.27.0.dist-info/METADATA +9 -0
- gstreamer_python/__init__.py +32 -0
- gstreamer_python-1.27.90.dist-info/METADATA +26 -0
- gstreamer_python-1.27.90.dist-info/RECORD +55 -0
- gstreamer_python-1.27.90.dist-info/WHEEL +5 -0
- gstreamer_python-1.27.90.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1273 @@
|
|
|
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
|
+
from __future__ import annotations
|
|
26
|
+
from typing_extensions import Self
|
|
27
|
+
|
|
28
|
+
import sys
|
|
29
|
+
import inspect
|
|
30
|
+
import itertools
|
|
31
|
+
import weakref
|
|
32
|
+
import typing
|
|
33
|
+
import gi
|
|
34
|
+
|
|
35
|
+
gi.require_version('GLib', '2.0')
|
|
36
|
+
gi.require_version('GObject', '2.0')
|
|
37
|
+
from gi.repository import GLib, GObject
|
|
38
|
+
from gi.overrides import override
|
|
39
|
+
|
|
40
|
+
# Typing relies on https://github.com/pygobject/pygobject-stubs.
|
|
41
|
+
if typing.TYPE_CHECKING:
|
|
42
|
+
# Import stubs for type checking this file.
|
|
43
|
+
#
|
|
44
|
+
# This causes some weirdness because stubs contains overridden APIs
|
|
45
|
+
# signatures. For example when using Gst.Bin.add() here, we mean to call the
|
|
46
|
+
# g-i generated API which does not have the same signature as our override
|
|
47
|
+
# Bin.add(). The type checker will use signature from stubs which is our
|
|
48
|
+
# override signature.
|
|
49
|
+
from gi.repository import Gst
|
|
50
|
+
|
|
51
|
+
# Type annotations cannot have `Gst.` prefix because they are copied into
|
|
52
|
+
# Gst stubs module which cannot refer to itself. Use type aliases.
|
|
53
|
+
MiniObject = Gst.MiniObject
|
|
54
|
+
MiniObjectFlags = Gst.MiniObjectFlags
|
|
55
|
+
FlowReturn = Gst.FlowReturn
|
|
56
|
+
PadDirection = Gst.PadDirection
|
|
57
|
+
PadLinkReturn = Gst.PadLinkReturn
|
|
58
|
+
MapFlags = Gst.MapFlags
|
|
59
|
+
BufferFlags = Gst.BufferFlags
|
|
60
|
+
else:
|
|
61
|
+
from gi.module import get_introspection_module
|
|
62
|
+
Gst = get_introspection_module('Gst')
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
__all__ = []
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if Gst.VERSION_MAJOR < 1:
|
|
69
|
+
import warnings
|
|
70
|
+
warn_msg = "You have imported the Gst 0.10 module. Because Gst 0.10 \
|
|
71
|
+
was not designed for use with introspection some of the \
|
|
72
|
+
interfaces and API will fail. As such this is not supported \
|
|
73
|
+
by the GStreamer development team and we encourage you to \
|
|
74
|
+
port your app to Gst 1 or greater. gst-python is the recommended \
|
|
75
|
+
python module to use with Gst 0.10"
|
|
76
|
+
|
|
77
|
+
warnings.warn(warn_msg, RuntimeWarning)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Float(float):
|
|
81
|
+
'''
|
|
82
|
+
A wrapper to force conversion to G_TYPE_FLOAT instead of G_TYPE_DOUBLE when
|
|
83
|
+
used in e.g. Gst.ValueArray.
|
|
84
|
+
'''
|
|
85
|
+
__gtype__ = GObject.TYPE_FLOAT
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
__all__.append('Float')
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# Ensuring that PyGObject loads the URIHandler interface
|
|
92
|
+
# so we can force our own implementation soon enough (in gstmodule.c)
|
|
93
|
+
class URIHandler(Gst.URIHandler):
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
override(URIHandler)
|
|
98
|
+
__all__.append('URIHandler')
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class Element(Gst.Element):
|
|
102
|
+
@staticmethod
|
|
103
|
+
def link_many(*args: Element) -> None: # type: ignore[override]
|
|
104
|
+
'''
|
|
105
|
+
:raises Gst.LinkError
|
|
106
|
+
'''
|
|
107
|
+
for pair in pairwise(args):
|
|
108
|
+
if not pair[0].link(pair[1]):
|
|
109
|
+
raise LinkError(f'Failed to link {pair[0]} and {pair[1]}')
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
override(Element)
|
|
113
|
+
__all__.append('Element')
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class Bin(Gst.Bin):
|
|
117
|
+
def __init__(self, name: typing.Optional[str] = None):
|
|
118
|
+
Gst.Bin.__init__(self, name=name)
|
|
119
|
+
|
|
120
|
+
def add(self, *args: Element) -> None: # type: ignore[override]
|
|
121
|
+
for arg in args:
|
|
122
|
+
if not Gst.Bin.add(self, arg): # type: ignore[func-returns-value]
|
|
123
|
+
raise AddError(arg)
|
|
124
|
+
|
|
125
|
+
def make_and_add(self, factoryname: str, name: typing.Optional[str] = None) -> Element:
|
|
126
|
+
'''
|
|
127
|
+
:raises Gst.AddError:
|
|
128
|
+
:raises Gst.MissingPluginError:
|
|
129
|
+
'''
|
|
130
|
+
elem = ElementFactory.make(factoryname, name)
|
|
131
|
+
self.add(elem)
|
|
132
|
+
return elem
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
override(Bin)
|
|
136
|
+
__all__.append('Bin')
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class NotWritableMiniObject(Exception):
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
__all__.append('NotWritableMiniObject')
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class MiniObjectMixin:
|
|
147
|
+
def make_writable(self) -> bool:
|
|
148
|
+
return _gi_gst.mini_object_make_writable(self)
|
|
149
|
+
|
|
150
|
+
def is_writable(self) -> bool:
|
|
151
|
+
return _gi_gst.mini_object_is_writable(self)
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def flags(self) -> MiniObjectFlags:
|
|
155
|
+
return _gi_gst.mini_object_flags(self)
|
|
156
|
+
|
|
157
|
+
@flags.setter
|
|
158
|
+
def flags(self, flags: MiniObjectFlags) -> None:
|
|
159
|
+
_gi_gst.mini_object_set_flags(self, flags)
|
|
160
|
+
|
|
161
|
+
def __ptr__(self):
|
|
162
|
+
return _gi_gst._get_object_ptr(self)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
__all__.append('MiniObjectMixin')
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class NotWritableQuery(Exception):
|
|
169
|
+
pass
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
__all__.append('NotWritableQuery')
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class Query(MiniObjectMixin, Gst.Query): # type: ignore[misc]
|
|
176
|
+
def get_structure(self) -> typing.Optional[Structure]:
|
|
177
|
+
s = _gi_gst.query_get_structure(self)
|
|
178
|
+
return s._set_parent(self) if s is not None else None
|
|
179
|
+
|
|
180
|
+
def writable_structure(self) -> StructureContextManager: # type: ignore[override]
|
|
181
|
+
return StructureContextManager(_gi_gst.query_writable_structure(self), self) # type: ignore[arg-type]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
override(Query)
|
|
185
|
+
__all__.append('Query')
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class NotWritableEvent(Exception):
|
|
189
|
+
pass
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
__all__.append('NotWritableEvent')
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class Event(MiniObjectMixin, Gst.Event): # type: ignore[misc]
|
|
196
|
+
def get_structure(self) -> typing.Optional[Structure]:
|
|
197
|
+
s = _gi_gst.event_get_structure(self)
|
|
198
|
+
return s._set_parent(self) if s is not None else None
|
|
199
|
+
|
|
200
|
+
def writable_structure(self) -> StructureContextManager: # type: ignore[override]
|
|
201
|
+
return StructureContextManager(_gi_gst.event_writable_structure(self), self) # type: ignore[arg-type]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
override(Event)
|
|
205
|
+
__all__.append('Event')
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class NotWritableContext(Exception):
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
__all__.append('NotWritableContext')
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class Context(MiniObjectMixin, Gst.Context): # type: ignore[misc]
|
|
216
|
+
def get_structure(self) -> Structure:
|
|
217
|
+
s = _gi_gst.context_get_structure(self)
|
|
218
|
+
return s._set_parent(self)
|
|
219
|
+
|
|
220
|
+
def writable_structure(self) -> StructureContextManager: # type: ignore[override]
|
|
221
|
+
return StructureContextManager(_gi_gst.context_writable_structure(self), self) # type: ignore[arg-type]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
override(Context)
|
|
225
|
+
__all__.append('Context')
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class NotWritableCaps(Exception):
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
__all__.append('NotWritableCaps')
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class NotWritableStructure(Exception):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
__all__.append('NotWritableStructure')
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class Caps(MiniObjectMixin, Gst.Caps): # type: ignore[misc]
|
|
243
|
+
|
|
244
|
+
def __nonzero__(self):
|
|
245
|
+
return not self.is_empty()
|
|
246
|
+
|
|
247
|
+
def __new__(cls, *args):
|
|
248
|
+
if not args:
|
|
249
|
+
return Caps.new_empty()
|
|
250
|
+
if len(args) > 1:
|
|
251
|
+
raise TypeError("wrong arguments when creating GstCaps object")
|
|
252
|
+
|
|
253
|
+
assert len(args) == 1
|
|
254
|
+
if isinstance(args[0], str):
|
|
255
|
+
return Caps.from_string(args[0])
|
|
256
|
+
elif isinstance(args[0], Caps):
|
|
257
|
+
return args[0].copy()
|
|
258
|
+
elif isinstance(args[0], Structure):
|
|
259
|
+
res = Caps.new_empty()
|
|
260
|
+
res.append_structure(args[0])
|
|
261
|
+
return res
|
|
262
|
+
elif isinstance(args[0], (list, tuple)):
|
|
263
|
+
res = Caps.new_empty()
|
|
264
|
+
for e in args[0]:
|
|
265
|
+
res.append_structure(e)
|
|
266
|
+
return res
|
|
267
|
+
|
|
268
|
+
raise TypeError("wrong arguments when creating GstCaps object")
|
|
269
|
+
|
|
270
|
+
def __init__(self, *args, **kwargs):
|
|
271
|
+
return super(Caps, self).__init__()
|
|
272
|
+
|
|
273
|
+
def __str__(self) -> str:
|
|
274
|
+
return self.to_string()
|
|
275
|
+
|
|
276
|
+
def __getitem__(self, index: int) -> Structure:
|
|
277
|
+
return self.get_structure(index)
|
|
278
|
+
|
|
279
|
+
def __iter__(self) -> typing.Iterator[Structure]:
|
|
280
|
+
for i in range(self.get_size()):
|
|
281
|
+
yield self.get_structure(i)
|
|
282
|
+
|
|
283
|
+
def __len__(self) -> int:
|
|
284
|
+
return self.get_size()
|
|
285
|
+
|
|
286
|
+
def get_structure(self, index: int) -> Structure:
|
|
287
|
+
if index >= self.get_size():
|
|
288
|
+
raise IndexError('structure index out of range')
|
|
289
|
+
s = _gi_gst.caps_get_structure(self, index)
|
|
290
|
+
return s._set_parent(self)
|
|
291
|
+
|
|
292
|
+
def writable_structure(self, index: int) -> StructureContextManager: # type: ignore[override]
|
|
293
|
+
return StructureContextManager(_gi_gst.caps_writable_structure(self, index), self) # type: ignore[arg-type]
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
override(Caps)
|
|
297
|
+
__all__.append('Caps')
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class PadProbeInfoObjectContextManager:
|
|
301
|
+
def __init__(self, object: MiniObject, info: PadProbeInfo):
|
|
302
|
+
self.__object = object
|
|
303
|
+
self.__info = info
|
|
304
|
+
|
|
305
|
+
def __enter__(self) -> MiniObject:
|
|
306
|
+
return self.__object
|
|
307
|
+
|
|
308
|
+
def __exit__(self, _type, _value, _tb):
|
|
309
|
+
self.__info.set_object(self.__object)
|
|
310
|
+
self.__object = None
|
|
311
|
+
self.__info = None
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
__all__.append('PadProbeInfoObjectContextManager')
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class PadProbeInfo(Gst.PadProbeInfo): # type: ignore[misc]
|
|
318
|
+
def writable_object(self) -> PadProbeInfoObjectContextManager: # type: ignore[override]
|
|
319
|
+
'''Return writable object contained in this PadProbeInfo.
|
|
320
|
+
It uses a context manager to steal the object from the PadProbeInfo,
|
|
321
|
+
and set it back when exiting the context.
|
|
322
|
+
'''
|
|
323
|
+
return PadProbeInfoObjectContextManager(_gi_gst.pad_probe_info_writable_object(self), self)
|
|
324
|
+
|
|
325
|
+
def set_object(self, obj: typing.Optional[MiniObject]) -> None:
|
|
326
|
+
_gi_gst.pad_probe_info_set_object(self, obj)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
setattr(sys.modules["gi.repository.Gst"], 'PadProbeInfo', PadProbeInfo)
|
|
330
|
+
__all__.append('PadProbeInfo')
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class PadFunc:
|
|
334
|
+
def __init__(self, func: typing.Callable[..., FlowReturn]):
|
|
335
|
+
self.func = func
|
|
336
|
+
|
|
337
|
+
def __call__(self, pad, parent, obj):
|
|
338
|
+
if isinstance(self.func, weakref.WeakMethod):
|
|
339
|
+
func = self.func()
|
|
340
|
+
else:
|
|
341
|
+
func = self.func
|
|
342
|
+
|
|
343
|
+
try:
|
|
344
|
+
res = func(pad, obj)
|
|
345
|
+
except TypeError:
|
|
346
|
+
try:
|
|
347
|
+
res = func(pad, parent, obj)
|
|
348
|
+
except TypeError:
|
|
349
|
+
raise TypeError(f"Invalid method {func}, 2 or 3 arguments required")
|
|
350
|
+
|
|
351
|
+
return res
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class Pad(Gst.Pad):
|
|
355
|
+
def __init__(self, *args, **kwargs):
|
|
356
|
+
super(Gst.Pad, self).__init__(*args, **kwargs)
|
|
357
|
+
|
|
358
|
+
def set_chain_function(self, func: typing.Callable[..., FlowReturn]) -> None:
|
|
359
|
+
self.set_chain_function_full(PadFunc(func), None)
|
|
360
|
+
|
|
361
|
+
def set_event_function(self, func: typing.Callable[..., FlowReturn]) -> None:
|
|
362
|
+
self.set_event_function_full(PadFunc(func), None)
|
|
363
|
+
|
|
364
|
+
def set_query_function(self, func: typing.Callable[..., FlowReturn]) -> None:
|
|
365
|
+
self.set_query_function_full(PadFunc(func), None)
|
|
366
|
+
|
|
367
|
+
def query_caps(self, filter=None):
|
|
368
|
+
return Gst.Pad.query_caps(self, filter)
|
|
369
|
+
|
|
370
|
+
def set_caps(self, caps: Caps) -> bool: # type: ignore[override]
|
|
371
|
+
if not isinstance(caps, Gst.Caps):
|
|
372
|
+
raise TypeError(f"{type(caps)} is not a Gst.Caps.")
|
|
373
|
+
|
|
374
|
+
if not caps.is_fixed():
|
|
375
|
+
return False
|
|
376
|
+
|
|
377
|
+
event = Gst.Event.new_caps(caps)
|
|
378
|
+
|
|
379
|
+
if self.direction == Gst.PadDirection.SRC:
|
|
380
|
+
res = self.push_event(event)
|
|
381
|
+
else:
|
|
382
|
+
res = self.send_event(event)
|
|
383
|
+
|
|
384
|
+
return res
|
|
385
|
+
|
|
386
|
+
def link(self, pad: Pad) -> PadLinkReturn:
|
|
387
|
+
ret = Gst.Pad.link(self, pad)
|
|
388
|
+
if ret != Gst.PadLinkReturn.OK:
|
|
389
|
+
raise LinkError(ret)
|
|
390
|
+
return ret
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
override(Pad)
|
|
394
|
+
__all__.append('Pad')
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class GhostPad(Gst.GhostPad):
|
|
398
|
+
def __init__(self, name: str, target: typing.Optional[Pad] = None, direction: typing.Optional[PadDirection] = None):
|
|
399
|
+
if direction is None:
|
|
400
|
+
if target is None:
|
|
401
|
+
raise TypeError('you must pass at least one of target '
|
|
402
|
+
'and direction')
|
|
403
|
+
direction = target.props.direction
|
|
404
|
+
|
|
405
|
+
Gst.GhostPad.__init__(self, name=name, direction=direction)
|
|
406
|
+
self.construct()
|
|
407
|
+
if target is not None:
|
|
408
|
+
self.set_target(target)
|
|
409
|
+
|
|
410
|
+
def query_caps(self, filter: typing.Optional[Caps] = None) -> Caps:
|
|
411
|
+
return Gst.GhostPad.query_caps(self, filter)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
override(GhostPad)
|
|
415
|
+
__all__.append('GhostPad')
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
class IteratorError(Exception):
|
|
419
|
+
pass
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
__all__.append('IteratorError')
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class MissingPluginError(Exception):
|
|
426
|
+
pass
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
__all__.append('MissingPluginError')
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class AddError(Exception):
|
|
433
|
+
pass
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
__all__.append('AddError')
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
class LinkError(Exception):
|
|
440
|
+
pass
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
__all__.append('LinkError')
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
class MapError(Exception):
|
|
447
|
+
pass
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
__all__.append('MapError')
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
class Iterator(Gst.Iterator):
|
|
454
|
+
def __iter__(self) -> typing.Iterator[typing.Any]:
|
|
455
|
+
while True:
|
|
456
|
+
result, value = self.next()
|
|
457
|
+
if result == Gst.IteratorResult.DONE:
|
|
458
|
+
break
|
|
459
|
+
|
|
460
|
+
if result != Gst.IteratorResult.OK:
|
|
461
|
+
raise IteratorError(result)
|
|
462
|
+
|
|
463
|
+
yield value
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
override(Iterator)
|
|
467
|
+
__all__.append('Iterator')
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class ElementFactory(Gst.ElementFactory):
|
|
471
|
+
|
|
472
|
+
# ElementFactory
|
|
473
|
+
def get_longname(self) -> typing.Optional[str]:
|
|
474
|
+
return self.get_metadata("long-name")
|
|
475
|
+
|
|
476
|
+
def get_description(self) -> typing.Optional[str]:
|
|
477
|
+
return self.get_metadata("description")
|
|
478
|
+
|
|
479
|
+
def get_klass(self) -> typing.Optional[str]:
|
|
480
|
+
return self.get_metadata("klass")
|
|
481
|
+
|
|
482
|
+
@staticmethod
|
|
483
|
+
def make(factoryname: str, name: typing.Optional[str] = None) -> Element: # type: ignore[override]
|
|
484
|
+
'''
|
|
485
|
+
:raises Gst.PluginMissingError:
|
|
486
|
+
'''
|
|
487
|
+
elem = Gst.ElementFactory.make(factoryname, name)
|
|
488
|
+
if not elem:
|
|
489
|
+
raise MissingPluginError(f'No such element: {factoryname}')
|
|
490
|
+
return elem # type: ignore[return-value]
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class Pipeline(Gst.Pipeline):
|
|
494
|
+
def __init__(self, name: typing.Optional[str] = None):
|
|
495
|
+
Gst.Pipeline.__init__(self, name=name)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
override(Pipeline)
|
|
499
|
+
__all__.append('Pipeline')
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
class StructureContextManager:
|
|
503
|
+
"""A Gst.Structure wrapper to force usage of a context manager.
|
|
504
|
+
"""
|
|
505
|
+
def __init__(self, structure: Structure, parent: MiniObject):
|
|
506
|
+
self.__structure = structure
|
|
507
|
+
self.__parent = parent
|
|
508
|
+
|
|
509
|
+
def __enter__(self) -> Structure:
|
|
510
|
+
return self.__structure
|
|
511
|
+
|
|
512
|
+
def __exit__(self, _type, _value, _tb):
|
|
513
|
+
self.__structure = None
|
|
514
|
+
self.__parent = None
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
__all__.append('StructureContextManager')
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
class Structure(Gst.Structure):
|
|
521
|
+
def __new__(cls, *args, **kwargs):
|
|
522
|
+
if not args:
|
|
523
|
+
if kwargs:
|
|
524
|
+
raise TypeError("wrong arguments when creating GstStructure, first argument"
|
|
525
|
+
" must be the structure name.")
|
|
526
|
+
struct = Structure.new_empty()
|
|
527
|
+
return struct
|
|
528
|
+
elif len(args) > 1:
|
|
529
|
+
raise TypeError("wrong arguments when creating GstStructure object")
|
|
530
|
+
elif isinstance(args[0], str):
|
|
531
|
+
if not kwargs:
|
|
532
|
+
struct = Structure.from_string(args[0])[0]
|
|
533
|
+
return struct
|
|
534
|
+
struct = Structure.new_empty(args[0])
|
|
535
|
+
for k, v in kwargs.items():
|
|
536
|
+
struct[k] = v
|
|
537
|
+
|
|
538
|
+
return struct
|
|
539
|
+
elif isinstance(args[0], Structure):
|
|
540
|
+
struct = args[0].copy()
|
|
541
|
+
return struct
|
|
542
|
+
|
|
543
|
+
raise TypeError("wrong arguments when creating GstStructure object")
|
|
544
|
+
|
|
545
|
+
def __init__(self, *args, **kwargs):
|
|
546
|
+
pass
|
|
547
|
+
|
|
548
|
+
def __ptr__(self):
|
|
549
|
+
return _gi_gst._get_object_ptr(self)
|
|
550
|
+
|
|
551
|
+
def __getitem__(self, key: str) -> typing.Any:
|
|
552
|
+
val = self.get_value(key)
|
|
553
|
+
if val is None:
|
|
554
|
+
raise KeyError(f"key {key} not found")
|
|
555
|
+
return val
|
|
556
|
+
|
|
557
|
+
def __setitem__(self, key: str, value: typing.Any) -> None:
|
|
558
|
+
self.set_value(key, value)
|
|
559
|
+
|
|
560
|
+
def __len__(self) -> int:
|
|
561
|
+
return self.n_fields()
|
|
562
|
+
|
|
563
|
+
def __iter__(self) -> typing.Iterator[str]:
|
|
564
|
+
return self.keys()
|
|
565
|
+
|
|
566
|
+
def items(self) -> typing.Iterator[typing.Tuple[str, typing.Any]]:
|
|
567
|
+
pairs: typing.List[typing.Tuple[str, typing.Any]] = []
|
|
568
|
+
|
|
569
|
+
def foreach(fid, value):
|
|
570
|
+
pairs.append((GLib.quark_to_string(fid), value))
|
|
571
|
+
return True
|
|
572
|
+
|
|
573
|
+
self.foreach(foreach)
|
|
574
|
+
return iter(pairs)
|
|
575
|
+
|
|
576
|
+
def keys(self) -> typing.Iterator[str]:
|
|
577
|
+
keys: list[str] = []
|
|
578
|
+
|
|
579
|
+
def foreach(fid, value):
|
|
580
|
+
keys.append(GLib.quark_to_string(fid))
|
|
581
|
+
return True
|
|
582
|
+
|
|
583
|
+
self.foreach(foreach)
|
|
584
|
+
return iter(keys)
|
|
585
|
+
|
|
586
|
+
def set_value(self, key: str, value: typing.Any) -> bool:
|
|
587
|
+
if not _gi_gst.structure_is_writable(self):
|
|
588
|
+
raise NotWritableStructure("Trying to write to a not writable structure."
|
|
589
|
+
" Make sure to use the right APIs to have access to structure"
|
|
590
|
+
" in a writable way.")
|
|
591
|
+
|
|
592
|
+
return Gst.Structure.set_value(self, key, value)
|
|
593
|
+
|
|
594
|
+
def __str__(self) -> str:
|
|
595
|
+
return self.to_string()
|
|
596
|
+
|
|
597
|
+
def _set_parent(self, parent):
|
|
598
|
+
self.__parent__ = parent
|
|
599
|
+
return self
|
|
600
|
+
|
|
601
|
+
def __enter__(self) -> Self:
|
|
602
|
+
return self
|
|
603
|
+
|
|
604
|
+
def __exit__(self, _type, _value, _tb):
|
|
605
|
+
self._set_parent(None)
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
override(Structure)
|
|
609
|
+
__all__.append('Structure')
|
|
610
|
+
|
|
611
|
+
override(ElementFactory)
|
|
612
|
+
__all__.append('ElementFactory')
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
class Fraction(Gst.Fraction):
|
|
616
|
+
num: int
|
|
617
|
+
denom: int
|
|
618
|
+
|
|
619
|
+
def __init__(self, num: int, denom: int = 1):
|
|
620
|
+
def __gcd(a, b):
|
|
621
|
+
while b != 0:
|
|
622
|
+
tmp = a
|
|
623
|
+
a = b
|
|
624
|
+
b = tmp % b
|
|
625
|
+
return abs(a)
|
|
626
|
+
|
|
627
|
+
def __simplify():
|
|
628
|
+
num = self.num
|
|
629
|
+
denom = self.denom
|
|
630
|
+
|
|
631
|
+
if num < 0:
|
|
632
|
+
num = -num
|
|
633
|
+
denom = -denom
|
|
634
|
+
|
|
635
|
+
# Compute greatest common divisor
|
|
636
|
+
gcd = __gcd(num, denom)
|
|
637
|
+
if gcd != 0:
|
|
638
|
+
num //= gcd
|
|
639
|
+
denom //= gcd
|
|
640
|
+
|
|
641
|
+
self.num = num
|
|
642
|
+
self.denom = denom
|
|
643
|
+
|
|
644
|
+
self.num = num
|
|
645
|
+
self.denom = denom
|
|
646
|
+
|
|
647
|
+
__simplify()
|
|
648
|
+
self.type = "fraction"
|
|
649
|
+
|
|
650
|
+
def __repr__(self) -> str:
|
|
651
|
+
return f'<Gst.Fraction {self}>'
|
|
652
|
+
|
|
653
|
+
def __value__(self):
|
|
654
|
+
return self.num / self.denom
|
|
655
|
+
|
|
656
|
+
def __eq__(self, other: object) -> bool:
|
|
657
|
+
if isinstance(other, Fraction):
|
|
658
|
+
return self.num * other.denom == other.num * self.denom
|
|
659
|
+
return False
|
|
660
|
+
|
|
661
|
+
def __ne__(self, other: object) -> bool:
|
|
662
|
+
return not self.__eq__(other)
|
|
663
|
+
|
|
664
|
+
def __mul__(self, other: object) -> Fraction:
|
|
665
|
+
if isinstance(other, Fraction):
|
|
666
|
+
return Fraction(self.num * other.num,
|
|
667
|
+
self.denom * other.denom)
|
|
668
|
+
elif isinstance(other, int):
|
|
669
|
+
return Fraction(self.num * other, self.denom)
|
|
670
|
+
raise TypeError(f"{type(other)} is not supported, use Gst.Fraction or int.")
|
|
671
|
+
|
|
672
|
+
__rmul__ = __mul__
|
|
673
|
+
|
|
674
|
+
def __truediv__(self, other: object) -> Fraction:
|
|
675
|
+
if isinstance(other, Fraction):
|
|
676
|
+
return Fraction(self.num * other.denom,
|
|
677
|
+
self.denom * other.num)
|
|
678
|
+
elif isinstance(other, int):
|
|
679
|
+
return Fraction(self.num, self.denom * other)
|
|
680
|
+
raise TypeError(f"{type(other)} is not supported, use Gst.Fraction or int.")
|
|
681
|
+
|
|
682
|
+
__div__ = __truediv__
|
|
683
|
+
|
|
684
|
+
def __rtruediv__(self, other: object) -> Fraction:
|
|
685
|
+
if isinstance(other, int):
|
|
686
|
+
return Fraction(self.denom * other, self.num)
|
|
687
|
+
raise TypeError(f"{type(other)} is not an int.")
|
|
688
|
+
|
|
689
|
+
__rdiv__ = __rtruediv__
|
|
690
|
+
|
|
691
|
+
def __float__(self) -> float:
|
|
692
|
+
return float(self.num) / float(self.denom)
|
|
693
|
+
|
|
694
|
+
def __str__(self) -> str:
|
|
695
|
+
return f'{self.num}/{self.denom}'
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
override(Fraction)
|
|
699
|
+
__all__.append('Fraction')
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
class IntRange(Gst.IntRange):
|
|
703
|
+
def __init__(self, r: range):
|
|
704
|
+
if not isinstance(r, range):
|
|
705
|
+
raise TypeError(f"{type(r)} is not a range.")
|
|
706
|
+
|
|
707
|
+
if (r.start >= r.stop):
|
|
708
|
+
raise TypeError("Range start must be smaller then stop")
|
|
709
|
+
|
|
710
|
+
if r.start % r.step != 0:
|
|
711
|
+
raise TypeError("Range start must be a multiple of the step")
|
|
712
|
+
|
|
713
|
+
if r.stop % r.step != 0:
|
|
714
|
+
raise TypeError("Range stop must be a multiple of the step")
|
|
715
|
+
|
|
716
|
+
self.range = r
|
|
717
|
+
|
|
718
|
+
def __repr__(self) -> str:
|
|
719
|
+
return f'<Gst.IntRange [{self.range.start},{self.range.stop},{self.range.step}]>'
|
|
720
|
+
|
|
721
|
+
def __str__(self) -> str:
|
|
722
|
+
if self.range.step == 1:
|
|
723
|
+
return f'[{self.range.start},{self.range.stop}]'
|
|
724
|
+
else:
|
|
725
|
+
return f'[{self.range.start},{self.range.stop},{self.range.step}]'
|
|
726
|
+
|
|
727
|
+
def __eq__(self, other: object) -> bool:
|
|
728
|
+
if isinstance(other, range):
|
|
729
|
+
return self.range == other
|
|
730
|
+
elif isinstance(other, IntRange):
|
|
731
|
+
return self.range == other.range
|
|
732
|
+
return False
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
override(IntRange)
|
|
736
|
+
__all__.append('IntRange')
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
class Int64Range(Gst.Int64Range):
|
|
740
|
+
def __init__(self, r: range):
|
|
741
|
+
if not isinstance(r, range):
|
|
742
|
+
raise TypeError(f"{type(r)} is not a range.")
|
|
743
|
+
|
|
744
|
+
if (r.start >= r.stop):
|
|
745
|
+
raise TypeError("Range start must be smaller then stop")
|
|
746
|
+
|
|
747
|
+
if r.start % r.step != 0:
|
|
748
|
+
raise TypeError("Range start must be a multiple of the step")
|
|
749
|
+
|
|
750
|
+
if r.stop % r.step != 0:
|
|
751
|
+
raise TypeError("Range stop must be a multiple of the step")
|
|
752
|
+
|
|
753
|
+
self.range = r
|
|
754
|
+
|
|
755
|
+
def __repr__(self) -> str:
|
|
756
|
+
return f'<Gst.Int64Range [{self.range.start},{self.range.stop},{self.range.step}]>'
|
|
757
|
+
|
|
758
|
+
def __str__(self) -> str:
|
|
759
|
+
if self.range.step == 1:
|
|
760
|
+
return f'(int64)[{self.range.start},{self.range.stop}]'
|
|
761
|
+
else:
|
|
762
|
+
return f'(int64)[{self.range.start},{self.range.stop},{self.range.step}]'
|
|
763
|
+
|
|
764
|
+
def __eq__(self, other: object) -> bool:
|
|
765
|
+
if isinstance(other, range):
|
|
766
|
+
return self.range == other
|
|
767
|
+
elif isinstance(other, IntRange):
|
|
768
|
+
return self.range == other.range
|
|
769
|
+
return False
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
class Bitmask(Gst.Bitmask):
|
|
773
|
+
def __init__(self, v: int) -> None:
|
|
774
|
+
if not isinstance(v, int):
|
|
775
|
+
raise TypeError(f"{type(v)} is not an int.")
|
|
776
|
+
|
|
777
|
+
self.v = int(v)
|
|
778
|
+
|
|
779
|
+
def __str__(self) -> str:
|
|
780
|
+
return hex(self.v)
|
|
781
|
+
|
|
782
|
+
def __eq__(self, other: object):
|
|
783
|
+
return self.v == other
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
override(Bitmask)
|
|
787
|
+
__all__.append('Bitmask')
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
override(Int64Range)
|
|
791
|
+
__all__.append('Int64Range')
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
class DoubleRange(Gst.DoubleRange):
|
|
795
|
+
def __init__(self, start: int | float, stop: int | float):
|
|
796
|
+
self.start = float(start)
|
|
797
|
+
self.stop = float(stop)
|
|
798
|
+
|
|
799
|
+
if (start >= stop):
|
|
800
|
+
raise TypeError("Range start must be smaller then stop")
|
|
801
|
+
|
|
802
|
+
def __repr__(self) -> str:
|
|
803
|
+
return f'<Gst.DoubleRange [{self.start},{self.stop}]>'
|
|
804
|
+
|
|
805
|
+
def __str__(self) -> str:
|
|
806
|
+
return f'(double)[{self.start},{self.stop}]'
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
override(DoubleRange)
|
|
810
|
+
__all__.append('DoubleRange')
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
class FractionRange(Gst.FractionRange):
|
|
814
|
+
def __init__(self, start: Fraction, stop: Fraction):
|
|
815
|
+
if not isinstance(start, Fraction):
|
|
816
|
+
raise TypeError(f"{type(start)} is not a Gst.Fraction.")
|
|
817
|
+
|
|
818
|
+
if not isinstance(stop, Fraction):
|
|
819
|
+
raise TypeError(f"{type(stop)} is not a Gst.Fraction.")
|
|
820
|
+
|
|
821
|
+
if (float(start) >= float(stop)):
|
|
822
|
+
raise TypeError("Range start must be smaller then stop")
|
|
823
|
+
|
|
824
|
+
self.start = start
|
|
825
|
+
self.stop = stop
|
|
826
|
+
|
|
827
|
+
def __repr__(self) -> str:
|
|
828
|
+
return f'<Gst.FractionRange [{self.start},{self.stop}]>'
|
|
829
|
+
|
|
830
|
+
def __str__(self) -> str:
|
|
831
|
+
return f'(fraction)[{self.start},{self.stop}]'
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
override(FractionRange)
|
|
835
|
+
__all__.append('FractionRange')
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
class ValueArray(Gst.ValueArray):
|
|
839
|
+
def __init__(self, array: typing.Optional[typing.List[typing.Any]] = None):
|
|
840
|
+
self.array = list(array or [])
|
|
841
|
+
|
|
842
|
+
def append(self, item: typing.Any) -> None:
|
|
843
|
+
self.array.append(item)
|
|
844
|
+
|
|
845
|
+
def prepend(self, item: typing.Any) -> None:
|
|
846
|
+
self.array = [item] + self.array
|
|
847
|
+
|
|
848
|
+
@staticmethod
|
|
849
|
+
def append_value(this: ValueArray, item: typing.Any) -> None:
|
|
850
|
+
this.append(item)
|
|
851
|
+
|
|
852
|
+
@staticmethod
|
|
853
|
+
def prepend_value(this: ValueArray, item: typing.Any) -> None:
|
|
854
|
+
this.prepend(item)
|
|
855
|
+
|
|
856
|
+
@staticmethod
|
|
857
|
+
def get_size(this: ValueArray) -> int:
|
|
858
|
+
return len(this.array)
|
|
859
|
+
|
|
860
|
+
def __iter__(self) -> typing.Iterator[typing.Any]:
|
|
861
|
+
return iter(self.array)
|
|
862
|
+
|
|
863
|
+
def __getitem__(self, index: int) -> typing.Any:
|
|
864
|
+
return self.array[index]
|
|
865
|
+
|
|
866
|
+
def __setitem__(self, index: int, value: typing.Any) -> None:
|
|
867
|
+
self.array[index] = value
|
|
868
|
+
|
|
869
|
+
def __len__(self) -> int:
|
|
870
|
+
return len(self.array)
|
|
871
|
+
|
|
872
|
+
def __str__(self) -> str:
|
|
873
|
+
return '<' + ','.join(map(str, self.array)) + '>'
|
|
874
|
+
|
|
875
|
+
def __repr__(self) -> str:
|
|
876
|
+
return f'<Gst.ValueArray {self}>'
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
override(ValueArray)
|
|
880
|
+
__all__.append('ValueArray')
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
class ValueList(Gst.ValueList):
|
|
884
|
+
def __init__(self, array: typing.Optional[typing.List[typing.Any]] = None):
|
|
885
|
+
self.array = list(array or [])
|
|
886
|
+
|
|
887
|
+
def append(self, item: typing.Any) -> None:
|
|
888
|
+
self.array.append(item)
|
|
889
|
+
|
|
890
|
+
def prepend(self, item: typing.Any) -> None:
|
|
891
|
+
self.array = [item] + self.array
|
|
892
|
+
|
|
893
|
+
@staticmethod
|
|
894
|
+
def append_value(this: ValueList, item: typing.Any) -> None:
|
|
895
|
+
this.append(item)
|
|
896
|
+
|
|
897
|
+
@staticmethod
|
|
898
|
+
def prepend_value(this: ValueList, item: typing.Any) -> None:
|
|
899
|
+
this.prepend(item)
|
|
900
|
+
|
|
901
|
+
@staticmethod
|
|
902
|
+
def get_size(this: ValueList) -> int:
|
|
903
|
+
return len(this.array)
|
|
904
|
+
|
|
905
|
+
def __iter__(self) -> typing.Iterator[typing.Any]:
|
|
906
|
+
return iter(self.array)
|
|
907
|
+
|
|
908
|
+
def __getitem__(self, index: int) -> typing.Any:
|
|
909
|
+
return self.array[index]
|
|
910
|
+
|
|
911
|
+
def __setitem__(self, index: int, value: typing.Any) -> None:
|
|
912
|
+
self.array[index] = value
|
|
913
|
+
|
|
914
|
+
def __len__(self) -> int:
|
|
915
|
+
return len(self.array)
|
|
916
|
+
|
|
917
|
+
def __str__(self) -> str:
|
|
918
|
+
return '{' + ','.join(map(str, self.array)) + '}'
|
|
919
|
+
|
|
920
|
+
def __repr__(self) -> str:
|
|
921
|
+
return f'<Gst.ValueList {self}>'
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
override(ValueList)
|
|
925
|
+
__all__.append('ValueList')
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
class TagList(Gst.TagList):
|
|
929
|
+
def __init__(self):
|
|
930
|
+
Gst.TagList.__init__(self)
|
|
931
|
+
|
|
932
|
+
def __getitem__(self, index: int) -> typing.Any:
|
|
933
|
+
if index >= self.n_tags():
|
|
934
|
+
raise IndexError('taglist index out of range')
|
|
935
|
+
|
|
936
|
+
key = self.nth_tag_name(index)
|
|
937
|
+
(res, val) = Gst.TagList.copy_value(self, key)
|
|
938
|
+
if not res:
|
|
939
|
+
raise KeyError(f"tag {key} not found")
|
|
940
|
+
return val
|
|
941
|
+
|
|
942
|
+
def __setitem__(self, key: str, value: typing.Any) -> None:
|
|
943
|
+
self.add_value(Gst.TagMergeMode.REPLACE, key, value)
|
|
944
|
+
|
|
945
|
+
def keys(self) -> typing.Iterable[str]:
|
|
946
|
+
keys = set()
|
|
947
|
+
|
|
948
|
+
def foreach(list, fid: str, udata):
|
|
949
|
+
keys.add(fid)
|
|
950
|
+
return True
|
|
951
|
+
|
|
952
|
+
self.foreach(foreach, None, None)
|
|
953
|
+
return keys
|
|
954
|
+
|
|
955
|
+
def enumerate(self) -> map[tuple[str, typing.Any]]:
|
|
956
|
+
return map(lambda k: (k, Gst.TagList.copy_value(self, k)[1]), self.keys())
|
|
957
|
+
|
|
958
|
+
def __len__(self) -> int:
|
|
959
|
+
return self.n_tags()
|
|
960
|
+
|
|
961
|
+
def __str__(self) -> str:
|
|
962
|
+
return self.to_string()
|
|
963
|
+
|
|
964
|
+
def __repr__(self) -> str:
|
|
965
|
+
return f'<Gst.TagList {self}>'
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
override(TagList)
|
|
969
|
+
__all__.append('TagList')
|
|
970
|
+
|
|
971
|
+
# From https://docs.python.org/3/library/itertools.html
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def pairwise(iterable: typing.Iterable[Element]) -> typing.Iterator[tuple[Element, Element]]:
|
|
975
|
+
a, b = itertools.tee(iterable)
|
|
976
|
+
next(b, None)
|
|
977
|
+
return zip(a, b)
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
class MapInfo:
|
|
981
|
+
def __init__(self):
|
|
982
|
+
self.memory = None
|
|
983
|
+
self.flags = Gst.MapFlags(0)
|
|
984
|
+
self.size = 0
|
|
985
|
+
self.maxsize = 0
|
|
986
|
+
self.data = None
|
|
987
|
+
self.user_data = None
|
|
988
|
+
self.__parent__ = None
|
|
989
|
+
|
|
990
|
+
def __iter__(self):
|
|
991
|
+
# Make it behave like a tuple similar to the PyGObject generated API for
|
|
992
|
+
# the `Gst.Buffer.map()` and friends.
|
|
993
|
+
for i in (self.__parent__ is not None, self):
|
|
994
|
+
yield i
|
|
995
|
+
|
|
996
|
+
def __enter__(self) -> Self:
|
|
997
|
+
if not self.__parent__:
|
|
998
|
+
raise MapError('MappingError', 'Mapping was not successful')
|
|
999
|
+
|
|
1000
|
+
return self
|
|
1001
|
+
|
|
1002
|
+
def __exit__(self, type, value, tb):
|
|
1003
|
+
if not self.__parent__.unmap(self):
|
|
1004
|
+
raise MapError('MappingError', 'Unmapping was not successful')
|
|
1005
|
+
|
|
1006
|
+
def get_data(self):
|
|
1007
|
+
return self.data
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
__all__.append("MapInfo")
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
class Buffer(MiniObjectMixin, Gst.Buffer):
|
|
1014
|
+
@property # type: ignore[override]
|
|
1015
|
+
def flags(self) -> BufferFlags:
|
|
1016
|
+
return _gi_gst.mini_object_flags(self)
|
|
1017
|
+
|
|
1018
|
+
@flags.setter
|
|
1019
|
+
def flags(self, flags: BufferFlags) -> None:
|
|
1020
|
+
_gi_gst.mini_object_set_flags(self, flags)
|
|
1021
|
+
|
|
1022
|
+
@property
|
|
1023
|
+
def dts(self) -> int:
|
|
1024
|
+
return _gi_gst.buffer_get_dts(self)
|
|
1025
|
+
|
|
1026
|
+
@dts.setter
|
|
1027
|
+
def dts(self, dts: int) -> None:
|
|
1028
|
+
_gi_gst.buffer_set_dts(self, dts)
|
|
1029
|
+
|
|
1030
|
+
@property
|
|
1031
|
+
def pts(self) -> int:
|
|
1032
|
+
return _gi_gst.buffer_get_pts(self)
|
|
1033
|
+
|
|
1034
|
+
@pts.setter
|
|
1035
|
+
def pts(self, pts: int) -> None:
|
|
1036
|
+
_gi_gst.buffer_set_pts(self, pts)
|
|
1037
|
+
|
|
1038
|
+
@property
|
|
1039
|
+
def duration(self) -> int:
|
|
1040
|
+
return _gi_gst.buffer_get_duration(self)
|
|
1041
|
+
|
|
1042
|
+
@duration.setter
|
|
1043
|
+
def duration(self, duration: int) -> None:
|
|
1044
|
+
_gi_gst.buffer_set_duration(self, duration)
|
|
1045
|
+
|
|
1046
|
+
@property
|
|
1047
|
+
def offset(self) -> int:
|
|
1048
|
+
return _gi_gst.buffer_get_offset(self)
|
|
1049
|
+
|
|
1050
|
+
@offset.setter
|
|
1051
|
+
def offset(self, offset: int) -> None:
|
|
1052
|
+
_gi_gst.buffer_set_offset(self, offset)
|
|
1053
|
+
|
|
1054
|
+
@property
|
|
1055
|
+
def offset_end(self) -> int:
|
|
1056
|
+
return _gi_gst.buffer_get_offset_end(self)
|
|
1057
|
+
|
|
1058
|
+
@offset_end.setter
|
|
1059
|
+
def offset_end(self, offset_end: int) -> None:
|
|
1060
|
+
_gi_gst.buffer_set_offset_end(self, offset_end)
|
|
1061
|
+
|
|
1062
|
+
def map_range(self, idx: int, length: int, flags: MapFlags) -> MapInfo: # type: ignore[override]
|
|
1063
|
+
mapinfo = MapInfo()
|
|
1064
|
+
if (_gi_gst.buffer_override_map_range(self, mapinfo, idx, length, int(flags))):
|
|
1065
|
+
mapinfo.__parent__ = self
|
|
1066
|
+
|
|
1067
|
+
return mapinfo
|
|
1068
|
+
|
|
1069
|
+
def map(self, flags: MapFlags) -> MapInfo: # type: ignore[override]
|
|
1070
|
+
mapinfo = MapInfo()
|
|
1071
|
+
if _gi_gst.buffer_override_map(self, mapinfo, int(flags)):
|
|
1072
|
+
mapinfo.__parent__ = self
|
|
1073
|
+
|
|
1074
|
+
return mapinfo
|
|
1075
|
+
|
|
1076
|
+
def unmap(self, mapinfo: MapInfo) -> bool: # type: ignore[override]
|
|
1077
|
+
mapinfo.__parent__ = None
|
|
1078
|
+
return _gi_gst.buffer_override_unmap(self, mapinfo)
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
override(Buffer)
|
|
1082
|
+
__all__.append('Buffer')
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
class Memory(Gst.Memory):
|
|
1086
|
+
|
|
1087
|
+
def map(self, flags: MapFlags) -> MapInfo: # type: ignore[override]
|
|
1088
|
+
mapinfo = MapInfo()
|
|
1089
|
+
if (_gi_gst.memory_override_map(self, mapinfo, int(flags))):
|
|
1090
|
+
mapinfo.__parent__ = self
|
|
1091
|
+
|
|
1092
|
+
return mapinfo
|
|
1093
|
+
|
|
1094
|
+
def unmap(self, mapinfo: MapInfo) -> bool: # type: ignore[override]
|
|
1095
|
+
mapinfo.__parent__ = None
|
|
1096
|
+
return _gi_gst.memory_override_unmap(self, mapinfo)
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
override(Memory)
|
|
1100
|
+
__all__.append('Memory')
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
def TIME_ARGS(time: int) -> str:
|
|
1104
|
+
if time == Gst.CLOCK_TIME_NONE:
|
|
1105
|
+
return "CLOCK_TIME_NONE"
|
|
1106
|
+
|
|
1107
|
+
return "%u:%02u:%02u.%09u" % (time / (Gst.SECOND * 60 * 60),
|
|
1108
|
+
(time / (Gst.SECOND * 60)) % 60,
|
|
1109
|
+
(time / Gst.SECOND) % 60,
|
|
1110
|
+
time % Gst.SECOND)
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
__all__.append('TIME_ARGS')
|
|
1114
|
+
|
|
1115
|
+
from gi.overrides import _gi_gst # type: ignore[attr-defined]
|
|
1116
|
+
_gi_gst
|
|
1117
|
+
|
|
1118
|
+
# maybe more python and less C some day if core turns a bit more introspection
|
|
1119
|
+
# and binding friendly in the debug area
|
|
1120
|
+
Gst.trace = _gi_gst.trace
|
|
1121
|
+
Gst.log = _gi_gst.log
|
|
1122
|
+
Gst.debug = _gi_gst.debug
|
|
1123
|
+
Gst.info = _gi_gst.info
|
|
1124
|
+
Gst.warning = _gi_gst.warning
|
|
1125
|
+
Gst.error = _gi_gst.error
|
|
1126
|
+
Gst.fixme = _gi_gst.fixme
|
|
1127
|
+
Gst.memdump = _gi_gst.memdump
|
|
1128
|
+
|
|
1129
|
+
# Make sure PyGst is not usable if GStreamer has not been initialized
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
class NotInitialized(Exception):
|
|
1133
|
+
pass
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
__all__.append('NotInitialized')
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
def fake_method(*args):
|
|
1140
|
+
raise NotInitialized("Please call Gst.init(argv) before using GStreamer")
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
def find_gi_repository_parent(klass):
|
|
1144
|
+
"""Find the gi.repository parent class in the MRO for introspection methods"""
|
|
1145
|
+
for parent in klass.__mro__:
|
|
1146
|
+
if parent.__module__.startswith('gi.repository.'):
|
|
1147
|
+
return parent
|
|
1148
|
+
return None
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def _collect_methods_from_dict(source_dict, klass, seen):
|
|
1152
|
+
"""Helper to collect methods from a class dictionary, avoiding dunder methods."""
|
|
1153
|
+
methods = []
|
|
1154
|
+
for attr_name in source_dict:
|
|
1155
|
+
if attr_name in seen:
|
|
1156
|
+
continue
|
|
1157
|
+
attr = source_dict[attr_name]
|
|
1158
|
+
if isinstance(attr, (type(Gst.init), staticmethod, classmethod)):
|
|
1159
|
+
# Skip dunder methods as they're Python special methods used for
|
|
1160
|
+
# object instantiation and other internals, replacing them breaks
|
|
1161
|
+
# class behavior
|
|
1162
|
+
if not attr_name.startswith('__'):
|
|
1163
|
+
methods.append((attr_name, getattr(klass, attr_name)))
|
|
1164
|
+
seen.add(attr_name)
|
|
1165
|
+
return methods
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
real_functions = [o for o in inspect.getmembers(Gst) if isinstance(o[1], type(Gst.init))]
|
|
1169
|
+
|
|
1170
|
+
class_methods = []
|
|
1171
|
+
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))]:
|
|
1172
|
+
klass = cname_klass[1]
|
|
1173
|
+
methods = []
|
|
1174
|
+
seen: set[str] = set()
|
|
1175
|
+
|
|
1176
|
+
# Collect methods from the override class itself
|
|
1177
|
+
methods.extend(_collect_methods_from_dict(klass.__dict__, klass, seen))
|
|
1178
|
+
|
|
1179
|
+
# Collect methods from the gi.repository introspection parent class
|
|
1180
|
+
gi_parent = find_gi_repository_parent(klass)
|
|
1181
|
+
if gi_parent:
|
|
1182
|
+
methods.extend(_collect_methods_from_dict(gi_parent.__dict__, klass, seen))
|
|
1183
|
+
|
|
1184
|
+
class_methods.append((cname_klass, methods))
|
|
1185
|
+
|
|
1186
|
+
pre_init_functions = set([
|
|
1187
|
+
"init",
|
|
1188
|
+
"init_check",
|
|
1189
|
+
"deinit",
|
|
1190
|
+
"is_initialized",
|
|
1191
|
+
"debug_add_log_function",
|
|
1192
|
+
"debug_add_ring_buffer_logger",
|
|
1193
|
+
"debug_remove_log_function",
|
|
1194
|
+
"debug_remove_log_function_by_data",
|
|
1195
|
+
"debug_remove_ring_buffer_logger",
|
|
1196
|
+
"debug_set_active",
|
|
1197
|
+
"debug_set_color_mode",
|
|
1198
|
+
"debug_set_color_mode_from_string",
|
|
1199
|
+
"debug_set_colored",
|
|
1200
|
+
"debug_set_default_threshold",
|
|
1201
|
+
])
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
def init_pygst():
|
|
1205
|
+
for fname, function in real_functions:
|
|
1206
|
+
if fname not in ["init", "init_check", "deinit"]:
|
|
1207
|
+
setattr(Gst, fname, function)
|
|
1208
|
+
|
|
1209
|
+
for cname_class, methods in class_methods:
|
|
1210
|
+
for mname, method in methods:
|
|
1211
|
+
setattr(cname_class[1], mname, method)
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
def deinit_pygst():
|
|
1215
|
+
for fname, func in real_functions:
|
|
1216
|
+
if fname not in pre_init_functions:
|
|
1217
|
+
setattr(Gst, fname, fake_method)
|
|
1218
|
+
for cname_class, methods in class_methods:
|
|
1219
|
+
for mname, method in methods:
|
|
1220
|
+
setattr(cname_class[1], mname, fake_method)
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
real_init = Gst.init
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
def init(argv: typing.Optional[list[str]] = None) -> None:
|
|
1227
|
+
init_pygst()
|
|
1228
|
+
|
|
1229
|
+
if Gst.is_initialized():
|
|
1230
|
+
return
|
|
1231
|
+
|
|
1232
|
+
# FIXME: Workaround for pygobject handling nullability wrong
|
|
1233
|
+
if argv is None:
|
|
1234
|
+
argv = []
|
|
1235
|
+
|
|
1236
|
+
real_init(argv)
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
Gst.init = init
|
|
1240
|
+
|
|
1241
|
+
real_init_check = Gst.init_check
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
def init_check(argv: typing.Optional[list[str]] = None) -> typing.Tuple[bool, typing.Optional[list[str]]]:
|
|
1245
|
+
init_pygst()
|
|
1246
|
+
if Gst.is_initialized():
|
|
1247
|
+
return True, argv
|
|
1248
|
+
|
|
1249
|
+
return real_init_check(argv)
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
Gst.init_check = init_check
|
|
1253
|
+
|
|
1254
|
+
real_deinit = Gst.deinit
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
def deinit() -> None:
|
|
1258
|
+
deinit_pygst()
|
|
1259
|
+
real_deinit()
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
def init_python():
|
|
1263
|
+
if not Gst.is_initialized():
|
|
1264
|
+
raise NotInitialized("Gst.init_python should never be called before GStreamer itself is initialized")
|
|
1265
|
+
|
|
1266
|
+
init_pygst()
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
Gst.deinit = deinit
|
|
1270
|
+
Gst.init_python = init_python
|
|
1271
|
+
|
|
1272
|
+
if not Gst.is_initialized():
|
|
1273
|
+
deinit_pygst()
|