VideoStream#
- class nominal.experimental.video.VideoStream(rid: str, src: Src, options: StreamOptions | None)#
Bases:
objectA live video stream from any source to a video channel on a Nominal dataset via WHIP.
Use
VideoStream.create()to construct — it resolves the WHIP endpoint from the Nominal video and prepares the pipeline configuration. The pipeline itself is not started untilopen()is called (or the context manager is entered).Requires
pip install 'nominal[video]'and GStreamer 1.20+ on your system.Example
from nominal.experimental.video import VideoStream, Src, StreamOptions dataset = client.create_dataset("my stream") # Context manager — open/close handled automatically: with VideoStream.create(dataset, Src.camera(), channel="camera/front") as stream: stream.run() # Timed stream — run for a fixed timeout then exit: with VideoStream.create(video, Src.udp_rtp(5000)) as stream: stream.run(timedelta(seconds=30)) # Manual lifecycle — useful when you need the stream object outside a with block, # or to restart after a NominalVideoStreamError (e.g. source disconnected): stream = VideoStream.create(video, Src.rtsp("rtsp://192.168.1.10/live")) stream.open() try: stream.run() except NominalVideoStreamError: stream.restart() # re-opens the pipeline with the same WHIP endpoint stream.run() finally: stream.close() # Push frames manually from your own source. # frame_bytes must be raw RGB bytes: width * height * 3 bytes per frame. # Use Src.app(width, height, format=ImageFormat.Bgr) if your source is BGR (e.g. OpenCV). with VideoStream.create(video, Src.app(1280, 720)) as stream: while capturing: frame_bytes: bytes = capture_rgb_frame() # 1280 * 720 * 3 bytes stream.send_frame(frame_bytes, timestamp_ns=time.time_ns())
- options: StreamOptions | None#
- close() None#
Stop the pipeline and release all resources. Idempotent — safe to call multiple times.
After close(), open() can be called again to restart with the same WHIP endpoint.
- classmethod create(target: Dataset | Video, src: Src, options: StreamOptions | None = None, *, channel: str | None = None, tags: Mapping[str, str] | None = None) VideoStream#
Create a VideoStream for a video channel on a dataset.
Resolves the WHIP endpoint from Nominal and configures the pipeline. The pipeline is not started until
open()is called.- Parameters:
target – The dataset owning the video channel to stream to. Passing a legacy standalone
Videois deprecated.src – Video source. Common options:
Src.camera()— local webcamSrc.rtsp("rtsp://...")— RTSP streamSrc.udp_rtp(port)— incoming RTP over UDPSrc.udp_mpegts(port)— incoming MPEG-TS over UDPSrc.file("path/to/video.mp4")— video fileSrc.app(width, height)— push frames manually via send_frame()
options – Encoding options — codec, bitrate, resolution, overlay, fps, etc. Defaults to H264 at 4 Mbps with no overlay.
channel – Name of the video channel on the dataset to stream to. Required when streaming to a dataset; unused when streaming to a legacy
Video.tags – Tags identifying the channel’s series. Defaults to none.
- Returns:
A configured VideoStream, ready to open.
- Raises:
ValueError –
channelwas omitted for a dataset target, or supplied for aVideotarget.NominalVideoStreamError – Nominal rejected the request for a WHIP endpoint.
- open() None#
Build and start the GStreamer pipeline. Idempotent — safe to call multiple times.
- Raises:
NominalVideoStreamError – if the pipeline fails to start (e.g. device not found, bad source URL).
- restart() None#
Stop and restart the pipeline.
Useful for recovering from errors or reconnecting after a source interruption. Reuses the same WHIP endpoint resolved at create() time.
- run(timeout: timedelta | float | None = None) None#
Block until the stream ends, errors, or Ctrl+C is pressed.
Calls close() internally when done, so no explicit cleanup is needed after run().
- Parameters:
timeout – How long to stream before stopping — either a timedelta or a number of seconds. If None, runs until the source ends naturally (e.g. end of file) or until interrupted with Ctrl+C.
- Raises:
NominalVideoStreamNotOpenError – if the stream is not open — call open() first or use as a context manager.
NominalVideoStreamError – if the pipeline encounters an unrecoverable error.
- send_frame(data: bytes, timestamp_ns: int | None = None) bool#
Push a raw video frame into the pipeline. Only valid when using
Src.app().- Parameters:
data – Raw frame bytes. Format must match the format passed to
Src.app()(default is RGB — width * height * 3 bytes).timestamp_ns – Absolute timestamp in nanoseconds (Unix epoch). If None, the pipeline assigns a timestamp automatically.
- Returns:
True if the frame was accepted, False if the internal buffer is full.
- Raises:
NominalVideoStreamNotOpenError – if the stream is not open.