1""""Module for producing sink elements
8from typing
import Tuple
11from lal
import LIGOTimeGPS
12from lal.utils
import CacheEntry
13from ligo
import segments
17gi.require_version(
'Gst',
'1.0')
18from gi.repository
import GObject
19from gi.repository
import Gst
24from gstlal.pipeparts
import pipetools, pipedot, mux, encode, filters, transform
26BYTE_ORDER =
'LE' if sys.byteorder ==
"little" else 'BE'
30 """Add path for file sink to element
34 Element, the element to which to add a filesink path property
38 Tuple[str, int], a string outpath and a directory digits int
41 >>> filesinkelem.connect("notify::timestamp", framecpp_filesink_ldas_path_handler, (".", 5))
44 Element, with the formatted outpath attached as the "path" property
46 outpath, dir_digits = path_digits
49 timestamp = elem.get_property(
"timestamp") // Gst.SECOND
52 leading_digits = timestamp // 10 ** int(math.log10(timestamp) + 1 - dir_digits)
55 instrument = elem.get_property(
"instrument")
56 frame_type = elem.get_property(
"frame-type")
59 path = os.path.join(outpath,
"%s-%s-%d" % (instrument, frame_type, leading_digits))
60 if not os.path.exists(path):
62 elem.set_property(
"path", path)
66 """Translate an element message posted by the multifilesink element
67 inside a framecpp_filesink bin into a lal.utils.CacheEntry object
68 describing the file being written by the multifilesink element.
71 start = LIGOTimeGPS(0, message.get_structure()[
"timestamp"])
72 end = start + LIGOTimeGPS(0, message.get_structure()[
"duration"])
76 parent = message.src.get_parent()
79 return CacheEntry(parent.get_property(
"instrument"), parent.get_property(
"frame-type"), segments.segment(start, end),
80 "file://localhost%s" % os.path.abspath(message.get_structure()[
"filename"]))
84def multi_file(pipeline: pipetools.Pipeline, src: pipetools.Element, next_file: int = 0, sync: bool =
False, async_: bool =
False, **properties) -> pipetools.Element:
85 """Adds a sink element to a pipeline with useful default properties
89 Gst.Pipeline, the pipeline to which the new element will be added
91 Gst.Element, the source element
103 properties[
"async"] = async_
104 return pipetools.make_element_with_src(pipeline, src,
"multifilesink", next_file=next_file, sync=sync, **properties)
107def gwf(pipeline: pipetools.Pipeline, src: pipetools.Element, message_forward: bool =
True, **properties) -> pipetools.Element:
108 """Add a framecpp file sink element to pipeline, that will write out a GWF file
112 Gst.Pipeline, the pipeline to which the new element will be added
114 Gst.Element, the source element
120 Implementation: gstlal-ugly/gst/framecpp/framecpp_filesink.c
125 post_messages = properties.pop(
"post_messages",
True)
126 elem = pipetools.make_element_with_src(pipeline, src,
"framecpp_filesink", message_forward=message_forward, **properties)
130 elem.get_by_name(
"multifilesink").set_property(
"post-messages", post_messages)
135def fake(pipeline: pipetools.Pipeline, src: pipetools.Element) -> pipetools.Element:
136 """Create a fake sink element
140 Gst.Pipeline, the pipeline to which the new element will be added
142 Gst.Element, the source element
147 return pipetools.make_element_with_src(pipeline, src,
"fakesink", sync=
False, **{
"async":
False})
151def file(pipeline: pipetools.Pipeline, src: pipetools.Element, filename: str, sync: bool =
False, async_: bool =
False) -> pipetools.Element:
152 """Add file sink to pipeline
156 Gst.Pipeline, the pipeline to which the new element will be added
158 Gst.Element, the source element
160 str, the name of the output file
169 return pipetools.make_element_with_src(pipeline, src,
"filesink", sync=sync, buffer_mode=2, location=filename, **{
"async": async_})
173def tsv(pipeline: pipetools.Pipeline, src: pipetools.Element, filename: str, segment: pipetools.Segment =
None) -> pipetools.Element:
174 """Converts audio time-series to tab-separated ascii text, a format compatible with most plotting utilities.
175 The output is multi-column tab-separated ASCII text. The first column is the time, the remaining columns are
176 the values of the channels in order.
180 Gst.Pipeline, the pipeline to which the new element will be added
182 Gst.Element, the source element
184 str, the filename of the output text file
186 Segment, default None, a ligo.segments.segment
191 if segment
is not None:
192 elem = pipetools.make_element_with_src(pipeline, src,
"lal_nxydump", start_time=segment[0].ns(), stop_time=segment[1].ns())
194 elem = pipetools.make_element_with_src(pipeline, src,
"lal_nxydump")
195 return file(pipeline, elem, filename)
198def ogm_video(pipeline: pipetools.Pipeline, videosrc: pipetools.Element, filename: str, audiosrc: pipetools.Element =
None, verbose: bool =
False):
199 """Make a ogm video sink element
203 Gst.Pipeline, the pipeline to which the new element will be added
205 Gst.Element, the video source element
207 str, the name of the output video file
209 Gst.Element, default None, the audio source element
214 Element, the sink element
216 src = transform.colorspace(pipeline, videosrc)
217 src = filters.caps(pipeline, src,
"video/x-raw-yuv, format=(fourcc)I420")
218 src = encode.theora(pipeline, src,
223 src = mux.ogg_mux(pipeline, src)
224 if audiosrc
is not None:
225 encode.flac(pipeline, filters.caps(pipeline, transform.audio_convert(pipeline, audiosrc),
"audio/x-raw, format=S24%s" % BYTE_ORDER)).link(src)
227 src = progress_report(pipeline, src, filename)
228 return file(pipeline, src, filename)
231def auto_video(pipeline: pipetools.Pipeline, src: pipetools.Element) -> pipetools.Element:
232 """Create a video sink that automatically detects an appropriate video sink to use. It does so by scanning the
233 registry for all elements that have "Sink" and "Video" in the class field of their element information, and
234 also have a non-zero autoplugging rank.
238 Gst.Pipeline, the pipeline to which the new element will be added
240 Gst.Element, the source element
243 [1] https://gstreamer.freedesktop.org/documentation/autodetect/autovideosink.html?gi-language=python
248 return pipetools.make_element_with_src(pipeline, transform.colorspace(pipeline, src),
"autovideosink")
252def auto_audio(pipeline: pipetools.Pipeline, src: pipetools.Element) -> pipetools.Element:
253 """Create an audio sink that automatically detects an appropriate audio sink to use. It does so by
254 scanning the registry for all elements that have "Sink" and "Audio" in the class field of their element
255 information, and also have a non-zero autoplugging rank.
259 Gst.Pipeline, the pipeline to which the new element will be added
261 Gst.Element, the source element
264 [1] https://gstreamer.freedesktop.org/documentation/autodetect/autoaudiosink.html?gi-language=python
269 return pipetools.make_element_with_src(pipeline, transform.queue(pipeline, src),
"autoaudiosink")
272def playback(pipeline: pipetools.Pipeline, src: pipetools.Element, amplification: float = 0.1) -> pipetools.Element:
273 """Create a playback pipeline and add it to existing pipeline
277 Gst.Pipeline, the pipeline to which the new element will be added
279 Gst.Element, the source element
287 Gst.ElementFactory.make(
"audioconvert",
None),
288 Gst.ElementFactory.make(
"capsfilter",
None),
289 Gst.ElementFactory.make(
"audioamplify",
None),
290 Gst.ElementFactory.make(
"audioconvert",
None),
291 Gst.ElementFactory.make(
"queue",
None),
292 Gst.ElementFactory.make(
"autoaudiosink",
None)
294 elems[1].set_property(
"caps", Gst.Caps.from_string(
"audio/x-raw, format=F32%s" % BYTE_ORDER))
295 elems[2].set_property(
"amplification", amplification)
296 elems[4].set_property(
"max-size-time", 1 * Gst.SECOND)
298 return Gst.element_link_many(src, *elems)
301def tsv_tee(pipeline: pipetools.Pipeline, src: pipetools.Element, *args, **properties) -> pipetools.Element:
302 """Split data from source to an nxy dump
306 Gst.Pipeline, the pipeline to which the new element will be added
308 Gst.Element, the source element
315 t = transform.tee(pipeline, src)
316 tsv(pipeline, transform.queue(pipeline, t), *args, **properties)
325 Gst.Pipeline, the pipeline to which the new element will be added
327 Gst.Element, the source element
329 str, output path for xml file
337 return pipetools.make_element_with_src(pipeline, src,
"lal_triggerxmlwriter", location=filename, sync=
False, **{
"async":
False})
343def app(pipeline: pipetools.Pipeline, src: pipetools.Element, max_buffers: int = 1, drop: bool =
False, sync: bool =
False, async_: bool =
False, **properties):
344 """Create an app sink, Appsink is a sink plugin that supports many different methods for making the
345 application get a handle on the GStreamer data in a pipeline. Unlike most GStreamer elements,
346 Appsink provides external API functions.
350 Gst.Pipeline, the pipeline to which the new element will be added
352 Gst.Element, the source element
364 [1] https://gstreamer.freedesktop.org/documentation/app/appsink.html?gi-language=python
369 properties[
"async"] = async_
370 return pipetools.make_element_with_src(pipeline, src,
"appsink", sync=sync, emit_signals=
True, max_buffers=max_buffers, drop=drop, **properties)
374 def __init__(self, appsink_new_buffer, appsinks=[]):
375 self.
lock = threading.Lock()
385 for elem
in appsinks:
388 def add_sink(self, pipeline, src, drop=False, **properties):
389 return self.
attach(
app(pipeline, src, drop=drop, **properties))
393 connect this AppSync's signal handlers to the given appsink
394 element. the element's max-buffers property will be set to
395 1 (required for AppSync to work).
398 raise ValueError(
"duplicate appsinks %s" % repr(appsink))
399 appsink.set_property(
"max-buffers", 1)
401 assert handler_id > 0
403 assert handler_id > 0
404 handler_id = appsink.connect(
"eos", self.
eos_handler)
405 assert handler_id > 0
409 def new_preroll_handler(self, elem):
414 elem.emit(
"pull-preroll")
415 return Gst.FlowReturn.OK
417 def new_sample_handler(self, elem):
422 self.
appsinks[elem] = elem.get_last_sample().get_buffer().pts
426 def eos_handler(self, elem):
435 for internal use. must be called with lock held.
442 timestamps = [(t, e)
for e, t
in self.
appsinks.items()
if e
not in self.
at_eos or t
is not None]
446 return Gst.FlowReturn.EOS
452 timestamp, elem_with_oldest = min(timestamps, key=
lambda x: x[0]
if x[0]
is not None else -numpy.inf)
456 if timestamp
is None:
457 return Gst.FlowReturn.OK
462 self.
appsinks[elem_with_oldest] =
None
467 """Add a signal handler to write a pipeline graph upon receipt of the
468 first trigger buffer. the caps in the pipeline graph are not fully
469 negotiated until data comes out the end, so this version of the graph
470 shows the final formats on all links
473 def __init__(self, pipeline, appsinks, basename, verbose=False):
475 self.
filestem =
"%s.%s" % (basename,
"TRIGGERS")
480 for sink
in appsinks:
484 def execute(self, elem):
489 elem.disconnect(handler_id)
490 return Gst.FlowReturn.OK
493def tcp_server(pipeline: pipetools.Pipeline, src: pipetools.Element, **properties) -> pipetools.Element:
494 """Create a sink via TCP server
498 Gst.Pipeline, the pipeline to which the new element will be added
500 Gst.Element, the source element
504 [1] https://gstreamer.freedesktop.org/documentation/tcp/tcpserversink.html?gi-language=python
511 return pipetools.make_element_with_src(pipeline, src,
"tcpserversink", sync=
True, sync_method=
"latest-keyframe", recover_policy=
"keyframe", unit_type=
"bytes",
512 units_soft_max=1024 ** 3,
new_sample_handler(self, elem)
new_preroll_handler(self, elem)
pipetools.Element auto_audio(pipetools.Pipeline pipeline, pipetools.Element src)
Adds a autoaudiosink element to a pipeline with useful default properties.
trigger_xml_writer(pipetools.Pipeline pipeline, pipetools.Element src, str filename)
pipetools.Element tsv_tee(pipetools.Pipeline pipeline, pipetools.Element src, *args, **properties)
pipetools.Element gwf(pipetools.Pipeline pipeline, pipetools.Element src, bool message_forward=True, **properties)
pipetools.Element auto_video(pipetools.Pipeline pipeline, pipetools.Element src)
pipetools.Element file(pipetools.Pipeline pipeline, pipetools.Element src, str filename, bool sync=False, bool async_=False)
Adds a filesink element to a pipeline with useful default properties.
framecpp_filesink_ldas_path_handler(pipetools.Element elem, pspec, Tuple[str, int] path_digits)
pipetools.Element tsv(pipetools.Pipeline pipeline, pipetools.Element src, str filename, pipetools.Segment segment=None)
Adds a lal_nxydump element to a pipeline with useful default properties.
framecpp_filesink_cache_entry_from_mfs_message(message)
pipetools.Element playback(pipetools.Pipeline pipeline, pipetools.Element src, float amplification=0.1)
pipetools.Element fake(pipetools.Pipeline pipeline, pipetools.Element src)
Adds a fakesink element to a pipeline with useful default properties.
ogm_video(pipetools.Pipeline pipeline, pipetools.Element videosrc, str filename, pipetools.Element audiosrc=None, bool verbose=False)
app(pipetools.Pipeline pipeline, pipetools.Element src, int max_buffers=1, bool drop=False, bool sync=False, bool async_=False, **properties)
Adds a appsink element to a pipeline with useful default properties.
pipetools.Element multi_file(pipetools.Pipeline pipeline, pipetools.Element src, int next_file=0, bool sync=False, bool async_=False, **properties)
Adds a multifilesink element to a pipeline with useful default properties.
pipetools.Element tcp_server(pipetools.Pipeline pipeline, pipetools.Element src, **properties)