Skip to main content

Module encode

Module encode 

Source
Expand description

VideoEncoder trait + OutputFormat enum + per-OS GStreamer pipeline builders (M-EXPORT.1 of M-RECORD-EXPORT; live variant M-QUAL.1).

LiveGstreamerEncoder (M-QUAL.1) is the VideoEncoder impl — streaming: it spawns the encode pipeline up front and streams BGRA frames into its stdin, so only compressed video lands on disk during capture. Bounding the on-disk footprint to the encoded bitrate (raw BGRA is w × h × 4 × fps — >1 GB/s at Retina) is the prerequisite for native-resolution capture.

The encoder doesn't link `gstreamer-rs` — it streams over the
child's stdin (`fdsrc fd=0`) rather than via `appsrc`, keeping the
project's "CLI-pipe over Rust bindings" convention (no compile-time
libgstreamer dep, no Windows-build breakage). A programmatic
`appsrc` pipeline remains a possible future swap behind the trait.

§Per-OS encoder coverage

OSH.264H.265VP9 (WebM)AV1
macOSvtenc_h264_hwvtenc_h265_hwvp9enc (sw)vtenc_av1_hw (M3+) → svtav1enc
Windowsmfh264encmfhevcencmfvp9encqsvav1enc
Linuxvaapih264encvaapih265encvaapivp9encvaapiav1enc

macOS is the hot path for M-RECORD-EXPORT; Win/Linux encoder strings are present so the cross-OS build + the arg-builder unit tests pass, but the runtime spawn returns EncodeError::Unsupported outside macOS until those ports land.

Structs§

EncoderConfig
Encoder configuration. Width + height + framerate are the video caps; output_path is the final container path the encoder writes to on finalize.
LiveGstreamerEncoder
Live (streaming) video encoder. Spawns the encode pipeline up front and streams BGRA frames into its stdin, so the only video on disk during capture is already compressed. That bounds the scratch footprint to the encoded bitrate instead of the raw firehose (width × height × 4 × fps ≈ 250 MB/s at 1080p, >1 GB/s at Retina) — the prerequisite for capturing at native resolution.

Enums§

EncodeError
Failure modes for the encoder.
OutputFormat
Output container + codec selection. Carries the (format → codec → muxer → file extension) tuple as one type so the rest of the pipeline can switch on a single value.

Constants§

RECORDING_MAX_LONG_EDGE
Longer-edge bound of the recording resolution cap (the “1080p” cap).
RECORDING_MAX_SHORT_EDGE
Shorter-edge bound of the recording resolution cap.

Traits§

VideoEncoder
Encoder trait — the seam M-EXPORT.3 hooks the per-channel capture callbacks into. Pure-sync interface; the LiveGstreamerEncoder impl streams each pushed frame into a gst-launch-1.0 child and remuxes in the audio at finalize.

Functions§

audio_encoder_element 🔒
Audio encoder element for the container family.
build_audio_decode_args
Build the gst-launch-1.0 argv that decodes source’s audio track to raw interleaved F32LE on stdout at sample_rate / channels (ED.21).
build_live_video_args
Build the gst-launch-1.0 argv for the live video-only encode (M-QUAL.1). Frames arrive on the child’s stdin (fd=0) as raw BGRA; the pipeline encodes them straight to a compressed video-only container at intermediate. The audio leg is handled separately at finalize (build_remux_args).
build_remux_args
Build the gst-launch-1.0 argv for the finalize remux (M-QUAL.1). The live video intermediate is stream-copied (no re-encode) and the raw F32LE audio_scratch is encoded to the container’s audio codec, both muxed into config.output_path.
build_webm_transcode_args
Build the gst-launch argv for the MP4 → WebM transcode. Split out so tests assert the pipeline shape without spawning gst. The Opus audio leg is present only when has_audio (see transcode_to_webm for why).
cap_recording_dims
Cap capture/encode dims to a 1080p box (1920×1080), aspect-preserving and orientation-agnostic: the longer edge is bounded to RECORDING_MAX_LONG_EDGE and the shorter to RECORDING_MAX_SHORT_EDGE, both edges scaled by the same factor (never stretched — the camera bubble stays circular) and rounded down to even (H.264 chroma subsampling). Dims already inside the box are returned unchanged (never upscaled), only evened. Integer arithmetic throughout.
decode_source_audio_f32
Decode source’s audio track to interleaved F32LE samples at sample_rate / channels (ED.21). Returns an empty Vec when the source has no audio track (probed via scratch_has_audio) — the caller then exports video-only.
demux_for 🔒
Demuxer element that reads the live video intermediate back for the finalize remux.
encoder_and_mux_elements 🔒
Per-(format, OS) video encoder element(s) + muxer element, used by build_live_video_args so the encoder coverage table lives in one place.
fit_within_encoder_limits
Clamp (width, height) so neither edge exceeds format’s hardware encoder limit (OutputFormat::max_encode_edge), preserving the aspect ratio and keeping both edges even (H.264 / HEVC require mod-2 dimensions).
generate_poster
Generate an AVIF poster image next to the encoded video. Spawns a one-shot gst-launch-1.0 pipeline that extracts a single frame from video_path, scales it to ≤640 px wide, and writes it to <video_path-without-ext>.avif.
leak_os_name 🔒
Convert a runtime OS string (std::env::consts::OS produces &str) to a &'static str suitable for the EncodeError::Unsupported field. The set of possible values is bounded so we map each known one explicitly; anything else falls through to "other".
mux_element_for 🔒
Muxer element for the container family (OS-independent).
mux_to_parser 🔒
poster_path_for
Compute the poster path for <video>.<ext><video>.avif. Replaces the video extension entirely (so Screen-...mp4Screen-...avif, not Screen-...mp4.avif).
poster_pipeline_args
Build the gst-launch argv for the poster pipeline. Split out so tests can assert the shape without spawning gst.
scratch_has_audio
Probe input for an audio track via gst-discoverer-1.0. Returns true only when an audio stream is reported; any failure (binary missing, probe error, no audio) returns false, so the transcode falls back to a video-only pipeline rather than hang on a decodebin audio pad that never fires.
scratch_path 🔒
transcode_to_webm
Transcode an existing video file (the MP4/H.264 recording scratch) into a VP9 + Opus .webm at output. Drives the Save panel’s “WebM” export: the recorder always captures to an MP4/H.264 scratch (the canonical intermediate), and a WebM export re-encodes it here.