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: boolWhether 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: u32Consecutive hardware encode failures and whether this pipeline already spent its one
rebuild; together they drive recover_hw.
hw_rebuilt: boolImplementations§
Source§impl X11Pipeline
impl X11Pipeline
Sourcepub fn new(settings: CaptureSettings) -> Self
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.
Sourcefn record_stream(&self)
fn record_stream(&self)
Put the session this pipeline settled on into the capture’s report.
Sourcefn recover_hw(&mut self)
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.
Sourcepub fn request_idr(&mut self)
pub fn request_idr(&mut self)
Request an on-demand keyframe on the next processed frame.
Sourcepub fn take_report(&mut self, report: ReferenceReport)
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.
Sourcepub fn encoder_name(&self) -> String
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.
Sourcepub fn is_hardware(&self) -> bool
pub fn is_hardware(&self) -> bool
Whether the pipeline encodes on a GPU.
Sourcepub fn capped(&self) -> bool
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.
Sourcepub fn fixed_rate_control(&self) -> Option<&'static str>
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.
Sourcepub fn holds_quantizer(&self) -> bool
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.
Sourcepub fn colorspace_desc(&self) -> &'static str
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.
Sourcepub fn reshape(
&mut self,
settings: &CaptureSettings,
size_changed: bool,
) -> bool
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.
Sourcepub fn update_rate(&mut self, bitrate_kbps: i32, vbv_multiplier: f64, fps: f64)
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).
Sourcepub fn set_link_rate(&mut self, kbps: i32)
pub fn set_link_rate(&mut self, kbps: i32)
Take the rate the path carries (CaptureSettings::video_link_kbps), which the next
process() reads.
Sourcepub fn update_tunables(&mut self, t: &LiveTunables)
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().
Sourcepub fn process(&mut self, argb: &[u8], stride: usize) -> Vec<EncodedStripe>
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,stridebytes per row).stride- Bytes per row (must equalwidth * 4for the software path).
§Returns
Vec of EncodedStripe — empty when nothing changed.
Sourcepub fn process_damaged(
&mut self,
argb: &[u8],
stride: usize,
changed: &[Rectangle<i32, Physical>],
) -> Vec<EncodedStripe>
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.
Sourcepub fn process_reported(
&mut self,
argb: &[u8],
stride: usize,
changed: &[Rectangle<i32, Physical>],
) -> Vec<EncodedStripe>
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.
Sourcepub fn process_reported_planes(
&mut self,
argb: &[u8],
stride: usize,
planes: &Nv12Planes,
changed: &[Rectangle<i32, Physical>],
) -> Vec<EncodedStripe>
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).
Sourcepub fn held_input(&self) -> Option<*const u8>
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.
Sourcepub fn release_input(&mut self)
pub fn release_input(&mut self)
Stop the session reading the picture it holds (Self::held_input).
Sourcepub fn takes_host_planes(&self) -> bool
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.
Sourcefn process_frame(
&mut self,
argb: &[u8],
stride: usize,
planes: Option<&Nv12Planes>,
changed: &[Rectangle<i32, Physical>],
reported: bool,
) -> Vec<EncodedStripe>
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§
impl !Sync for X11Pipeline
impl Freeze for X11Pipeline
impl RefUnwindSafe for X11Pipeline
impl Send for X11Pipeline
impl Unpin for X11Pipeline
impl UnsafeUnpin for X11Pipeline
impl UnwindSafe for X11Pipeline
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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