Skip to main content

H264EncoderWrapper

Struct H264EncoderWrapper 

Source
pub struct H264EncoderWrapper {
    pub width: i32,
    pub height: i32,
    pub is_i444: bool,
    /* private fields */
}
Expand description

One long-lived libx264 session for a stripe, holding the raw x264_t handle alongside a mirror of its live parameters so the encoder can be retuned per frame instead of rebuilt.

Rebuilding an x264 encoder is expensive and forces a fresh IDR, so a stripe keeps its instance across frames and only nudges CRF, bitrate, VBV, and frame rate live; the tracked current_* fields are that mirror, letting a reconfigure skip the FFI call whenever nothing actually changed. is_i444 (4:4:4 vs 4:2:0) is baked into the encoder’s colour space at open, so a change to it is one of the few things that forces a full rebuild; is_cbr records which rate-control mode was chosen at open and gates which of the live reconfigures apply. The manual Send impl exists only because a raw pointer is not Send by default and the handle must move onto the rayon stripe workers; Drop closes it under the global open/close lock for the same reason that lock exists.

Fields§

§width: i32§height: i32§is_i444: bool

Implementations§

Source§

impl H264EncoderWrapper

Source

pub fn new( width: i32, height: i32, crf: i32, is_i444: bool, fps: f64, threads: i32, cbr_mode: bool, bitrate_kbps: i32, vbv_kbit: i32, min_qp: i32, max_qp: i32, ) -> Option<Self>

Open an x264 encoder tuned for real-time screen streaming, or None on failure.

Why this configuration. These frames are captured live and must ship immediately, so the encoder is optimized for latency over compression ratio: the ultrafast preset keeps encode time under the frame budget, and zerolatency bars the frame reordering and lookahead buffering that would otherwise add pipeline delay. Everything below then bends x264 toward the pipeline’s own keyframe and colour model instead of its broadcast-oriented defaults.

  1. Preset/tune: starts from the ultrafast preset with the zerolatency tune, then overrides resolution, frame rate (floored to 30 fps when under 1), and thread count.
  2. Infinite GOP: i_keyint_max is set to x264’s infinite sentinel and adaptive scene-cut is disabled (i_scenecut_threshold = 0), so the encoder never injects an unrequested IDR on a scene change — keyframes are purely on-demand via the forced-IDR path, matching the strict infinite-GOP model.
  3. Rate control:
    • CBR (cbr_mode): ABR targeting bitrate_kbps with a VBV cap pinned to the same value (buffer vbv_kbit, precomputed by the caller from the frame-time multiplier policy) and filler disabled. Optional QP clamps apply only when non-zero — max_qp is the legibility floor (caps how ugly a rate-starved frame gets) and min_qp the waste ceiling (stops over-spending on easy content); both are clamped to 51.
    • CRF (default): constant-quality with f_rf_constant = crf.
  4. Colour: I444 (full range) or I420 (limited range) CSP, BT.709 VUI primaries/transfer/ matrix, and the matching high444 / baseline profile.
  5. Coding tools: CABAC and the 8x8 transform are disabled, matching the low-latency baseline profile — CAVLC entropy coding with no 8x8 DCT — for minimal encode cost.
  6. Output: repeated headers (SPS/PPS before each keyframe) and Annex-B framing, with x264’s own logging silenced.

The x264_encoder_open call is serialized under X264_OPEN_CLOSE_LOCK because it mutates libx264 global state.

Source

pub fn reconfigure_crf(&mut self, new_crf: i32)

Retune the constant-quality CRF on the running encoder, so a quality change costs a parameter push rather than tearing down and rebuilding the session (a rebuild would force an IDR and drop encoder state).

It is a no-op in CBR mode, where rate is bitrate-controlled and CRF simply does not apply, and a no-op when the value is unchanged — the tracked current_crf is what makes that cheap early-out possible. Otherwise it reads the encoder’s live parameters, overwrites f_rf_constant, and pushes the change via x264_encoder_reconfig, advancing the tracked CRF only once the reconfig has actually succeeded so the mirror never drifts from the encoder.

Source

pub fn reconfigure_rate(&mut self, bitrate_kbps: i32, vbv_kbit: i32, fps: f64)

Retune bitrate/VBV (CBR only) and/or frame rate to match the live settings, structured to be called unconditionally every frame so the caller need not track what changed itself.

Because encode_cpu fires it on every frame, it first computes the would-be values and bails before touching the encoder when neither the CBR bitrate/VBV nor the frame rate differs from what is live — that self-gating keeps a per-frame call nearly free.

A frame-rate change reopens the encoder rather than reconfiguring it: x264_encoder_reconfig does not apply i_fps_*, and the CBR/VBV per-frame budget is bitrate / fps, so a session left at its old rate ships roughly half the configured bitrate once fps halves. The reopen carries the new bitrate/VBV too, and a fresh session emits an IDR on its first frame; a failed reopen keeps the working session instead of nulling the handle. A bitrate/VBV-only change (CBR) stays a live x264_encoder_reconfig, and the tracked mirror advances only on success so it cannot drift from the encoder’s real state.

Source

pub fn encode_with_headers( &mut self, y: &[u8], u: &[u8], v: &[u8], y_stride: i32, u_stride: i32, v_stride: i32, frame_id: i64, force_idr: bool, fixed_header: &[u8], omit_headers: bool, output_buf: &mut Vec<u8>, ) -> bool

Encode one YUV frame into H.264 and frame it for the wire, reporting whether the encoder actually emitted a bitstream this call.

The boolean return is load-bearing: x264_encoder_encode can legitimately produce nothing on a given call, and the caller must forward a stripe only when real bytes exist — never an empty or header-only packet. Framing is conditional because the transport needs the pipeline’s small wire header to route the stripe, while omit_headers consumers take the bare Annex-B elementary stream.

  1. Picture setup: wraps the borrowed Y/U/V planes and their strides in an x264_picture_t with the encoder’s CSP, stamps the presentation timestamp with frame_id, and requests an IDR when force_idr is set (otherwise X264_TYPE_AUTO).
  2. Encode: calls x264_encoder_encode; a non-positive returned size means no frame was emitted this call, so the function returns false without writing output.
  3. Framing: output_buf is cleared and refilled. Unless omit_headers is set, a header is prepended — a 0x04 codec tag, then a type byte read from the actual output picture type rather than from force_idr, because the encoder may not honor a keyframe request and the client keys its decode-recovery on the frame type it truly received (IDR = 0x01, I = 0x02, else 0x00), then the caller’s fixed_header (frame number, y-start, width, height). With omit_headers the output is bare Annex-B.
  4. Payload: every NAL payload is appended to output_buf after the optional header, so the bytes past the wire header are always a contiguous Annex-B access unit.

Trait Implementations§

Source§

impl Drop for H264EncoderWrapper

Available on crate feature gpl only.
Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl Send for H264EncoderWrapper

Available on crate feature gpl only.

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> 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<T> Ungil for T
where T: Send,

§

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