56 Utility to watch for missing data. Pad probes are used to collect
57 the times spanned by buffers, these are compared to a segment list
58 defining the intervals of data the stream is required to have. If
59 any intervals of data are found to have been skipped or if EOS is
60 seen before the end of the segment list then a ValueError exception
63 There are two ways to use this tool. To directly install a segment
64 list monitor on a single pad use the .set_probe() class method.
65 For elements with dynamic pads, the class can be allowed to
66 automatically add monitors to pads as they become available by
67 using the element's pad-added signal. In this case initialize an
68 instance of the class with the element and a dictionary of segment
69 lists mapping source pad name to the segment list to check that
72 In both cases a jitter parameter sets the maximum size of a skipped
73 segment that will be ignored (for example, to accomodate round-off
74 error in element timestamp computations). The default is 1 ns.
86 def __init__(self, elem, seglists, jitter=LIGOTimeGPS(0, 1)):
94 def pad_added(self, element, pad, seglists):
103 def set_probe(cls, pad, seglist, jitter=LIGOTimeGPS(0, 1)):
105 seglist = segments.segmentlist(seglist)
107 data = [seglist, jitter,
None]
109 probe_id = data[2] = pad.add_probe(Gst.PadProbeType.DATA_DOWNSTREAM, cls.
probe, data)
113 def probe(pad, probeinfo, seg_jitter_id):
114 seglist, jitter, probe_id = seg_jitter_id
115 if probeinfo.type & Gst.PadProbeType.BUFFER:
116 obj = probeinfo.get_buffer()
117 if not obj.mini_object.flags & Gst.BufferFlags.GAP:
120 seglist -= segments.segmentlist([segments.segment((LIGOTimeGPS(0, obj.pts), LIGOTimeGPS(0, obj.pts + obj.duration)))])
123 iterutils.inplace_filter(
lambda seg: abs(seg) > jitter, seglist)
126 preceding = segments.segment((segments.NegInfinity, LIGOTimeGPS(0, obj.pts)))
127 if seglist.intersects_segment(preceding):
128 raise ValueError(
"%s: detected missing data: %s" % (pad.get_name(), seglist & segments.segmentlist([preceding])))
129 elif probeinfo.type & Gst.PadProbeType.EVENT_DOWNSTREAM
and probeinfo.get_event().type == Gst.EventType.EOS:
131 pad.remove_probe(probe_id)
134 iterutils.inplace_filter(
lambda seg: abs(seg) > jitter, seglist)
136 raise ValueError(
"%s: at EOS detected missing data: %s" % (pad.get_name(), seglist))
161 """Mux a source using framecpp
165 Gst.Pipeline, the pipeline to which the new element will be added
167 dict, mapping a channel -> src element
169 str, default None, if given set these units on source
171 default None, if given create a segments handler for these segments
175 Element, the muxed sources
177 elem = pipetools.make_element_with_src(pipeline,
None,
"framecpp_channelmux", **properties)
178 if channel_src_map
is not None:
179 for channel, src
in channel_src_map.items():
180 for srcpad
in src.srcpads:
188 if srcpad.link(elem.request_pad(Gst.PadTemplate.new(channel, Gst.PadDirection.SINK, Gst.PadPresence.REQUEST, Gst.Caps(
"ANY")), channel)) == Gst.PadLinkReturn.OK:
190 if units
is not None:
192 if seglists
is not None:
198 """Mux a source using framecpp
200 NOTE: This acts similarly to framecpp_channel_mux with a different function
201 signature to map channels to sources.
205 Gst.Pipeline, the pipeline to which the new element will be added
207 Gst.Element, the source elements
209 Union[str, Iterable], default None, the channels mapping to sources
211 default None, if given create a segments handler for these segments
215 Element, the muxed sources
217 if isinstance(channels, str):
218 channels = [channels]
219 channel_src_map = {channel: src
for channel, src
in zip(channels, srcs)}