roboto.experimental.video#
Video APIs in active refinement; see roboto.experimental for the stability contract.
Decodes compressed-video topic data (one Annex B-framed H.264 frame per MCAP
message, as written by Roboto ingestion for foxglove.CompressedVideo and
compatible schemas) into still frames on demand. Decoding requires the
roboto[video] extra; the bitstream-inspection helpers in
roboto.experimental.video.h264 are dependency-free.
Submodules#
Package Contents#
- roboto.experimental.video.DEFAULT_KEYFRAME_LOOKBACK_NS: int = 10000000000#
How far before a requested range to search for the keyframe that makes the range’s leading delta frames decodable. Bounds the cost of the backward walk on streams with pathological keyframe intervals.
- class roboto.experimental.video.DecodedVideoFrame(log_time, frame)#
A decoded video frame paired with the log time of its source message.
Pixel data stays in the decoder’s native representation until one of the accessors is called, so frames that a caller samples past are never converted.
- Parameters:
log_time (int)
frame (av.VideoFrame)
- property height: int#
Frame height in pixels.
- Return type:
int
- property is_keyframe: bool#
Whether this frame is a keyframe (clean decoder entry point).
- Return type:
bool
- property log_time: int#
Log time (nanoseconds since Unix epoch) of the message this frame came from.
- Return type:
int
- to_image()#
Convert the frame to a PIL RGB image.
- Returns:
The frame’s pixels as a
PIL.Image.Imagein RGB mode.- Raises:
ImportError – If Pillow is not installed (
roboto[video]).- Return type:
PIL.Image.Image
- to_ndarray()#
Convert the frame to an
(height, width, 3)uint8 RGB array.- Returns:
The frame’s pixels as a numpy array in RGB channel order.
- Raises:
ImportError – If numpy is not installed (
roboto[video]).- Return type:
numpy.ndarray
- property width: int#
Frame width in pixels.
- Return type:
int
- roboto.experimental.video.MessageRangeLoader#
Loads a topic’s
(log_time, data)messages for a(start_time, end_time)range.Both times are nanoseconds since Unix epoch; messages must come back in ascending log-time order. Whether
end_timeis inclusive follows the underlying reader — frame emission is bounded by log-time filtering, not by the loader’s boundary semantics.
- class roboto.experimental.video.NalUnit#
One NAL unit split out of an Annex B-framed H.264 frame.
- data: bytes#
header byte included, start code excluded.
- Type:
The unit’s bytes
- type: int#
nal_unit_typefrom the unit’s header byte.
- class roboto.experimental.video.NalUnitType#
Bases:
enum.IntEnumH.264 NAL unit types (ITU-T H.264 table 7-1) relevant to this module.
NAL headers can carry any 5-bit type value, so
NalUnit.typeis a plainint; compare against these members for the types that matter here.- IDR_SLICE = 5#
- NON_IDR_SLICE = 1#
- PICTURE_PARAMETER_SET = 8#
- SEI = 6#
- SEQUENCE_PARAMETER_SET = 7#
- roboto.experimental.video.decode_frames_in_range(load_messages, start_time, end_time, keyframe_lookback_ns=DEFAULT_KEYFRAME_LOOKBACK_NS)#
Decode the H.264 video frames of a time range.
Frames in the range that are undecodable — e.g. delta frames whose keyframe lies further back than
keyframe_lookback_ns— are silently omitted; no player could render them either.- Parameters:
load_messages (MessageRangeLoader) – Loads the topic’s
(log_time, data)messages for a time range; called once for the requested range and, when the range starts mid-GOP, once more for the keyframe lookback before it.start_time (int) – Start of the range in nanoseconds since Unix epoch (inclusive).
end_time (int) – End of the range in nanoseconds since Unix epoch; passed through to
load_messages.keyframe_lookback_ns (int) – Upper bound on how far before
start_timeto search for the keyframe that anchors the range’s leading delta frames.
- Yields:
One
DecodedVideoFrameper decodable frame withlog_time >= start_time, in ascending log-time order.- Raises:
ImportError – If PyAV is not installed (
roboto[video]).- Return type:
collections.abc.Generator[roboto.experimental.video.decoder.DecodedVideoFrame, None, None]
Examples
>>> from roboto.experimental.video import decode_frames_in_range >>> frames = decode_frames_in_range( ... load_messages=my_loader, start_time=start_ns, end_time=end_ns ... ) >>> next(frames).to_image()
- roboto.experimental.video.decode_h264_stream(encoded_frames)#
Decode an in-order stream of Annex B-framed H.264 frames.
Frames before the first keyframe are skipped — without the preceding GOP state no decoder can render them. Individually corrupt frames are likewise skipped (with a warning) and decoding resumes at the next decodable frame. A fresh decoder session is created per call; concatenating unrelated streams into one call is only valid if each starts with a keyframe.
- Parameters:
encoded_frames (collections.abc.Iterable[tuple[int, bytes]]) –
(log_time, data)pairs in ascending log-time order, wheredatais one Annex B-framed H.264 frame.- Yields:
One
DecodedVideoFrameper decodable input frame, carrying the source message’s log time.- Raises:
ImportError – If PyAV is not installed (
roboto[video]).- Return type:
collections.abc.Generator[DecodedVideoFrame, None, None]
Examples
>>> from roboto.experimental.video import decode_h264_stream >>> for frame in decode_h264_stream(encoded_frames): ... frame.to_image().save(f"frame-{frame.log_time}.jpeg")
- roboto.experimental.video.find_nal_units(data)#
Split Annex B-framed H.264 data into its NAL units.
- Parameters:
data (bytes) – One frame’s Annex B-framed bytes, using 3-byte or 4-byte start codes.
- Returns:
The frame’s NAL units in bitstream order. Each unit’s
datais a copy of the unit’s bytes (header included, start code excluded).- Return type:
list[NalUnit]
Examples
>>> from roboto.experimental.video import NalUnitType, find_nal_units >>> units = find_nal_units(annex_b_frame_bytes) >>> [unit.type for unit in units] [7, 8, 5]
- roboto.experimental.video.is_keyframe(data)#
Whether the Annex B-framed H.264 frame contains an IDR slice.
An IDR slice is a clean decoder entry point: decoding may start at this frame without any earlier GOP state. Frames without one are delta frames, decodable only after the preceding keyframe has been fed to the decoder.
- Parameters:
data (bytes) – One frame’s Annex B-framed bytes.
- Returns:
True when the frame contains an IDR slice.
- Return type:
bool