Skip to content
Roboto
Esc
↑↓navigate↵open⌘Jpreview
On this page

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

roboto.experimental.video.AV1#View Source

DEFAULT_KEYFRAME_LOOKBACK_NS

roboto.experimental.video.DEFAULT_KEYFRAME_LOOKBACK_NS: int = 10000000000#View Source

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

class roboto.experimental.video.DecodedVideoFrame(log_time, frame)#View Source

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

Properties

DecodedVideoFrame.height

height int #

Frame height in pixels.

Return type: int

DecodedVideoFrame.is_keyframe

is_keyframe bool #

Whether this frame is a keyframe (clean decoder entry point).

Return type: bool

DecodedVideoFrame.log_time

log_time int #

Log time (nanoseconds since Unix epoch) of the message this frame came from.

Return type: int

DecodedVideoFrame.to_image()

to_image()#View Source

Convert the frame to a PIL RGB image.

Returns

PIL.Image.Image

The frame’s pixels as a PIL.Image.Image in RGB mode.

Raises

ImportError

If Pillow is not installed (roboto[video]).

DecodedVideoFrame.to_ndarray()

to_ndarray()#View Source

Convert the frame to an (height, width, 3) uint8 RGB array.

Returns

numpy.ndarray

The frame’s pixels as a numpy array in RGB channel order.

Raises

ImportError

If numpy is not installed (roboto[video]).

Properties

DecodedVideoFrame.width

width int #

Frame width in pixels.

Return type: int

H264

roboto.experimental.video.H264#View Source

H265

roboto.experimental.video.H265#View Source

MessageRangeLoader

roboto.experimental.video.MessageRangeLoader#View Source

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

class roboto.experimental.video.NalUnit#View Source

One NAL unit split out of Annex B-framed data.

Attributes

NalUnit.data

data bytes #

The unit’s bytes: header included, start code excluded.

NalUnit.type

type int #

nal_unit_type from the unit’s header (codec-specific layout).

NalUnitType

class roboto.experimental.video.NalUnitType#View Source

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.

Attributes

NalUnitType.IDR_SLICE

IDR_SLICE = 5 #

NalUnitType.NON_IDR_SLICE

NON_IDR_SLICE = 1 #

NalUnitType.PICTURE_PARAMETER_SET

PICTURE_PARAMETER_SET = 8 #

NalUnitType.SEI

SEI = 6 #

NalUnitType.SEQUENCE_PARAMETER_SET

SEQUENCE_PARAMETER_SET = 7 #

VP9

roboto.experimental.video.VP9#View Source

VideoCodec

class roboto.experimental.video.VideoCodec#View Source

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

decoder_thread_count int | None = None #

Fixed thread_count for the decoder context, or None for FFmpeg’s default.

VideoCodec.formats

formats frozenset[str] #

Per-message format tokens that resolve to this codec (compared lowercase).

VideoCodec.is_keyframe

is_keyframe collections.abc.Callable[[bytes], bool] #

Whether an encoded frame is an independently decodable keyframe (clean entry point).

VideoCodec.name

name str #

Canonical codec name (matches the per-message format field, lowercase).

VideoCodec.pyav_codec_name

pyav_codec_name str #

Decoder name passed to PyAV’s CodecContext.create.

decode_frames_in_range()

roboto.experimental.video.decode_frames_in_range(load_messages, start_time, end_time, keyframe_lookback_ns=DEFAULT_KEYFRAME_LOOKBACK_NS, codec=H264)#View Source

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 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_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

ImportError

If PyAV is not installed (roboto[video]).

Return type

collections.abc.Generator[roboto.experimental.video.decoder.DecodedVideoFrame, None, None]

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()

roboto.experimental.video.decode_h264_stream(encoded_frames)#View Source

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.abc.Iterable[tuple[int, bytes]]

(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

ImportError

If PyAV is not installed (roboto[video]).

Return type

collections.abc.Generator[DecodedVideoFrame, None, None]

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()

roboto.experimental.video.decode_stream(encoded_frames, codec)#View Source

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.abc.Iterable[tuple[int, bytes]]

(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

ImportError

If PyAV is not installed (roboto[video]).

Return type

collections.abc.Generator[DecodedVideoFrame, None, None]

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()

roboto.experimental.video.find_nal_units(data)#View Source

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 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()

roboto.experimental.video.is_keyframe(data)#View Source

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

bool

True when the frame contains an IDR slice.

resolve_codec()

roboto.experimental.video.resolve_codec(format)#View Source

Return the codec registered for a per-message format token.

Parameters

format str

The per-message format field of a compressed-video message (e.g. "h264"); matched case-insensitively.

Returns

VideoCodec | None

The matching VideoCodec, or None when no registered codec claims the token (the stream carries a codec with no decode path).

supported_formats()

roboto.experimental.video.supported_formats()#View Source

The per-message format tokens that have a decode path, lowercase.

Return type

frozenset[str]

Was this page helpful?