Terminal sink that hands every buffer (and, optionally, every control
message) to a plain closure instead of requiring a bespoke struct +
Element/Sink impl — the equivalent of GStreamer’s appsink: the
pipeline’s job ends here, and whatever the caller does with the data
(run inference, forward it to a channel, write it out, …) is none of
this crate’s concern.
D3d11RendererWindows and d3d11 and (d3d11 or d3d12 or wasapi-renderer)
D3d12RendererWindows and d3d12 and (d3d11 or d3d12 or wasapi-renderer)
Terminal sink that submits decoded video frames to a caller-supplied
D3d12FrameRenderer. Only built with the d3d12 feature —
every consumer that doesn’t need to render to a window pulls in
neither this nor the windows dependency it needs for the zero-copy
path.
One detected object, in the pixel space of the frame OrtDetector
was handed — see its own doc comment for why no further rescaling is
needed to place this on top of that same frame.
Terminal sink that counts decoded frames (video or audio). Backed by
an Arc<AtomicUsize> so the count can be read from outside the
pipeline even when this sink ends up running on a Queue worker
thread.
Builds one HLS media playlist and returns one Sink per registered
track. FFmpeg owns segment boundary selection, fMP4/MPEG-TS creation,
atomic playlist replacement, live-window trimming, and final
#EXT-X-ENDLIST generation.
Builds an MP4 (or any other container ffmpeg infers from path’s
extension) with one or more tracks, then opens it into one Sink per
track. Two-phase on purpose: a container’s header has to describe
every stream’s codec parameters up front — avformat_write_header
can’t run until every Mp4Muxer::add_stream this file will ever hold
has already happened — so there’s no way to make this a single
long-lived Sink that tracks attach to one at a time as their encoders
come online (contrast crate::elements::AudioMixer, whose inputs
can attach at any time — it has no “known shape before the first
byte” constraint the way a container header does).
One track’s own Sink — a lightweight handle sharing a
Mp4MuxerShared with every other track Mp4Muxer::open returned
alongside it. See Mp4Muxer::open’s own docs for the
finalize-once-every-track-is-done contract this relies on.
Terminal sink that runs a YOLOv8/v11-style ONNX object-detection model
(an Ultralytics export: one image input, one [1, 4 + num_classes, num_boxes] output, box coordinates as center/width/height) on every
incoming frame via ort, then hands the decoded, NMS-filtered
detections to a plain closure — same “bring your own closure” shape as
crate::elements::AppSink, except the closure gets structured
Detections instead of a raw MediaBuffer.
Terminal sink that just counts packets. Backed by an Arc<AtomicUsize>
so the count can be read from outside the pipeline even when this sink
ends up running on a Queue worker thread.
RawPlaneWindows and d3d12 and (d3d11 or d3d12 or wasapi-renderer)
One CPU-resident image plane — data pointer, byte length, and row
stride. Deliberately a plain, GPU-vendor-agnostic struct (no
dependency on any particular rendering crate’s own type) — unlike
D3d12FrameRenderer::submit_nv12_texture’s COM types, this is the
one part of the trait that isn’t D3D12-specific, so
D3d12FrameRenderer implementors only need this crate to know
anything about their concrete rendering setup for the CPU-upload path.
Builds a SegmentedMp4Muxer the same two-phase way as a plain
Mp4Muxer (every track’s shape must be known before the first byte
is written) — create picks the rotation policy and how segments get
named, add_stream registers each track exactly like
Mp4Muxer::add_stream, open writes the first segment’s header and
returns one Sink per track.
WasapiRendererWindows and wasapi-renderer and (d3d11 or d3d12 or wasapi-renderer)
Terminal audio sink backed by a WASAPI shared-mode render endpoint.
The endpoint’s mix format is returned by WasapiRenderer::open so a
caller can place an crate::elements::AudioResampler immediately
before this sink. This element intentionally performs no hidden format
conversion. Call WasapiRenderer::bind_playback_clock while wiring a
fixed A/V pipeline to publish this endpoint’s actual played-sample position
as that pipeline’s audio master. A branch attached to a running dynamic Tee
uses WasapiRenderer::bind_playback_clock_deferred instead, so it cannot
stall video before the first audio frame reaches the renderer.
WasapiRendererOptionsWindows and wasapi-renderer and (d3d11 or d3d12 or wasapi-renderer)
Errors a D3d12FrameRenderer/D3d11FrameRenderer implementation can
report. GPU-vendor-agnostic (no D3D11/D3D12-specific type in here), so
it’s shared by both instead of each defining its own copy — and left
ungated (not behind either renderer feature) so it’s a stable type to
reference regardless of which one a caller actually enables.
WasapiRendererErrorWindows and wasapi-renderer and (d3d11 or d3d12 or wasapi-renderer)
Convenience label table for the 80 COCO classes stock Ultralytics
YOLOv8/v11 weights are trained on. Meaningless for a custom-trained
model with a different class set — index Detection::class_id into
your own labels in that case instead.
D3d11FrameRendererWindows and d3d11 and (d3d11 or d3d12 or wasapi-renderer)
What D3d11Renderer needs from an actual DX11 window/rendering
implementation — the D3D11 sibling of
crate::elements::D3d12FrameRenderer, deliberately not an impl of
that trait (it’s documented as inherently D3D12-only). Unlike the D3D12
trait, neither submit method here takes a fence or a keep_alive —
see crate::elements::D3d11Renderer’s own docs on why a single
shared ID3D11Device needs no explicit GPU-side synchronization at
all, and this doc comment’s own note below on why lifetime-keeping is
unnecessary too. Both paths here are zero-copy (no CPU-upload method
the way D3d12FrameRenderer::submit_yuv420p is one): everything in
this crate’s D3D11 stack already produces GPU-resident Pixel::D3D11
textures (see crate::elements::D3d11Upload/
crate::elements::DxgiCaptureSource’s GPU capture mode/
crate::elements::D3d11Decoder), so there’s no CPU-side pixel data
left to upload by the time a frame reaches here.
D3d12FrameRendererWindows and d3d12 and (d3d11 or d3d12 or wasapi-renderer)
What D3d12Renderer needs from an actual DX12 window/rendering
implementation — deliberately the only thing this crate knows about
D3D12 rendering. Not GPU-vendor-agnostic despite submit_yuv420p’s
plain RawPlane args: submit_nv12_texture’s zero-copy path takes
ID3D12Resource/ID3D12Fence directly, so this trait (and any
element built on it) is inherently D3D12-only — a Vulkan/CUDA renderer
would need its own trait, not an impl of this one. D3d12Renderer
itself only depends on this trait (plus the windows COM types the
zero-copy path needs to pass through) — not on renderer_engine or
any other concrete rendering crate. A caller wanting to actually
render implements this for its own window/rendering stack; this
repository’s examples use examples/render/render_common for that
implementation, outside the media-pp crate itself.