Skip to main content

DecodePath

Enum DecodePath 

Source
pub enum DecodePath {
    Auto,
    AnyHardware,
    Hardware(Backend),
    Software,
}
Expand description

Which decode path a video session takes — the choice CarrierVideoStreamDecoder::open_as is given.

§Three words and a pin, and what each permits

  • Auto: before the first picture, the platform’s hardware backends in probe order, the packets taken so far replayed across them; when none takes the stream, software, the same packets replayed into it. After it, the decoder that produced it.
  • AnyHardware: the same probe, and never software — when no backend takes the stream, Error::AllBackendsFailed hands back the packets the probe took. After the first picture, the backend that produced it.
  • Software: libavcodec’s own decoder, with no probe, before and after.
  • Hardware(b), the pin: backend b, committed at open; nothing else is tried, before or after.

After the first picture nothing changes the road, on any path, and nothing is classified. A decoder failure (VideoDecodeError::Decode) is that picture’s own error, reported as it was minted, and nothing of it is remembered, so the next call reaches libavcodec. Whether a hardware session recovers is FFmpeg’s: after a VideoToolbox restart that fails, every picture fails the same way until a new parameter set re-arms the restart, and flush rebuilds no hardware session. See VideoDecoder for the lines.

§When to stop trusting a hardware session

A caller that sees a hardware session’s decoder failures persist rebuilds: it opens a session on Software from the same parameters and feeds it forward. When to do so is the caller’s policy, not this crate’s, because it is the caller that sees the failures on all three roads, the packets’ key flags and what it has delivered. What the new session can be fed depends on the road the failure came from:

  • send_packet: the failure names the packet in hand, and the new session is given that packet.
  • receive_frame: the failure may concern a packet accepted earlier. FFmpeg decouples input from output and may hold several pictures (libavcodec/avcodec.h 90–139 in FFmpeg 9.0.1), so no packet is named: the new session is given the next packet, and the caller accepts the gap.
  • send_eof: the end has no packet to give a new session. What the hardware session still held is recoverable only from packets kept from before, or by a seek.

What a policy counts is the hardware session’s decoder failures, VideoDecodeError::Decode. A VideoDecodeError::Convert is this wrapper’s own: a decoded picture it could not convert into a frame (a frame ceiling, a pixel format or plane layout it cannot carry, an allocation). It is reported, not counted. One that failed on an allocation parks the picture: the next receive_frame converts it again, and until one delivers it send_packet and send_eof answer Sent::MustDrain without reaching libavcodec. That is the wrapper’s back pressure, not a failure.

The example in the crate documentation is the simplest such policy:

  • It counts the hardware session’s decoder failures from all three roads, and only a delivered picture ends the count.
  • At a threshold of its own it opens Software from the same parameters and feeds it forward, road by road as above. Every picture the new session delivers is delivered as it is.
  • On software its failures are reported and the stream goes on: software is where the policy ends.

It keeps no packets, so the pictures from a failure to the next keyframe are lost: the new session holds no reference pictures, and libavcodec drops or conceals what comes before one. A caller that cannot afford that gap keeps packets and replays them with a picture identity of its own; that bookkeeping is the caller’s design, and the example does not show it.

The words differ in what they permit, not only where they start. That is the difference the consumers of this door need. A determinism comparison decodes one stream both ways and compares the pixels; a run that silently swapped paths halfway would compare nothing and say it had. An operator turning hardware off for a lane over a driver that produces wrong pixels needs it to stay off. And a node that sends hardware and software sessions to separate pools needs a hardware session that never quietly becomes a software one — which is what AnyHardware is for.

§Observability

is_hardware and is_software read where a session is, which stays a live reading — under Auto it can change once, during the probe, and under the others it answers what was chosen because nothing can move it.

This type deliberately grows no is_* predicates of its own, where most vocabularies in this crate do. They would spell the decoder’s two questions a second time with a different meaning — path.is_software() is what was asked for and decoder.is_software() is where it ended up, and under Auto those genuinely differ. A caller that needs to branch on the choice it made already holds the value and can match it.

Variants§

§

Auto

Probe the platform’s hardware backends in order and fall back to software when none takes the stream before its first picture, the packets the probe consumed replayed into it so nothing is lost. After the first picture the session stays on the decoder that produced it.

What CarrierVideoStreamDecoder::open does.

§

AnyHardware

Any of the platform’s hardware backends, and never software.

The same probe as Auto: the backends in the platform’s probe order, the packets taken before the first picture replayed across them as each one is tried. Where Auto would then open software, this arm refuses — at open_as when no backend opens (on a platform with no hardware backend at all, at once), and on the road that met it when the probe exhausts later — with Error::AllBackendsFailed carrying every backend’s attempt and the packets the probe took, so the caller can replay them into a software session of its own. After the first picture it is the backend that produced it, as on every path.

is_hardware answers true for the session’s whole life.

§

Hardware(Backend)

This hardware backend, or nothing. No other backend is probed and software is never opened.

A backend that cannot be opened for the stream fails the open_as call. The backend is committed from open, so every failure after it is that picture’s own error, as on every path.

§

Software

Software, with no probe at all.

Opens libavcodec’s own decoder for the stream directly. There is no hardware in this session to fail, so there is nothing for it to fall back from — the state Auto reaches when its probe exhausts, entered on purpose.

Trait Implementations§

Source§

impl Clone for DecodePath

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for DecodePath

Source§

impl Debug for DecodePath

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for DecodePath

Source§

impl Hash for DecodePath

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for DecodePath

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for DecodePath

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

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

Source§

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

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.
Source§

impl<T> WithSubscriber for T

Source§

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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