---
title: "Examples"
description: "What each example in the streamlib repository shows, what it needs, and how its stream is wired with the current API."
type: "docs-page"
url: "https://tatolab.com/docs/examples"
site: "Tatolab"
section: "Examples"
---

# Examples

> What each example in the streamlib repository shows, what it needs, and how its stream is wired with the current API.

The [streamlib repository](https://github.com/tatolab/streamlib/tree/main/examples) has a dozen examples, each a small project that does one thing well: a codec round trip, a recorder, a GPU halftone, an object detector, a reverb.

> **Caution: Written for the previous API**
>
> The examples were written for the previous version of the Python API (`from streamlib import …`, with a `setup(rt)` function in `app.py`), and they're being rewritten for the current one. Until an example is updated, `tatolab run` won't load it as it is. Read it for the technique and the node logic, and use the stream code on this page, which is written for the current API.

## Camera and display

### camera-display

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-display). Your camera in a window: the smallest useful stream.

```txt
CameraSource → DisplayWindow
```

```python title="stream.py"
from tatolab.stream import CameraSource, DisplayWindow, StreamBuilder, stream


@stream
def camera_display(stream_builder: StreamBuilder) -> None:
    """The camera in a window."""
    camera = stream_builder.add(CameraSource, config={"max_width": 1920, "max_height": 1080})
    window = stream_builder.add(
        DisplayWindow, config={"title": "Camera", "width": 1280, "height": 720, "scaling": "fit"}
    )
    stream_builder.connect(camera.output("video"), window.input("video"))
```

**Needs:** a camera. Both nodes are built in, so the project needs nothing but `tatolab-stream`.

### camera-codec-roundtrip

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-codec-roundtrip). The camera after a real hardware encode and decode, so what you see has been through an H.264 (or H.265) bitstream.

```txt
CameraSource → H264Encoder → H264Decoder → DisplayWindow
```

```python title="stream.py"
from tatolab.stream import (
    CameraSource,
    DisplayWindow,
    H264Decoder,
    H264Encoder,
    StreamBuilder,
    stream,
)


@stream
def codec_roundtrip(stream_builder: StreamBuilder) -> None:
    """The camera, encoded to H.264 and decoded again, in a window."""
    camera = stream_builder.add(CameraSource)
    encoder = stream_builder.add(H264Encoder)
    decoder = stream_builder.add(H264Decoder)
    window = stream_builder.add(DisplayWindow, config={"title": "After the round trip"})
    stream_builder.connect(camera.output("video"), encoder.input("video"))
    stream_builder.connect(encoder.output("encoded_video"), decoder.input("encoded_video"))
    stream_builder.connect(decoder.output("video"), window.input("video"))
```

Swap in `H265Encoder` and `H265Decoder` and nothing else changes; the two ends must match. **Shows:** an encoded stream is an ordinary link. **Needs:** a GPU with hardware encode and decode: Vulkan Video on Linux, VideoToolbox on a Mac. Without a decoder, the decoder node fails in `setup()` and the window stays black; without an encoder, the encoder logs one error and drops every frame. See [Record and encode](https://tatolab.com/docs/build/recording).

### camera-compute-kernel and camera-halftone

[camera-compute-kernel](https://github.com/tatolab/streamlib/tree/main/examples/camera-compute-kernel) turns the camera black and white with a compute kernel; [camera-halftone](https://github.com/tatolab/streamlib/tree/main/examples/camera-halftone) turns it into a newsprint dot screen.

```txt
CameraSource → GrayscaleCompute → DisplayWindow
CameraSource → HalftoneCompute → DisplayWindow
```

**Shows:** writing a full compute kernel when a one-function pixel effect isn't enough: compiling GLSL in `setup()` with `ctx.gpu_full_access.create_compute_kernel(...)`, dispatching it in `process()`, push constants for live settings (`strength`, `cell_size`, `dot_boost`), and the halftone's gather pattern, where each pixel reads neighbors it doesn't write. Start with [GPU effects](https://tatolab.com/docs/build/gpu-effects); these examples are the next step.

### camera-python-effects

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-python-effects). A "breaking news" look: glitch and CRT film-grain shaders over the camera, a neon overlay drawn with Skia, and a 3D avatar that follows your pose, all composited into one window.

```txt
CameraSource ─┬─ CameraFrameToTexture → CyberpunkGlitch → CrtFilmGrain ─┐
              └─ CyberpunkAvatar (MediaPipe pose, ModernGL) ─────────────┤
NeonOverlaySource (Skia, every 33 ms) ───────────────────────────────────┴─ BreakingNewsCompositor → DisplayWindow
```

**Shows:** fan-out and fan-in, graphics (fragment) shaders loaded from `.frag` files, a node that composites three inputs at the video's pace, a source that draws on its own timer (`execution="continuous", interval_ms=33`), pose estimation on the CPU over `numpy.from_dlpack(frame, device="cpu")`, and an optional recorder that writes [LeRobot](https://github.com/huggingface/lerobot) dataset episodes. **Needs:** `skia-python`, `mediapipe` and `moderngl` from PyPI; runs on Linux with NVIDIA and on Apple silicon.

### camera-virtual-camera

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-virtual-camera). Two virtual cameras that any other app can open, one plain and one inverted. Linux only.

```txt
CameraSource ─┬─ VirtualCameraSink ("StreamLib Camera")
              └─ InvertingEffect → VirtualCameraSink ("StreamLib Camera Inverted")
```

