roboto.experimental.video
Video APIs in active refinement; see roboto.experimental for the stability contract.
Decodes compressed-video topic data (one encoded frame per MCAP message, as written by Roboto ingestion for CompressedVideo and compatible schemas) into still frames on demand. Supported codecs are enumerated by supported_formats() (H.264, H.265, VP9, and AV1 today). Decoding requires the roboto[video] extra; the per-codec bitstream-inspection helpers (h264, h265, vp9, av1) are dependency-free.
Submodules
Package Contents
AV1
DEFAULT_KEYFRAME_LOOKBACK_NS
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.
DecodedVideoFrame
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 intframe av.Properties
DecodedVideoFrame.is_keyframe
Whether this frame is a keyframe (clean decoder entry point).
DecodedVideoFrame.log_time
Log time (nanoseconds since Unix epoch) of the message this frame came from.
DecodedVideoFrame.to_image()
Convert the frame to a PIL RGB image.
Returns
The frame’s pixels as a PIL.Image.Image in RGB mode.
Raises
ImportErrorIf Pillow is not installed (roboto[video]).
DecodedVideoFrame.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
ImportErrorIf numpy is not installed (roboto[video]).
Properties
H264
H265
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_time is inclusive follows the underlying reader — frame emission is bounded by log-time filtering, not by the loader’s boundary semantics.
NalUnit
NalUnitType
Bases: enum.IntEnum
H.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.type is a plain int; compare against these members for the types that matter here.
VP9
VideoCodec
The per-codec hooks the generic stream decoder depends on.
A codec is data plus one function: the PyAV decoder name and a predicate that recognizes an independently decodable keyframe from an encoded frame’s bytes. Everything else about decoding (GOP skipping, log-time remapping, error recovery) is codec-agnostic and lives in the decoder.
Attributes
VideoCodec.decoder_thread_count
Fixed thread_count for the decoder context, or None for FFmpeg’s default.
VideoCodec.formats
Per-message format tokens that resolve to this codec (compared lowercase).
VideoCodec.is_keyframe
Whether an encoded frame is an independently decodable keyframe (clean entry point).
decode_frames_in_range()
Decode the compressed-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 MessageRangeLoaderLoads 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 intStart of the range in nanoseconds since Unix epoch (inclusive).
end_time intEnd of the range in nanoseconds since Unix epoch; passed through to load_messages.
keyframe_lookback_ns intUpper bound on how far before start_time to search for the keyframe that anchors the range’s leading delta frames.
The codec of every loaded frame (defaults to H.264); supplies keyframe detection and the PyAV decoder. Resolve it from the stream’s format token via resolve_codec().
Yields
One DecodedVideoFrame per decodable frame with log_time >= start_time, in ascending log-time order.
Raises
ImportErrorIf PyAV is not installed (roboto[video]).
Return type
Usage
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()decode_h264_stream()
Decode an in-order stream of Annex B-framed H.264 frames.
Thin wrapper over decode_stream() bound to the H.264 codec; see it for the GOP, corruption-recovery, and log-time-mapping semantics.
Parameters
encoded_frames collections.(log_time, data) pairs in ascending log-time order, where data is one Annex B-framed H.264 frame.
Yields
One DecodedVideoFrame per decodable input frame, carrying the source message’s log time.
Raises
ImportErrorIf PyAV is not installed (roboto[video]).
Return type
Usage
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")decode_stream()
Decode an in-order stream of encoded frames of a single codec.
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.(log_time, data) pairs in ascending log-time order, where data is one encoded frame in codec’s bitstream format.
The codec of every frame in encoded_frames; supplies the PyAV decoder name and the keyframe predicate.
Yields
One DecodedVideoFrame per decodable input frame, carrying the source message’s log time.
Raises
ImportErrorIf PyAV is not installed (roboto[video]).
Return type
Usage
from roboto.experimental.video.codec import H264
from roboto.experimental.video import decode_stream
for frame in decode_stream(encoded_frames, H264):
frame.to_image().save(f"frame-{frame.log_time}.jpeg")find_nal_units()
Split Annex B-framed H.264 data into its NAL units.
Parameters
data bytesOne 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 data is a copy of the unit’s bytes (header included, start code excluded).
Usage
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]is_keyframe()
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 bytesOne frame’s Annex B-framed bytes.
Returns
True when the frame contains an IDR slice.
resolve_codec()
Return the codec registered for a per-message format token.
Parameters
format strThe per-message format field of a compressed-video message (e.g. "h264"); matched case-insensitively.
Returns
The matching VideoCodec, or None when no registered codec claims the token (the stream carries a codec with no decode path).
supported_formats()
The per-message format tokens that have a decode path, lowercase.
Return type