feat(vkdecode): M7's Vulkan CPU half — AV1 into the Std structures
The sequence header and the picture info, converted for VK_KHR_video_decode_av1. Same shape as the H.264 and H.265 conversions, and the same ownership contract: boxed backing beside the Std struct that points at it, movable wrapper, no mutation, not Clone. AV1 puts almost the whole frame header in the PICTURE info rather than in a parameter set, so StdVideoDecodeAV1PictureInfo carries eight pointers to per-frame blocks — tile info, quantisation, segmentation, loop filter, CDEF, loop restoration, global motion, film grain — and the tile info carries four more arrays of its own. Session parameters, by contrast, hold exactly one sequence header. That asymmetry is why params_av1 is the small module here and pic_av1 the large one. The plan now carries the parsed frame header whole. The client needs a digest — size, depth, colour, keyframe — but a backend needs nearly all of the header, so AuPlan carries it the way its H.264 and H.265 siblings carry their activated parameter sets: a backend builds from exactly what was parsed, never by re-reading the access unit. referenceNameSlotIndices holds DPB SLOT indices, not positions in the reference list, and that is the HEVC RPS defect's exact shape in a narrower place. Measured rather than argued: over the vendored vector the two readings disagree 566 times across 274 frames, and the test fails if they ever stop disagreeing, because then it would no longer be able to tell the conventions apart. Two places where transcription would have been wrong, both caught by the types and then by asking the spec: The parser's film-grain point arrays are 16 entries where the Std ones are 14 (luma) and 10 (chroma) — the spec's own maxima. The counts are validated against the Std capacity and the copy is bounded by them; a stream declaring more is refused, because a decoder handed fewer scaling points than the stream declared synthesises different grain. `coded_denom` is the superres denominator less SUPERRES_DENOM_MIN and only meaningful where superres is in use, and `UsesLr` is derived — no frame header codes it — from whether any plane's restoration type is not NONE. Film grain rides only where the sequence enables it AND the frame applies it, with the apply_grain flag set from whether a block is attached, so the flag and the pointer cannot disagree. Gates: macOS fmt/clippy/345 tests, container clippy -D warnings over six crates, 800 tests, workspace check.
This commit is contained in:
@@ -38,7 +38,6 @@ use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
use cros_codecs::codec::av1::parser::FrameHeaderObu;
|
||||
use cros_codecs::codec::av1::parser::FrameType;
|
||||
use cros_codecs::codec::av1::parser::ObuAction;
|
||||
use cros_codecs::codec::av1::parser::ParsedObu;
|
||||
use cros_codecs::codec::av1::parser::Parser;
|
||||
@@ -46,6 +45,13 @@ use cros_codecs::codec::av1::parser::SequenceHeaderObu;
|
||||
|
||||
use crate::h264::ColourDescription;
|
||||
|
||||
/// The parsed types a backend conversion names, re-exported so each names them
|
||||
/// through this module rather than reaching into the vendored crate — the same
|
||||
/// courtesy [`crate::h264`] does with its `Sps`/`Pps`.
|
||||
pub use cros_codecs::codec::av1::parser::FrameHeaderObu as ParsedFrameHeader;
|
||||
pub use cros_codecs::codec::av1::parser::FrameType;
|
||||
pub use cros_codecs::codec::av1::parser::SequenceHeaderObu as ParsedSequenceHeader;
|
||||
|
||||
/// A stable identity for a decoded picture, the same currency the other two planners
|
||||
/// deal in: the backends key their surface tables by it and never by slot index.
|
||||
pub type PicId = u64;
|
||||
@@ -133,6 +139,17 @@ pub struct AuPlan {
|
||||
pub dpb_refs: Vec<RefPic>,
|
||||
pub warnings: Vec<PlanWarning>,
|
||||
pub sequence: Rc<SequenceHeaderObu>,
|
||||
/// The frame header this plan was built from, whole.
|
||||
///
|
||||
/// [`Self::picture`] is the digest the CLIENT needs — size, depth, colour,
|
||||
/// keyframe — while a hardware backend needs nearly all of the header:
|
||||
/// AV1 puts tile info, quantisation, segmentation, loop filter, CDEF, loop
|
||||
/// restoration, global motion and film grain in the per-frame header rather
|
||||
/// than in a parameter set, and every one of them reaches the driver. Carried
|
||||
/// whole for the same reason the H.264 and H.265 plans carry their activated
|
||||
/// SPS/PPS: a backend must build its structures from exactly what was parsed,
|
||||
/// never by re-reading the access unit.
|
||||
pub header: Rc<FrameHeaderObu>,
|
||||
}
|
||||
|
||||
/// Concealment signals: planning continues, the session layer requests recovery.
|
||||
@@ -342,6 +359,9 @@ impl Av1Planner {
|
||||
tiles: Vec<TilePlan>,
|
||||
mut warnings: Vec<PlanWarning>,
|
||||
) -> Result<AuPlan, PlanError> {
|
||||
// Shared with the plan: the backends need the whole header and there is no
|
||||
// reason for each to own a copy of a struct this size.
|
||||
let header = Rc::new(header);
|
||||
let dpb_refs = self.dpb_refs();
|
||||
|
||||
// `show_existing_frame` decodes nothing: it displays a slot's contents.
|
||||
@@ -374,6 +394,7 @@ impl Av1Planner {
|
||||
removed,
|
||||
},
|
||||
dpb_refs,
|
||||
header: header.clone(),
|
||||
warnings,
|
||||
sequence,
|
||||
});
|
||||
@@ -425,6 +446,7 @@ impl Av1Planner {
|
||||
removed,
|
||||
},
|
||||
dpb_refs,
|
||||
header: header.clone(),
|
||||
warnings,
|
||||
sequence,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user