gstlal
1.13.0
Toggle main menu visibility
Loading...
Searching...
No Matches
python
gstpipetools.py
1
"""Miscellaneous utilities for working with Gstreamer Pipelines
2
3
References:
4
[1] 1.0 API: https://lazka.github.io/pgi-docs/Gst-1.0/index.html
5
"""
6
from
typing
import
Any, Union, Tuple, Iterable, Optional, Callable
7
8
import
gi
9
10
gi.require_version(
'Gst'
,
'1.0'
)
11
from
gi.repository
import
GObject
12
from
gi.repository
import
Gst
13
14
GObject.threads_init()
15
Gst.init(
None
)
16
17
from
lal
import
LIGOTimeGPS
18
from
gstlal
import
simplehandler
19
from
gstlal
import
pipeio
20
21
LIVE_SEGMENT = (
None
,
None
)
22
Time = Union[int, float, LIGOTimeGPS]
23
24
25
def
is_element
(x: Any) -> bool:
26
"""Test whether an object is a Gst Element. TODO: do these belong somewhere more general?
27
28
Args:
29
x:
30
Any, the object to test
31
32
Returns:
33
bool, True if x is a Gst Element, false otherwise
34
"""
35
return
isinstance(x, Gst.Element)
36
37
38
def
is_pad
(x: Any) -> bool:
39
"""Test whether an object is a Gst Pad. TODO: do these belong somewhere more general?
40
41
Args:
42
x:
43
Any, the object to test
44
45
Returns:
46
bool, True if x is a Gst Pad, false otherwise
47
"""
48
return
isinstance(x, Gst.Pad)
49
50
51
def
to_caps
(x: Union[str, Gst.Caps]) -> Gst.Caps:
52
"""Create a Caps object from a string, or pass thru if already is Caps
53
54
Args:
55
x:
56
str or Caps, if a string construct Caps instance from x, else pass thru as Caps
57
58
Returns:
59
Caps
60
"""
61
if
isinstance(x, str):
62
return
Gst.Caps.from_string(x)
63
if
not
isinstance(x, Gst.Caps):
64
raise
ValueError(
'Cannot coerce type {} to Caps: {}'
.format(type(x), str(x)))
65
return
x
66
67
68
def
make_element
(type_name: str, name: str =
None
, **properties: dict) -> Gst.Element:
69
"""Create a new element of the type defined by the given element factory. If name is None, then the element will
70
receive a guaranteed unique name, consisting of the element factory name and a number. If name is given, it will
71
be given the name supplied.
72
73
Args:
74
type_name:
75
str, the name of the type of element
76
elem_name:
77
str, default None, the name of the element instance
78
properties:
79
dict, keyword arguments to set as properties of the element
80
81
References:
82
[1] ElementFactor.make: https://lazka.github.io/pgi-docs/Gst-1.0/classes/ElementFactory.html#Gst.ElementFactory.make
83
84
Returns:
85
Gst.Element
86
"""
87
elem = Gst.ElementFactory.make(type_name, name)
88
if
elem
is
None
:
89
raise
RuntimeError(
"Unknown failure creating {} element: confirm that the correct plugins are being loaded"
.format(type_name))
90
91
# Set element properties
92
for
k, v
in
properties.items():
93
elem.set_property(k, pipeio.format_property(v))
94
95
return
elem
96
97
98
def
make_pipeline
(name: str) -> Gst.Pipeline:
99
"""Create a Pipeline, which is the macroscopic container for Gstreamer elements and is necessary
100
prior to creating any elements
101
102
Args:
103
name:
104
str, the name of the pipeline
105
106
References:
107
[1] https://gstreamer.freedesktop.org/documentation/application-development/introduction/basics.html?gi-language=c#bins-and-pipelines
108
109
Returns:
110
Pipeline
111
"""
112
return
Gst.Pipeline(name)
113
114
115
def
run_pipeline
(pipeline: Gst.Pipeline, segment: Tuple[Time, Time] = LIVE_SEGMENT, handlers: Optional[Iterable[Callable]] =
None
):
116
"""Run a pipeline using the main event loop
117
118
Args:
119
pipeline:
120
Gst.Pipeline, the pipeline to run
121
segment:
122
Tuple[Time, Time], a playback segment
123
handlers:
124
Iterable[Callable], default None, an optional list of functions that return Handlers. Each must
125
accept only a "mainloop" and "pipeline" argument.
126
127
Returns:
128
None
129
"""
130
if
handlers
is
None
:
131
handlers = (
simplehandler.Handler
,)
132
133
mainloop = GObject.MainLoop()
134
135
# Set handlers
136
for
handler
in
handlers:
137
_ = handler(mainloop=mainloop, pipeline=pipeline)
138
139
if
pipeline.set_state(Gst.State.READY) != Gst.StateChangeReturn.SUCCESS:
140
raise
RuntimeError(
"pipeline did not enter ready state"
)
141
142
seek
(pipeline, segment)
143
144
if
pipeline.set_state(Gst.State.PLAYING) != Gst.StateChangeReturn.SUCCESS:
145
raise
RuntimeError(
"pipeline did not enter playing state"
)
146
147
mainloop.run()
148
149
150
def
seek
(pipeline, segment: Tuple[Time, Time], flags=Gst.SeekFlags.FLUSH):
151
"""Create a new seek event, i.e., Gst.Event.new_seek() for a given
152
gps_start_time and gps_end_time, with optional flags.
153
154
Args:
155
pipeline:
156
gps_start_time:
157
start time as LIGOTimeGPS, float
158
gps_end_time:
159
end time as LIGOTimeGPS, float
160
flags:
161
Optional flags, see [2] for options
162
163
Notes:
164
In contrast to the documentation, we set the seek event directly on the pipeline sources. This is because of implementation
165
issues in framecpp demux that prevent the full backward propagation of the seek event from sink -> source (as is done in the
166
gstreamer documentation [1]).
167
168
References:
169
[1] https://gstreamer.freedesktop.org/documentation/additional/design/seeking.html?gi-language=python
170
[2] Flags https://gstreamer.freedesktop.org/documentation/gstreamer/gstsegment.html?gi-language=python#GstSeekFlags
171
172
Returns:
173
None
174
"""
175
start, end = segment
176
177
start_type, start_time =
seek_args
(start)
178
stop_type, stop_time =
seek_args
(end)
179
180
if
pipeline.current_state != Gst.State.READY:
181
raise
ValueError(
"pipeline must be in READY state"
)
182
183
pipeline.seek(rate=1.0,
184
format=Gst.Format(Gst.Format.TIME),
185
flags=flags,
186
start_type=start_type,
187
start=start_time,
188
stop_type=stop_type,
189
stop=stop_time)
190
191
for
elem
in
pipeline.iterate_sources():
192
elem.seek(rate=1.0,
193
format=Gst.Format(Gst.Format.TIME),
194
flags=flags,
195
start_type=start_type,
196
start=start_time,
197
stop_type=stop_type,
198
stop=stop_time)
199
200
201
def
seek_args
(time: Time) -> Tuple[Gst.SeekType, int]:
202
"""Convenience function for determining the type of arguments to seek for a given time input
203
204
Args:
205
time:
206
Time, either a float or LIGOTimeGPS
207
208
Returns:
209
Tuple[Gst.SeekType, int]
210
"""
211
if
time
is
None
or
time == -1:
212
return
(Gst.SeekType.NONE, -1)
# -1 == Gst.CLOCK_TIME_NONE
213
elif
isinstance(time, LIGOTimeGPS):
214
return
(Gst.SeekType.SET, time.ns())
215
else
:
216
return
(Gst.SeekType.SET, int(float(time) * Gst.SECOND))
python.simplehandler.Handler
Definition
simplehandler.py:59
python.gstpipetools.seek_args
Tuple[Gst.SeekType, int] seek_args(Time time)
Definition
gstpipetools.py:201
python.gstpipetools.run_pipeline
run_pipeline(Gst.Pipeline pipeline, Tuple[Time, Time] segment=LIVE_SEGMENT, Optional[Iterable[Callable]] handlers=None)
Definition
gstpipetools.py:115
python.gstpipetools.make_pipeline
Gst.Pipeline make_pipeline(str name)
Definition
gstpipetools.py:98
python.gstpipetools.to_caps
Gst.Caps to_caps(Union[str, Gst.Caps] x)
Definition
gstpipetools.py:51
python.gstpipetools.make_element
Gst.Element make_element(str type_name, str name=None, **dict properties)
Definition
gstpipetools.py:68
python.gstpipetools.is_pad
bool is_pad(Any x)
Definition
gstpipetools.py:38
python.gstpipetools.is_element
bool is_element(Any x)
Definition
gstpipetools.py:25
python.gstpipetools.seek
seek(pipeline, Tuple[Time, Time] segment, flags=Gst.SeekFlags.FLUSH)
Definition
gstpipetools.py:150
Generated by
1.17.0