Skip to main content

X11Pipeline

Struct X11Pipeline 

Source
pub struct X11Pipeline {
    settings: CaptureSettings,
    stripes: Vec<StripeState>,
    hw: Option<FrameEncoder>,
    hw_state: StripeState,
    bands: Vec<StripeState>,
    checked: Vec<StripeState>,
    turbo_dirty: Vec<bool>,
    report_whole: bool,
    frame_counter: u16,
    pending_force_idr: bool,
    hw_error_streak: u32,
    hw_rebuilt: bool,
}
Expand description

Everything the X11 host-ARGB path has to remember between frames.

Unlike the Wayland backend, X11 capture over XShm has no compositor to report every change, so this context holds the state that stands in for that missing damage signal: the per-stripe hashes and the persistent encoder session that let process() discover damage by comparing content frame-to-frame. A source that does report every change (the shared framebuffer’s watch) is read through process_reported instead, as Wayland’s compositor damage is. A full-frame encoder runs through decide_hw_fullframe; the CPU path (striped JPEG, or software H.264) runs through encode_cpu with hash_damage=true.

Recording fan-out (socket sink and MP4 recorder) is handled at the delivery layer; a consumer needing a keyframe goes through X11Pipeline::request_idr like everyone else.

Fields§

§settings: CaptureSettings§stripes: Vec<StripeState>§hw: Option<FrameEncoder>

The full-frame encoder, or None for the CPU path.

§hw_state: StripeState§bands: Vec<StripeState>

The content hashes of a full-frame session, one per band of DAMAGE_BAND_ROWS rows.

§checked: Vec<StripeState>

The bands of the Turbo frames hashed on the CPU before their encode where the session hashes its frames on the device (FrameEncoder::hash_next_upload): kept apart from bands, which holds the device’s hashes, a different function of the same picture.

§turbo_dirty: Vec<bool>

The bands the content hash found changed in the frame before this one, which a Turbo frame reads (process); empty until the first hash.

§report_whole: bool

Whether the next frame whose source reports every change (process_reported) counts as changed whole whatever it reports: the first this pipeline codes, or the first at a new size, which the source reports against a picture the pipeline never had.

§frame_counter: u16§pending_force_idr: bool§hw_error_streak: u32

Consecutive hardware encode failures and whether this pipeline already spent its one rebuild; together they drive recover_hw.

§hw_rebuilt: bool

Implementations§

Source§

impl X11Pipeline

Source

pub fn new(settings: CaptureSettings) -> Self

Build the context, choosing the full-frame encoder for the X11 host-BGRA path through the shared ladder (select_frame_encoder): the hardware backend the encode node’s driver selects, then the codec’s software encoder, or the CPU path for JPEG and H.264. A codec no backend serves falls through to the video codecs the host does serve, JPEG last.

Source

fn record_stream(&self)

Put the session this pipeline settled on into the capture’s report.

Source

fn recover_hw(&mut self)

React to a streak of hardware encode failures: rebuild the session once with the startup selection, and demote to the software encoder when a fresh session fails the same way. A session whose encodes keep failing still constructs, so the rebuild only counts as recovery until an encode succeeds; otherwise the stream would rebuild in a loop and never demote. Streaming nothing forever is not an option.

The demote is the last rung: the software path has no encode-error streak of its own, so once the pipeline lands there it is never re-entered.

Source

pub fn request_idr(&mut self)

Request an on-demand keyframe on the next processed frame.

Source

pub fn take_report(&mut self, report: ReferenceReport)

Apply what the consumers say of a frame (FrameEncoder::take_report): a loss leaves it and every frame after it out of the predictions, a key frame where the encoder cannot.

Source

pub fn encoder_name(&self) -> String

The encoder’s name for the stream log: the hardware backend, the software library of a full-frame session, or CPU with the library of the CPU path.

Source

pub fn codec(&self) -> Codec

The codec the pipeline actually emits, after any demotion.

Source

pub fn is_hardware(&self) -> bool

Whether the pipeline encodes on a GPU.

Source

pub fn capped(&self) -> bool

Whether the session runs its constant quality under the peak of its bitrate (encoders::session_capped), for this pipeline’s stream log.

Source

pub fn fixed_rate_control(&self) -> Option<&'static str>

The encoder’s one rate control where its backend has one alone (FrameEncoder::fixed_rate_control), for this pipeline’s stream log.

Source

pub fn holds_quantizer(&self) -> bool

Whether the encoder holds a cleanup at the quantizer asked for (FrameEncoder::holds_quantizer, software::stripes_hold_quantizer), for this pipeline’s stream log.

Source

pub fn colorspace_desc(&self) -> &'static str

