Skip to main content

VaapiEncoder

Struct VaapiEncoder 

Source
pub struct VaapiEncoder { /* private fields */ }
Expand description

Hardware-accelerated H.264 encoder built on FFmpeg’s h264_vaapi, owning the whole VA-API pipeline for one capture: device contexts, the surface pool, the color-convert filter graph, the reusable frames/packet, and live rate-control state.

The pointer members are raw FFmpeg objects freed in Drop. Three groups matter:

  1. Device / frames contexts: drm_device_ctx → derived hw_device_ctx; drm_frames_ctx describes the incoming DMA-BUF, enc_frames_ctx the VA-surface pool the encoder draws from. enc_frames_ctx is kept referenced so reopen_codec can rebuild the codec against the same pool.
  2. Filter graph: buffersrc_ctx → hwmap/hwupload + scale_vaapibuffersink_ctx, which lands every input on a GPU surface in sw_format.
  3. Reusable frames: video_frame feeds the graph on the dmabuf/host paths, sw_frame + hw_frame stage the direct planar upload in encode_raw, and packet is the shared output.

sw_format is the surface format the session negotiated — NV12 for 4:2:0, or the 4:4:4 format the driver offered — and every path keys its plane layout off it; packed_444 is the reused repack scratch for a driver whose only 4:4:4 surface is packed.

current_qp / qp_hysteresis_counter drive the CQP hysteresis in update_qp. cbr_mode, current_bitrate_kbps, current_vbv_mult, and current_kf_s cache the live rate-control state so reconfigure_rate re-opens the codec only when a value actually changes. omit_stripe_headers drops the 10-byte framing when the consumer wants a bare Annex-B stream.

Implementations§

Source§

impl VaapiEncoder

Source

pub fn new(settings: &RustCaptureSettings) -> Result<Self, String>

Build a VA-API encoder for the Wayland dmabuf path — the source is a DRM-PRIME dmabuf that the filter graph hwmaps onto a VA surface. Thin wrapper over new_impl with host_input = false.

Source

pub fn new_host(settings: &RustCaptureSettings) -> Result<Self, String>

Build a VA-API encoder for the X11 host-ARGB path — the source is a CPU BGRA frame that the filter graph hwuploads onto a VA surface. Thin wrapper over new_impl with host_input = true; the GPU still does the ARGB→YUV convert, so there is no CPU colorspace conversion.

Source

pub fn is_fullcolor(&self) -> bool

Whether this session negotiated 4:4:4 chroma. The request alone does not settle it — the driver and the FFmpeg build both have to carry it — so callers describing the active colorspace ask the encoder rather than the settings.

Source

pub fn reconfigure_rate( &mut self, settings: &RustCaptureSettings, ) -> Result<(), String>

Stays cheap enough for the pipeline to call on every single frame by re-opening the codec only when a rate-control or framerate setting has actually changed — an unconditional re-open here would force a needless IDR every frame and cripple the stream.

The change test is deliberately narrow, to keep that guard tight: in CBR, a different target bitrate or VBV multiplier; in any mode, a different target fps. When nothing changed it returns without touching the codec. On a real change it caches the new fps / bitrate / VBV / keyframe interval and calls reopen_codec carrying the current QP, so a CQP stream keeps its quantizer across the change. Err means the re-open failed and the session no longer has a codec context: the caller has to rebuild it.

Source

pub fn encode_dmabuf( &mut self, dmabuf: &Dmabuf, frame_number: u64, qp: u32, force_idr: bool, ) -> Result<Vec<u8>, String>

Encode one Wayland DRM-PRIME dmabuf by wrapping it in an FFmpeg DRM frame descriptor and pushing it through the filter graph, which hwmaps it to a VA surface and converts to the session’s surface format before encode.

  1. Quantizer: apply the requested qp through update_qp (hysteresis / CBR-aware).
  2. Descriptor: allocate a zeroed AVDRMFrameDescriptor and populate it from the dmabuf — one object per handle with a freshly dup’d fd (so FFmpeg owns independent fds), the object size the fd reports (lseek to its end, which is the buffer object’s allocation whatever the tiling or padding), the format modifier, and one layer whose planes carry each plane’s offset and pitch. A single-handle multi-plane buffer points all planes at object 0.
  3. Ownership: the dup’d fds live in a boxed DmabufResources handed to av_buffer_create as release_drm_frame’s opaque, so FFmpeg closes them on teardown. If building that buffer fails, release_drm_frame is called directly to clean up.
  4. Submit: point video_frame at the descriptor, tag it DRM-PRIME with the DRM frames context, and feed the graph. av_buffersrc_add_frame consumes the frame’s refs only on success; on error the frame is untouched, so video_frame is unref’d to release buf[0] (which runs release_drm_frame and closes the fds) — no manual fd close, which would double-close.
  5. Collect: pull each converted frame from the sink, stamp pict_type = I when force_idr, send it to the encoder, and drain packets via collect_packet.
Source

pub fn encode_host_argb( &mut self, bgra: &[u8], stride: usize, frame_number: u64, qp: u32, force_idr: bool, ) -> Result<Vec<u8>, String>

Encode one host BGRA frame (X11 path) by staging it onto a VA surface and letting the GPU do the color convert — valid only on an encoder built with new_host.

bgra is B,G,R,A in memory at stride bytes per row (padding allowed) and must hold at least stride * height bytes. The flow: apply qp via update_qp; allocate a fresh refcounted BGRA video_frame and copy the host rows in (the sole copy — plain data movement to a GPU-uploadable frame, clamped to min(width*4, stride, dst_stride) per row, not a colorspace conversion); feed the graph, where hwupload stages it onto a VA surface and scale_vaapi converts ARGB→YUV; then pull converted frames, stamp pict_type = I when force_idr, encode, and drain packets via collect_packet.

Source

pub fn encode_raw( &mut self, pixels: &[u8], frame_number: u64, qp: u32, force_idr: bool, ) -> Result<Vec<u8>, String>

Encode already-planar pixels by uploading them straight to a VA surface, bypassing the filter graph (there is no color convert to do).

pixels carries whichever layout the session negotiated: NV12 (w*h of Y then w*h/2 of interleaved UV) for a 4:2:0 session, or planar I444 (w*h each of Y, U, V) for a 4:4:4 one. The sw_frame is pointed at those planes without copying, except on a driver whose only 4:4:4 surface is packed, where pack_i444_as_vuyx stages the frame into a reused buffer first. A fresh hw_frame is pulled from the encoder pool (the frame is unref’d first, or the prior surface would leak), av_hwframe_transfer_data copies CPU→GPU, and the sw_frame is released. Keyframes are forced through pict_type = I (AV_PKT_FLAG_KEY is a packet flag, unusable on a frame); otherwise pict_type = NONE. The GPU frame is sent to the encoder and packets are drained via collect_packet.

Trait Implementations§

Source§

impl Drop for VaapiEncoder

Tear down every FFmpeg object in dependency order so nothing is freed while still referenced: first the reusable packet and frames, then the filter graph and codec context, and last the frames/device contexts they pointed at (encoder pool, DRM frames, VA-API device, DRM device). Each pointer is null-checked so a partially-built encoder unwinds cleanly.

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 VaapiEncoder

Assert VaapiEncoder is Send: its raw FFmpeg pointers are owned exclusively and the encoder is driven from a single capture thread, so moving the whole object across threads adds no aliasing.

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