**Shows:** presenting a stream as a camera for Zoom, OBS or a browser, and why an effect that sits next to other readers of the same frame must write its own output frame rather than editing the shared one. See [Virtual camera](https://tatolab.com/docs/build/virtual-camera).

## Recording and publishing

### camera-audio-recorder

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-audio-recorder). The camera and the microphone recorded into one MP4 file, with a live preview.

```txt
CameraSource ─┬─ H264Encoder ─┐
              └─ DisplayWindow ├─ Mp4Sink (recording.mp4)
MicrophoneSource → OpusEncoder ┘
```

```python title="stream.py"
from pathlib import Path

from tatolab.stream import (
    CameraSource,
    DisplayWindow,
    H264Encoder,
    MicrophoneSource,
    Mp4Sink,
    OpusEncoder,
    StreamBuilder,
    stream,
)

RECORDING = Path(__file__).resolve().parent / "recording.mp4"


@stream
def recorder(stream_builder: StreamBuilder) -> None:
    """Camera and microphone into one MP4, with a preview window."""
    camera = stream_builder.add(CameraSource)
    video_encoder = stream_builder.add(H264Encoder)
    microphone = stream_builder.add(MicrophoneSource)
    audio_encoder = stream_builder.add(OpusEncoder)
    recording = stream_builder.add(Mp4Sink, config={"path": str(RECORDING)})
    preview = stream_builder.add(DisplayWindow, config={"title": "Recording"})

    stream_builder.connect(camera.output("video"), video_encoder.input("video"))
    stream_builder.connect(camera.output("video"), preview.input("video"))
    stream_builder.connect(video_encoder.output("encoded_video"), recording.input("tracks"))
    stream_builder.connect(microphone.output("audio"), audio_encoder.input("audio"))
    stream_builder.connect(audio_encoder.output("encoded_audio"), recording.input("tracks"))
```

**Shows:** each link into `Mp4Sink`'s `tracks` input becomes one track, with its kind (video or audio) taken from what arrives. `OpusEncoder` converts the microphone's sample rate and framing for you. **Needs:** a camera, a microphone, and hardware H.264 encode. See [Record and encode](https://tatolab.com/docs/build/recording).

### camera-webrtc-publish

[Source](https://github.com/tatolab/streamlib/tree/main/examples/camera-webrtc-publish). The camera and microphone published to a WHIP endpoint, such as Cloudflare Stream, as one WebRTC session.

```txt
CameraSource → H264Encoder ──┐
MicrophoneSource → OpusEncoder ┴─ WhipPublisher
```

**Shows:** a node from a package (`WhipPublisher`, from `tatolab-webrtc`) used exactly like your own, and treating a URL that contains a stream key as a secret. See [WebRTC](https://tatolab.com/docs/build/webrtc) for the current-API stream.

## Models

### fisheye-object-detection

[Source](https://github.com/tatolab/streamlib/tree/main/examples/fisheye-object-detection). The camera through a simulated fisheye lens in one window; in a second, the same picture straightened out, with YOLO's boxes drawn on it.

```txt
CameraSource → SyntheticFisheyeLens ─┬─ DisplayWindow ("LensWindow")
                                     └─ UndistortingObjectDetector → DisplayWindow ("DetectionWindow")
```

**Shows:** a full model-in-the-loop node: a compute kernel that undistorts the frame, `ModelInputTensorKernel` preparing the model's input on the GPU, `torch.from_dlpack` handing it to YOLO with no copy, boxes mapped back to frame coordinates, and detections written into the output bag beside the frame. **Needs:** `torch>=2.10` and `ultralytics`, and a GPU torch can use (CUDA on Linux, `mps` on a Mac). See [Use your model](https://tatolab.com/docs/build/models).

## Audio

### microphone-reverb-speaker

[Source](https://github.com/tatolab/streamlib/tree/main/examples/microphone-reverb-speaker). Your voice through a room reverb, played back live. Wear headphones, or the speaker feeds the microphone.

```txt
MicrophoneSource → ReverbEffect → SpeakerSink
```

**Shows:** an audio window contract (`AudioWindowContract`): the node asks for exactly 128 mono samples at 48 kHz and the runtime converts whatever the microphone opened at. **Needs:** numpy; a microphone and speakers (it runs silently with no audio devices).

### audio-mixer-demo

[Source](https://github.com/tatolab/streamlib/tree/main/examples/audio-mixer-demo). A steady C major chord from three tone generators, mixed and played.

```txt
ToneSource (C4) ─┐
ToneSource (E4) ─┼─ ChordMixer → SpeakerSink
ToneSource (G4) ─┘
```

**Shows:** three sources at three different sample rates and channel counts, converted to one window contract by the runtime, and a mixer that lines blocks up by their timestamps instead of by arrival order. See [Audio](https://tatolab.com/docs/build/audio).

## GPU showcase

### raytracing-showcase

[Source](https://github.com/tatolab/streamlib/tree/main/examples/raytracing-showcase). A split screen: the same scene rasterized on the left ("RTX OFF") and ray traced on the right ("RTX ON").

```txt
RasterizedSceneRenderer ─┐
RayTracedSceneRenderer ──┴─ SplitScreenCompositor → DisplayWindow
```

**Shows:** graphics, ray-tracing and compute kernels in one stream, and two renderers kept in step by the shared clock (`ctx.time`). **Needs:** a GPU with hardware ray tracing (NVIDIA RTX, or AMD RDNA 2 and later) on Linux. Ray tracing isn't available on macOS, and the renderer says so at `setup()`.

## Not yet examples

`jpeg-psnr` and `screen-recorder` are Rust projects kept for reference while their features are redesigned. They aren't meant to be run.