The Colorspace: field for this pipeline’s stream log, describing what its encoder settled on: a hardware session only reaches 4:4:4 when the device carries it, the software path only when the build’s encoder for the codec does.

Source

pub fn reshape( &mut self, settings: &CaptureSettings, size_changed: bool, ) -> bool

Adapt the live pipeline to recreated capture surfaces without rebuilding it.

§Arguments
  • settings - New geometry plus current live rates.
  • size_changed - Whether the capture dimensions changed.
§Returns

true if the pipeline was successfully adapted in place; false when the active encoder cannot follow (VAAPI on resize), or the CPU path stands where an engine may take the new size (one that refused the old size, past its maximum), and the caller must rebuild.

Source

pub fn update_rate(&mut self, bitrate_kbps: i32, vbv_multiplier: f64, fps: f64)

Apply a runtime rate-control / framerate change: the CBR target bitrate + VBV (kbps / kb; ignored unless CBR is active) and the target fps. NVENC and libvpx reconfigure their live session; SVT-AV1 takes a new bitrate live where the library can and re-opens otherwise, as x265 and kvazaar always do; a VA-API session takes a constant-rate target with the next picture and starts a new sequence for any other change; the CPU path picks the new values up on the next process() (encode_cpu reads the updated settings and reconfigures its encoder).

Take the rate the path carries (CaptureSettings::video_link_kbps), which the next process() reads.

Source

pub fn update_tunables(&mut self, t: &LiveTunables)

Apply live per-frame tunables (quality, paint-over, streaming mode, keyframe cadence); every encoder re-reads them from the settings on the next process().

Source

pub fn process(&mut self, argb: &[u8], stride: usize) -> Vec<EncodedStripe>

Encode one host-ARGB frame and return the encoded stripes.

Damage is read from the content hash (hash_bands). Without Turbo the hash decides whether a frame (or a stripe) is sent, so it runs first. Turbo sends every video frame, and only its cleanup reads the damage, so there the frame’s hash runs beside its encode (hash_beside) and the cleanup reads the frame before’s (turbo_dirty; the CPU path as the rows it maps onto its regions): the hash, a millisecond and a half at 1080p and six at 4K, stays off the path to the client. A frame the cleanup codes at its own quality is hashed before its encode instead, so a change landing on it is coded at the session’s. With the paint-over off nothing reads it, and Turbo hashes nothing.

§Arguments
  • argb - Packed BGRA pixel buffer (B,G,R,A byte order, stride bytes per row).
  • stride - Bytes per row (must equal width * 4 for the software path).
§Returns

Vec of EncodedStripe — empty when nothing changed.

Source

pub fn process_damaged( &mut self, argb: &[u8], stride: usize, changed: &[Rectangle<i32, Physical>], ) -> Vec<EncodedStripe>

Self::process for a frame whose source says where it changed (changed, in the frame’s coordinates), which places the change within each region for its block ledger (ledger); the content hash still decides which regions changed, and one it finds changed that no rectangle reaches counts as changed whole.

Source

pub fn process_reported( &mut self, argb: &[u8], stride: usize, changed: &[Rectangle<i32, Physical>], ) -> Vec<EncodedStripe>

Self::process for a frame whose source reports every change it made (changed): the rectangles decide what changed, as a compositor’s damage does on Wayland, and no content hash is taken. Hashing the frame only to learn what the source already said cost 0.84 ms of every 2560x1600 frame on the capture’s critical path.

Source

pub fn process_reported_planes( &mut self, argb: &[u8], stride: usize, planes: &Nv12Planes, changed: &[Rectangle<i32, Physical>], ) -> Vec<EncodedStripe>

Self::process_reported for a frame its capture already converted to the picture the session encodes (planes, where Self::takes_host_planes); argb is left unread. The session reads the picture through the next frame’s encode (Self::held_input).

Source

pub fn held_input(&self) -> Option<*const u8>

The picture the session still reads after the last frame’s encode returned, by its Nv12Planes::id, which its owner leaves unchanged until a later encode stops naming it or Self::release_input.

Source

pub fn release_input(&mut self)

Stop the session reading the picture it holds (Self::held_input).

Source

pub fn takes_host_planes(&self) -> bool

Whether this pipeline encodes 8-bit 4:2:0 pictures a capture converts itself, as NV12 laid out for x264 (Nv12Planes): the x264 session of the CPU path.

Source

fn process_frame( &mut self, argb: &[u8], stride: usize, planes: Option<&Nv12Planes>, changed: &[Rectangle<i32, Physical>], reported: bool, ) -> Vec<EncodedStripe>

Self::process_damaged, or Self::process_reported where reported, from planes where the capture converted the frame itself.

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,

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
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.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

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

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<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