Skip to main content

DxgiCaptureSource

Struct DxgiCaptureSource 

Source
pub struct DxgiCaptureSource { /* private fields */ }
Available on Windows and crate feature dxgi-capture and (crate features dxgi-capture or wasapi-capture) only.
Expand description

Captures the desktop via Windows’ DXGI Desktop Duplication API (IDXGIOutputDuplication) — GStreamer’s d3d11screencapturesrc equivalent. One src pad, pushing Pixel::BGRA frames (no internal color conversion — same division of labor as every other source in this crate: chain a crate::elements::Scaler downstream if something needs YUV420P, e.g. crate::elements::D3d12Renderer’s CPU-upload path or crate::elements::SwEncoder).

Emits at a constant rate — DxgiCaptureOptions::fps — not one push per real desktop change. An earlier version of this pushed variable-rate (VFR): a real wall-clock pts per actual change, nothing in between. That turned out to cause real problems, both for muxing (most consumers assume something closer to a steady rate) and, concretely, for live rendering: D3d12Renderer presents on a vsync-locked swap chain (Present(1, ..)) that only ever shows the latest submitted frame each tick, silently dropping anything else queued behind it — submission timing straight off an irregular VFR source has no relationship to that vsync grid, so real changes would unpredictably race into the same tick (one silently discarded) or land in a gap (stale frame held an extra tick), which is visible judder even though the average rate was exactly right.

So instead: this element always keeps the most recently captured desktop image on hand, and SourceElement::run’s own loop emits it — the same one again if nothing changed since the last tick — at a steady 1 / fps cadence, entirely on the one thread run() already has (no extra threads spawned; see this crate’s own “elements never spawn their own threads” rule). Same shape as crate::elements::TestVideoSource: DxgiCaptureSource::time_base is 1 / fps and pts is a plain incrementing tick counter, one per emitted frame, not per real capture.

Confirmed (examples/render/screen_capture, with and without a downstream crate::elements::Pacer) that this constant-rate, drift-free schedule is what actually mattered — not whether a separate Pacer stage exists. The VFR version needed one to paper over its own irregular submission timing; once emission here is steady and drift-free, Scaler’s modest, fairly consistent per-frame conversion cost isn’t enough on its own to reintroduce the same vsync misalignment, so a straight DxgiCaptureSource -> Scaler -> D3d12Renderer chain stays smooth with no Pacer at all. Pacer remains genuinely useful for other reasons (multi-stream sync against a shared Clock, or a stage with real per-frame variance like SwEncoder), just not load-bearing here purely for vsync alignment the way it first appeared to be.

Deliberately does not retry internally on DXGI_ERROR_ACCESS_LOST (lock screen, UAC prompt, display mode change, …) — same “fail fast, caller rebuilds” contract as crate::elements::RtspSource; watch for DxgiCaptureSourceError::AccessLost and call DxgiCaptureSource::open again.

Runs until Stop — never reaches Eos on its own, same as TestVideoSource (there’s no natural end to a live desktop capture).

May capture from more than one output at once — see CaptureArea::Region — in which case every field below that used to describe “the” duplication instead describes one CaptureUnit per contributing output.

Implementations§

Source§

impl DxgiCaptureSource

Source

pub fn open( name: impl Into<String>, options: DxgiCaptureOptions, ) -> Result<(Self, u32, u32, Option<ID3D11Device>), DxgiCaptureSourceError>

Opens whichever output(s) DxgiCaptureOptions::area resolves to and starts duplicating them. Returns the element alongside the captured composite’s actual (width, height) — what the caller needs to build a matching downstream crate::elements::Scaler/crate::elements::Pacer, same pattern as crate::elements::RtspSource::open returning stream info — plus, under CaptureMode::Gpu, the ID3D11Device this capture was opened on (None under CaptureMode::Cpu, where nothing downstream needs to share it). This is always built from whichever adapter area actually resolves to — see CaptureMode::Gpu’s own docs on why callers should build every other D3D11 element sharing this capture from the returned device rather than a separately-created one.

Source

pub fn time_base(&self) -> Rational

The unit each emitted frame’s pts is expressed in — what you need to construct a matching crate::elements::Pacer. 1 / fps, same convention as crate::elements::TestVideoSource::time_base.

Trait Implementations§

Source§

impl Element for DxgiCaptureSource

Source§

fn name(&self) -> Arc<str>

Returns a cheap clone (refcount bump, not a deep copy) of this element’s name — crate::bus::BusEvent stores names as Arc<str> for exactly this reason: a hot path like crate::queue::Queue posting BusEvent::Dropped once per overflowed buffer shouldn’t pay for a fresh heap allocation every time it wants to report which element it is.
Source§

fn element_type(&self) -> ElementType

Source§

fn pp_log(&self) -> &PpLog

This element’s identity for crate::bus::Bus::post — same id/name as Element::name, just already wrapped as the crate::pp_log::PpLog its pp_info!/pp_warn!/pp_error! macros need. A stored private field, not built fresh per call, for the same reason name() returns a cheap Arc<str> clone instead of a fresh String — see its own docs.
Source§

fn pp_log_mut(&mut self) -> &mut PpLog

Mutable access to the same field Element::pp_log reads — used by crate::pipeline::ChainBuilder to stamp the owning crate::pipeline::Pipeline’s id onto every element that passes through it, via element_pp_log. Not meant to be called from anywhere else.
Source§

fn graph_id(&self) -> Option<ElementId>

A pre-reserved graph identity for elements that expose dynamic attachment handles. Most elements receive an ID from ChainBuilder and keep the default None implementation.
Source§

impl Send for DxgiCaptureSource

Source§

impl Source for DxgiCaptureSource

Source§

fn src_pads(&mut self) -> &mut [SrcPad]

Source§

impl SourceElement for DxgiCaptureSource

Source§

fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>

Drives this source until Eos (normal completion), crate::pipeline::Pipeline::finish, or Stop (see ControlMsg::Stop) — call crate::control::drain_control once per loop iteration to make control responsive between blocking reads. Read more
Source§

fn seek(&mut self, _target: Duration) -> Result<Duration>

Repositions this source to target, an absolute position from the start of the media (e.g. av_seek_frame for crate::elements::FileDemuxer). Called by crate::control::drain_control as part of handling ControlMsg::Seek, before that message is forwarded to the source’s own pads — so whatever’s read next comes from the new position by the time downstream elements are told to flush for it. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more