oxideav-source 0.1.5

Generic source registry: opens URIs (file://, plus http:// via oxideav-http) into Read+Seek; prefetch buffer wrapper
Documentation

oxideav-source

Generic source registry: opens URIs into Read + Seek byte streams, with bundled drivers and a prefetching BufferedSource wrapper.

The registry returns SourceOutput — one of Bytes (file / mem / http here), Packets, or Frames — so transport-layer or generator sources slot into the same opener API.

Bundled schemes

Scheme Driver Notes
file://<path> and bare paths open_file unscoped — every readable path resolves
file://<path> (scoped) FileScope + open_file_scoped restricts opens to a canonicalised directory allow-list; blocks .. traversals through symlinks
mem://<id> open_mem in-memory buffer registered via oxideav_source::mem::put(id, bytes); useful for tests and synthetic sources
data:[<mediatype>][;base64],<bytes> open_data RFC 2397 inline byte literals; payload decoded directly from the URI (no filesystem access). Percent-decoded by default; base64 when ;base64 is present.
concat:<a>|<b>|… open_concat |-separated segments presented as one seekable byte stream; reads walk segment boundaries, Seek resolves an absolute offset into the right segment. Each segment may be a bare path, file://, mem://, data:, or slice: URI (same set the slice: driver accepts as inner). Nested concat: segments rejected (the outer | split would shred them); empty segments rejected.
slice:<offset>+<length>!<inner-uri> open_slice URI-level windowed view: [offset, offset + length) of <inner-uri> mapped onto [0, length). The inner URI may be a file:// / bare path, mem://, data:, or another slice: (recursive composition). Equivalent to constructing a SubSource programmatically, but expressible as a single URI string for CLI flags and config files.
http://, https:// provided by oxideav-http registered separately by that crate

with_defaults() pre-populates a registry with the file, mem, data, concat, and slice drivers (the file opener in its unscoped form). For server-side use, build an empty registry and install a FileScope instead:

use oxideav_source::{FileScope, SourceRegistry};

let mut reg = SourceRegistry::new();
FileScope::new()
    .allow_dir("/var/media")
    .allow_dir("/srv/uploads")
    .register_into(&mut reg);
// reg.open("file:///etc/passwd") now errors instead of leaking.

BufferedSource

BufferedSource wraps any Box<dyn ReadSeek> (HTTP, file, mem) with a worker-thread prefetch ring. Backwards seeks inside the ring window are handled without re-reading the inner source; seeks past the ring restart prefetch at the new position.

BufferedSource::new(inner, capacity) keeps the historical two-argument shape with default tunables. For finer control — non-default prefetch timeout, custom worker block size, or a different lookback fraction — use BufferedSource::builder():

use std::time::Duration;
use oxideav_source::BufferedSource;
# fn make_inner() -> Box<dyn oxideav_core::ReadSeek> { unimplemented!() }
let inner = make_inner();
let buf = BufferedSource::builder()
    .capacity(4 * 1024 * 1024)            // 4 MiB ring
    .block_size(64 * 1024)                // 64 KiB worker syscalls
    .prefetch_timeout(Duration::from_secs(5))
    .lookback_fraction(1, 4)              // 25 % back-cache
    .build(inner)
    .unwrap();
# let _ = buf;

Defaults are 1 MiB capacity, 256 KiB block size, 30 s prefetch timeout, 1/8 lookback. Builder values are clamped on build so the worker is always able to make forward progress (capacity ≥ 4 × block, block ≥ 4 KiB, timeout ≥ 1 ms, lookback strictly less than 1).

SubSource — windowed view

SubSource re-projects a slice [base, base + len) of an inner BytesSource onto [0, len) so containers can hand a codec a stream that looks like the codec's own sample. This is the seekable analogue of std::io::Read::take: take only caps forward reads, but a codec that needs to seek backwards within its window — e.g. to re-read a header it just probed — needs a real windowed seek too. The [stream_len] helper probes a source's total length non-destructively (useful at SubSource::new-time and anywhere else a length probe is needed without disturbing the cursor).

use oxideav_source::{with_defaults, SourceOutput, SubSource};

let reg = with_defaults();
let inner = match reg.open("/some/container.mp4").unwrap() {
    SourceOutput::Bytes(b) => b,
    _ => panic!("expected Bytes"),
};
// Hand the codec just the mdat sample at offset 4_321_000, length 34_112.
let mut sample = SubSource::new(inner, 4_321_000, 34_112).unwrap();
// `sample` now behaves like a `Read + Seek` source over [0, 34_112).
# let _ = &mut sample;

Status

Part of the oxideav framework — a pure-Rust media transcoding and streaming stack. Codec, container, and filter crates are implemented from the spec (no C codec libraries linked or wrapped, no *-sys crates). Optional hardware-engine crates (oxideav-videotoolbox / -audiotoolbox / -vaapi / -vdpau / -nvidia / -vulkan-video) bridge to OS APIs via runtime libloading; pass --no-hwaccel (or omit the hwaccel feature) to opt out.

Usage

[dependencies]
oxideav-source = "0.1"

License

MIT — see LICENSE.