NURLNURL registrynurl-lang.org →

← video

video 0.2.5 API

main.nu

packages/video/src/main.nu — the video CLI.

video frames <file> [--fps n] [--out dir] [--quiet] video probe <file.avi>

frames extracts JPEG frames from a video — MJPEG AVI in pure NURL, anything else through ffmpeg when it is installed. probe opens an AVI and reports what the extractor would see: the frame rate, the video stream, where the movi payload sits.

API

@ main → i


video.nu

packages/video/src/video.nu — a video file, as frames on disk.

( vid_extract path fps outdir verbose ) → !i String frames kept

A vision tool wants ordered frames; a video is the natural way to shoot them. This extracts JPEG frames, numbered 000000.jpg on, into a directory of the caller's choosing — vid_frames_dir names the <video>_frames/ convention next to the file — and a directory pipeline takes it from there.

Two extraction paths:

MJPEG in AVI — parsed HERE, in pure NURL. An AVI is a RIFF tree and an MJPEG frame chunk is a complete JPEG, which packages/image already decodes; extraction is finding the '..dc' chunks of the video stream and writing their bytes to files. Cameras, OBS and ffmpeg can all record MJPEG.

Everything else (H.264 in MP4, HEVC, VP9, ...) — delegated to ffmpeg when it is on PATH. A from-scratch H.264 decoder is not this package's fight. When ffmpeg is absent the error says exactly what to install or how to record instead.

The sampling stride is computed from the stream's own frame rate: keep every round(src_fps / target_fps)-th frame, floor 1.

( vid_is_video path ) → b the extension is a video's ( vid_frames_dir path ) → String <dir>/<stem>frames ( vidavi_open path ) → !VidAvi String ( vid_avi_fps_num v ) ( vid_avi_fps_den v ) ( vid_avi_vstream v ) ( vid_avi_movi_off v ) ( vid_avi_movi_end v ) → i stream metadata ( vid_avi_extract v outdir stride ) → !i String ( vid_avi_close v ) → v early release (optional) ( vid_extract path fps outdir verbose ) → !i String

A VidAvi is a handle: every copy is the same open file, and the last owner closes it. Nothing here is released by hand.

API

@ vid_is_video s path → b

A positional argument with one of these extensions is a video, the way a directory is a frames directory.

@ vid_frames_dir s path → String

<dir>/<stem>_frames — the conventional place: next to the video, named after it, so what a run leaves behind is self-explaining.

: VidAviImpl

: VidAviImpl {
    File f  // closed by its last owner (the drop glue), as vid_avi_close did
    i fsize
    i fps_num  // dwRate of the vids stream
    i fps_den  // dwScale
    i vstream  // index of the vids stream, for the 'NNdc' fourcc
    i movi_off  // where the movi LIST's payload starts
    i movi_end
}

: VidAvi { ( Locked VidAviImpl ) st }

An opened AVI is a handle on its state in a Locked (stdlib/std/thread.nu): every copy is the same open file, the last owner closes it, and a read checks the state out (locked_take) — copies on several threads take turns at the file position. vid_avi_close is an optional early release.

@ VidAvi_share VidAvi h → VidAvi

@ VidAvi_drop sink VidAvi h → v

@ vid_avi_fps_num VidAvi h → i

The stream's declared frame rate, fps_num / fps_den (dwRate / dwScale).

@ vid_avi_fps_den VidAvi h → i

@ vid_avi_vstream VidAvi h → i

Index of the video stream (the NN of its 'NNdc' chunks).

@ vid_avi_movi_off VidAvi h → i

The movi LIST's payload: [movi_off, movi_end) in the file.

@ vid_avi_movi_end VidAvi h → i

@ vid_avi_open s path → !VidAvi String

Walk the RIFF tree far enough to know the frame rate, which stream is the video, and where the movi payload lives. Everything else in the file is somebody else's business.

@ vid_avi_close sink VidAvi v → v

Let go of v now rather than at the end of its owner's scope; the last owner's drop closes the file.

@ vid_avi_extract VidAvi v__h s outdir i stride → !i String

Extract every stride-th video frame as a JPEG file into outdir, stopping the numbering at what was kept. Returns the kept count.

@ vid_extract s path i fps s outdir i verbose → !i String

Extract path at ~fps frames per second into its _frames dir. Returns the directory; the caller feeds it to the ordinary frames pipeline. verbose gates the progress line.