libvideo provides frame-based pixel processing helpers for Magnolia.
It is designed for lightweight video-style pipelines where each frame is represented as:
{
width: <int>
height: <int>
channels: <int>
pixels: [byte...]
}
Pixels are row-major and interleaved by channel.
video := import('video')
Creates a frame object. Defaults:
channels = 3pixels =zero-filled byte buffer
Creates a solid-color frame filled with a single byte value.
Clones frame metadata and pixel data.
Returns the flat index into frame.pixels.
Reads one pixel and returns channel values as a list.
Returns a new frame with one pixel overwritten.
Transforms all pixels with mapper(pixel, x, y).
Converts RGB/RGBA to grayscale using luma weighting while preserving frame shape.
Inverts channels against maxValue (default 255).
Converts to black/white via luma threshold (t, default 127).
Converts one RGB pixel to [y, u, v].
Converts one YUV pixel to [r, g, b].
Extracts a clamped rectangle from a frame.
Resizes with nearest-neighbor sampling.
Blends two frames with alpha in [0, 1]. Uses overlapping top-left region if dimensions differ.
Computes per-channel absolute difference.
Maps frame sequences with f(frame, index).
Returns nearest frame for a timestamp (fps default 30).
video := import('video')
base := video.blank(320, 180, 3, 32)
overlay := video.blank(320, 180, 3, 200)
mixed := video.blend(base, overlay, 0.25)
grayscale := video.toGrayscale(mixed)
small := video.resizeNearest(grayscale, 160, 90)
edge := video.frameDiff(grayscale, mixed)
frameAtTime := video.sampleFrame([base, mixed, grayscale], 0.08, 30)
Applies mapper(pixel, x, y) in parallel using bounded concurrency. Each row is processed as an independent unit of work. numWorkers defaults to 4.
bright := video.pmapPixels(f, fn(px, x, y) [
px.0 + 30, px.1 + 30, px.2 + 30
], 4)
Rescales a frame using nearest-neighbor sampling with parallel row processing.
scaled := video.presizeNearest(f, 1920, 1080, 4)
Applies f(frame, index) over a sequence of frames in parallel.
processed := video.pmapFrames(frames, fn(f, i) video.toGrayscale(f))
- Channel and byte values are clamped where appropriate.
- Most operations return new frames rather than mutating the input.
- The library targets practical frame processing, not codec/container decoding.