//! H.265 parameter-set conversion: the vendored parser's [`Vps`]/[`Sps`]/[`Pps`]
//! into the `StdVideoH265*ParameterSet` structs a Vulkan Video session-parameters
//! object is created from — [`crate::params`] one codec over (M3's CPU half).
//!
//! The Std structs embed raw pointers (`pProfileTierLevel`, `pDecPicBufMgr`,
//! `pScalingLists`, `pShortTermRefPicSet`, `pLongTermRefPicsSps`, ...), so
//! conversion returns OWNING wrappers — the exact aliasing/lifetime contract of
//! [`crate::OwnedStdSps`], restated on [`OwnedStdH265Sps`].
//!
//! Deliberate skips, mirroring the H.264 module's VUI decision (a DECODE session
//! consumes neither of these — they shape display and rate conformance, not
//! reconstruction):
//!
//! - VUI: `vui_parameters_present_flag` stays 0 and `pSequenceParameterSetVui`
//!   stays null. Colour rides [`pf_bitstream::h265::PicturePlan::colour`] into the
//!   presenter, per picture, exactly as H.264 does it.
//! - HRD/timing: `vps_timing_info_present_flag` stays 0 and `pHrdParameters`
//!   stays null. HRD is buffer-conformance machinery; no decode operation reads it.
//!
//! Short-term RPS candidates are re-encoded in RESOLVED form: the vendored parser
//! has already run the 7.4.8 inter-RPS prediction (equations 7-59..7-66) and
//! stores every SPS candidate as absolute `DeltaPocS0`/`DeltaPocS1` arrays, so
//! each set is declared non-predicted with those derived values encoded back into
//! `delta_poc_sX_minus1` syntax. Equivalent by construction — 7-65/7-66 IS the
//! definition of a set's content, and both the direct and the predicted syntax
//! derive the same arrays — and it is the same "the parser already resolved it"
//! idiom the H.264 module applies to scaling lists. A slice-inline RPS that
//! predicts from an SPS candidate still derives identically in hardware: the
//! derivation consumes only the source set's DeltaPoc arrays and counts, all
//! preserved here (`NumDeltaPocsOfRefRpsIdx` rides the picture info, see
//! [`crate::pic_h265`]).

use ash::vk::native as hh;
pub use cros_codecs::codec::h265::parser::Pps;
use cros_codecs::codec::h265::parser::ProfileTierLevel;
use cros_codecs::codec::h265::parser::ScalingLists;
use cros_codecs::codec::h265::parser::ShortTermRefPicSet;
pub use cros_codecs::codec::h265::parser::Sps;
pub use cros_codecs::codec::h265::parser::Vps;
use pf_bitstream::h265::Level;

/// A parameter set that cannot be represented as a StdVideo struct, or that sits
/// outside the punktfunk H.265 decode envelope (4:2:0 and 4:4:4 at 8 or 10 bits,
/// from encoders we control). Hitting one is a stream-integrity failure, not a
/// feature gap — reject-with-error rather than submit a half-truth to a driver.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum H265ParamsError {
    /// `general_profile_idc` has no `StdVideoH265ProfileIdc` code point. Vulkan
    /// defines Main (1), Main 10 (2), Main Still Picture (3) and Format Range
    /// Extensions (4); High Throughput/SCC/scalable profiles land here.
    UnmappableProfileIdc(u8),
    /// `chroma_format_idc` past 3 — not legal H.265 to begin with.
    InvalidChromaFormatIdc(u8),
    /// 4:2:2 or monochrome: legal H.265, but no punktfunk host emits it and the
    /// client has no output-format plumbing for it — outside the envelope.
    UnsupportedChromaFormat(u8),
    /// 4:4:4 with `separate_colour_plane_flag`: ChromaArrayType 0 in disguise
    /// (three monochrome-coded planes) — no output-format plumbing, and most
    /// decode hardware refuses it.
    SeparateColourPlanes,
    /// Bit depth beyond 8/10, or luma and chroma depths that disagree: no
    /// punktfunk output format (NV12/P010 and their 4:4:4 counterparts) can carry
    /// it — outside the envelope.
    UnsupportedBitDepth { luma_minus8: u8, chroma_minus8: u8 },
    /// SCC palette predictor initializers: `pPredictorPaletteEntries` is the one
    /// Std pointer this conversion does not populate (punktfunk hosts emit no SCC
    /// coding), and a present-flag over a null pointer would be a half-truth.
    PalettePredictorInitializers,
    /// `num_short_term_ref_pic_sets` past the spec's 64 (7.4.3.2.1).
    TooManyShortTermRpsSets(u8),
    /// The SPS declares more short-term RPS candidates than the parser resolved —
    /// a corrupt table this conversion refuses to pad.
    MissingShortTermRps { index: usize },
    /// An RPS candidate holds more entries on one side than the Std struct's
    /// 16-element arrays (7.4.8 bounds both sides by the DPB size, itself <= 16).
    RpsEntryOverflow {
        set: usize,
        negative: u8,
        positive: u8,
    },
    /// An RPS candidate's derived `DeltaPocS0`/`DeltaPocS1` array is not strictly
    /// monotonic (or a step exceeds the 7.4.8 bound of 2^15), so it cannot be
    /// re-encoded as `delta_poc_sX_minus1` syntax. Unreachable off the vendored
    /// parser; guards directly-constructed inputs.
    NonMonotonicRps { set: usize },
    /// `num_long_term_ref_pics_sps` past the spec's 32 (7.4.3.2.1).
    TooManyLongTermSpsPics(u8),
    /// A syntax value overflows the (narrower) Std field that carries it — e.g. a
    /// tile column width past `u16`. The parser bounds everything it reads, so
    /// this guards hostile or directly-constructed inputs.
    FieldOverflow { field: &'static str, value: i64 },
}

impl std::fmt::Display for H265ParamsError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            H265ParamsError::UnmappableProfileIdc(idc) => {
                write!(
                    f,
                    "general_profile_idc {idc} has no StdVideoH265ProfileIdc code point"
                )
            }
            H265ParamsError::SeparateColourPlanes => {
                write!(
                    f,
                    "4:4:4 with separate_colour_plane_flag (ChromaArrayType 0) is \
                     outside the punktfunk decode envelope"
                )
            }
            H265ParamsError::InvalidChromaFormatIdc(idc) => {
                write!(f, "invalid chroma_format_idc {idc}")
            }
            H265ParamsError::UnsupportedChromaFormat(idc) => {
                write!(
                    f,
                    "chroma_format_idc {idc} is outside the punktfunk decode envelope \
                     (4:2:0 and 4:4:4 only)"
                )
            }
            H265ParamsError::UnsupportedBitDepth {
                luma_minus8,
                chroma_minus8,
            } => {
                write!(
                    f,
                    "bit depth {}/{} is outside the punktfunk decode envelope \
                     (8- and 10-bit, luma == chroma)",
                    luma_minus8 + 8,
                    chroma_minus8 + 8
                )
            }
            H265ParamsError::PalettePredictorInitializers => {
                write!(
                    f,
                    "SCC palette predictor initializers are not expressible by this conversion"
                )
            }
            H265ParamsError::TooManyShortTermRpsSets(n) => {
                write!(f, "{n} short-term RPS candidates exceed the spec's 64")
            }
            H265ParamsError::MissingShortTermRps { index } => {
                write!(f, "short-term RPS candidate {index} was never resolved")
            }
            H265ParamsError::RpsEntryOverflow {
                set,
                negative,
                positive,
            } => {
                write!(
                    f,
                    "short-term RPS candidate {set} holds {negative} negative / {positive} \
                     positive entries; the Std arrays hold 16 per side"
                )
            }
            H265ParamsError::NonMonotonicRps { set } => {
                write!(
                    f,
                    "short-term RPS candidate {set} has a non-monotonic DeltaPoc array"
                )
            }
            H265ParamsError::TooManyLongTermSpsPics(n) => {
                write!(f, "{n} long-term SPS candidates exceed the spec's 32")
            }
            H265ParamsError::FieldOverflow { field, value } => {
                write!(f, "{field} value {value} overflows its Std field")
            }
        }
    }
}

impl std::error::Error for H265ParamsError {}

/// Checked narrowing into a Std field: the parser bounds everything it reads, so
/// an overflow here means hostile or directly-constructed input — fail closed,
/// never truncate (a truncated tile width would decode as garbage, silently).
fn narrow<S, D>(field: &'static str, value: S) -> Result<D, H265ParamsError>
where
    D: TryFrom<S>,
    S: Copy + Into<i64>,
{
    D::try_from(value).map_err(|_| H265ParamsError::FieldOverflow {
        field,
        value: value.into(),
    })
}

/// The converted VPS plus the heap allocations its embedded pointers target.
/// Ownership contract as [`crate::OwnedStdSps`]: boxed backing, movable wrapper,
/// no mutation, deliberately not `Clone` (re-convert instead).
#[derive(Debug)]
pub struct OwnedStdH265Vps {
    /// Boxed so [`Self::std`]'s ADDRESS — what `pStdVPSs` points at — survives every
    /// move of the wrapper ([`crate::OwnedStdSps`]).
    std: Box<hh::StdVideoH265VideoParameterSet>,
    _ptl_backing: Box<hh::StdVideoH265ProfileTierLevel>,
    _dpb_backing: Box<hh::StdVideoH265DecPicBufMgr>,
}

impl OwnedStdH265Vps {
    /// The Std struct, valid for as long as `self` lives (do not let a `Copy` of
    /// it outlive the wrapper — see [`crate::OwnedStdSps`]).
    pub fn std(&self) -> &hh::StdVideoH265VideoParameterSet {
        &self.std
    }

    /// Lower the profile/tier/level block's `general_level_idc` to `max` when the
    /// stream declares a higher one. The declared level is a CLAIM, and encoders
    /// over-claim in the wild (AMF stamps 6.2 — the codec maximum — on streams that
    /// need 5.2); handing the driver a level above its `maxLevelIdc` is invalid
    /// usage, while the stream's real demands are enforced by the session's coded
    /// extent and DPB depth. The "no mutation" ownership contract is about blocks a
    /// LIVE parameters object points at; this runs before the set is handed over.
    pub(crate) fn clamp_level(&mut self, max: hh::StdVideoH265LevelIdc) {
        if self._ptl_backing.general_level_idc > max {
            self._ptl_backing.general_level_idc = max;
        }
    }
}

/// The converted SPS plus the heap allocations its embedded pointers target.
///
/// Same ownership contract as [`crate::OwnedStdSps`], with five potential
/// pointers: the profile/tier/level and DPB-manager blocks are always present,
/// scaling lists / short-term RPS candidates / long-term SPS candidates only when
/// the stream carries them. `pSequenceParameterSetVui` and
/// `pPredictorPaletteEntries` are null by design (module docs; palette data is
/// rejected, not dropped).
#[derive(Debug)]
pub struct OwnedStdH265Sps {
    /// Boxed for [`OwnedStdH265Vps`]'s reason: `pStdSPSs` is this field's address.
    std: Box<hh::StdVideoH265SequenceParameterSet>,
    _ptl_backing: Box<hh::StdVideoH265ProfileTierLevel>,
    _dpb_backing: Box<hh::StdVideoH265DecPicBufMgr>,
    _scaling_backing: Option<Box<hh::StdVideoH265ScalingLists>>,
    /// `pShortTermRefPicSet`'s target: `num_short_term_ref_pic_sets` entries.
    _st_rps_backing: Option<Box<[hh::StdVideoH265ShortTermRefPicSet]>>,
    _lt_backing: Option<Box<hh::StdVideoH265LongTermRefPicsSps>>,
}

impl OwnedStdH265Sps {
    /// The Std struct, valid for as long as `self` lives (see [`crate::OwnedStdSps`]).
    pub fn std(&self) -> &hh::StdVideoH265SequenceParameterSet {
        &self.std
    }

    /// Lower `general_level_idc` to the device ceiling — [`OwnedStdH265Vps::clamp_level`]
    /// carries the argument.
    pub(crate) fn clamp_level(&mut self, max: hh::StdVideoH265LevelIdc) {
        if self._ptl_backing.general_level_idc > max {
            self._ptl_backing.general_level_idc = max;
        }
    }
}

/// The converted PPS plus the scaling-list allocation its `pScalingLists`
/// targets. Same ownership contract as [`crate::OwnedStdSps`].
#[derive(Debug)]
pub struct OwnedStdH265Pps {
    /// Boxed for [`OwnedStdH265Vps`]'s reason: `pStdPPSs` is this field's address.
    std: Box<hh::StdVideoH265PictureParameterSet>,
    _scaling_backing: Option<Box<hh::StdVideoH265ScalingLists>>,
}

impl OwnedStdH265Pps {
    /// The Std struct, valid for as long as `self` lives (see [`crate::OwnedStdSps`]).
    pub fn std(&self) -> &hh::StdVideoH265PictureParameterSet {
        &self.std
    }
}

/// H.265 `general_level_idc` (value-coded: 30 x the level number, Table A.8) to
/// Vulkan's index-coded `StdVideoH265LevelIdc`. The Std code points ascend with
/// the level, so a driver's `maxLevelIdc` gate compares them numerically.
pub(crate) const fn level_to_std(level: Level) -> hh::StdVideoH265LevelIdc {
    match level {
        Level::L1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_1_0,
        Level::L2 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_2_0,
        Level::L2_1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_2_1,
        Level::L3 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_3_0,
        Level::L3_1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_3_1,
        Level::L4 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_0,
        Level::L4_1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1,
        Level::L5 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_0,
        Level::L5_1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_1,
        Level::L5_2 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_2,
        Level::L6 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_0,
        Level::L6_1 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_1,
        Level::L6_2 => hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_2,
    }
}

/// `general_profile_idc` to `StdVideoH265ProfileIdc` — the code points equal the
/// profile_idc values they name, so recognised ones pass through.
///
/// (Visible to the crate because the GPU half's profile key
/// [`crate::caps_h265::H265ProfileKey`] must be built from the PICTURE's profile
/// idc before any parameter-set conversion runs — the caps query needs it — and
/// both must agree on the mapping.)
pub(crate) fn profile_to_std(idc: u8) -> Result<hh::StdVideoH265ProfileIdc, H265ParamsError> {
    match u32::from(idc) {
        p @ 1..=4 => Ok(p),
        _ => Err(H265ParamsError::UnmappableProfileIdc(idc)),
    }
}

/// profile_tier_level() to the Std block (always pointer-backed in VPS and SPS).
fn ptl_to_std(ptl: &ProfileTierLevel) -> Result<hh::StdVideoH265ProfileTierLevel, H265ParamsError> {
    // SAFETY: StdVideoH265ProfileTierLevel is a plain-C bindgen struct of a
    // bitfield word and two enum ints; all-zero is a valid value for every field.
    let mut std: hh::StdVideoH265ProfileTierLevel = unsafe { std::mem::zeroed() };
    std.flags
        .set_general_tier_flag(u32::from(ptl.general_tier_flag));
    std.flags
        .set_general_progressive_source_flag(u32::from(ptl.general_progressive_source_flag));
    std.flags
        .set_general_interlaced_source_flag(u32::from(ptl.general_interlaced_source_flag));
    std.flags
        .set_general_non_packed_constraint_flag(u32::from(ptl.general_non_packed_constraint_flag));
    std.flags
        .set_general_frame_only_constraint_flag(u32::from(ptl.general_frame_only_constraint_flag));
    std.general_profile_idc = profile_to_std(ptl.general_profile_idc)?;
    std.general_level_idc = level_to_std(ptl.general_level_idc);
    Ok(std)
}

/// Pack the parser's scaling lists into the Std layout.
///
/// The vendored parser has already run 7.4.5 in full — explicit coefficients,
/// matrix-id prediction (equation 7-42) and the Table 7-5/7-6 defaults — so the
/// arrays hold the fully RESOLVED lists (the H.264 module's idiom). Layout notes:
///
/// - 32x32 (sizeId 3) has exactly TWO lists, at parser matrix ids 0 (intra) and
///   3 (inter) — 7.4.5's loop steps matrixId by 3 there. The Std array holds them
///   compacted at indices 0 and 1.
/// - The Std DC fields carry the VALUE (`scaling_list_dc_coef_minus8 + 8`,
///   1..255), not the minus8 syntax element.
fn scaling_lists_to_std(
    lists: &ScalingLists,
) -> Result<hh::StdVideoH265ScalingLists, H265ParamsError> {
    // SAFETY: StdVideoH265ScalingLists is a plain-C bindgen struct of byte
    // arrays; all-zero is a valid value for every field.
    let mut std: hh::StdVideoH265ScalingLists = unsafe { std::mem::zeroed() };
    std.ScalingList4x4 = lists.scaling_list_4x4;
    std.ScalingList8x8 = lists.scaling_list_8x8;
    std.ScalingList16x16 = lists.scaling_list_16x16;
    std.ScalingList32x32 = [lists.scaling_list_32x32[0], lists.scaling_list_32x32[3]];
    for i in 0..6 {
        std.ScalingListDCCoef16x16[i] = narrow(
            "scaling_list_dc_coef_minus8_16x16 + 8",
            i32::from(lists.scaling_list_dc_coef_minus8_16x16[i]) + 8,
        )?;
    }
    for (dst, src) in [0usize, 3].into_iter().enumerate() {
        std.ScalingListDCCoef32x32[dst] = narrow(
            "scaling_list_dc_coef_minus8_32x32 + 8",
            i32::from(lists.scaling_list_dc_coef_minus8_32x32[src]) + 8,
        )?;
    }
    Ok(std)
}

/// One resolved SPS short-term RPS candidate re-encoded as a non-predicted Std
/// set (module docs: the parser flattened 7.4.8's prediction, so the prediction
/// flags stay 0 and the derived `DeltaPocSX` arrays encode back into
/// `delta_poc_sX_minus1` syntax — `DeltaPocS0` is strictly decreasing negative,
/// `DeltaPocS1` strictly increasing positive, so both step differences are the
/// positive minus1+1 values).
fn st_rps_to_std(
    index: usize,
    set: &ShortTermRefPicSet,
) -> Result<hh::StdVideoH265ShortTermRefPicSet, H265ParamsError> {
    let negative = usize::from(set.num_negative_pics);
    let positive = usize::from(set.num_positive_pics);
    if negative > 16 || positive > 16 {
        return Err(H265ParamsError::RpsEntryOverflow {
            set: index,
            negative: set.num_negative_pics,
            positive: set.num_positive_pics,
        });
    }

    // SAFETY: StdVideoH265ShortTermRefPicSet is a plain-C bindgen struct of a
    // bitfield word, integers and integer arrays; all-zero is valid for every
    // field and is exactly the non-predicted baseline (prediction flags 0).
    let mut std: hh::StdVideoH265ShortTermRefPicSet = unsafe { std::mem::zeroed() };
    std.num_negative_pics = set.num_negative_pics;
    std.num_positive_pics = set.num_positive_pics;

    // 7.4.8: the syntax steps are ue(v)-bounded at 2^15 - 1, so a legal step is
    // 1..=2^15; anything else cannot be re-encoded (fn docs).
    let mut prev: i64 = 0;
    for i in 0..negative {
        let cur = i64::from(set.delta_poc_s0[i]);
        let step = prev - cur;
        if !(1..=32768).contains(&step) {
            return Err(H265ParamsError::NonMonotonicRps { set: index });
        }
        std.delta_poc_s0_minus1[i] = (step - 1) as u16;
        if set.used_by_curr_pic_s0[i] {
            std.used_by_curr_pic_s0_flag |= 1 << i;
        }
        prev = cur;
    }
    let mut prev: i64 = 0;
    for i in 0..positive {
        let cur = i64::from(set.delta_poc_s1[i]);
        let step = cur - prev;
        if !(1..=32768).contains(&step) {
            return Err(H265ParamsError::NonMonotonicRps { set: index });
        }
        std.delta_poc_s1_minus1[i] = (step - 1) as u16;
        if set.used_by_curr_pic_s1[i] {
            std.used_by_curr_pic_s1_flag |= 1 << i;
        }
        prev = cur;
    }
    Ok(std)
}

/// The envelope + representability gate every conversion path shares: profile,
/// chroma format and bit depth (struct docs on the error type for the WHY of
/// each). Runs before any allocation so a rejection is cheap and total.
fn check_envelope(sps: &Sps) -> Result<(), H265ParamsError> {
    profile_to_std(sps.profile_tier_level.general_profile_idc)?;
    if sps.chroma_format_idc > 3 {
        return Err(H265ParamsError::InvalidChromaFormatIdc(
            sps.chroma_format_idc,
        ));
    }
    if sps.chroma_format_idc == 0 || sps.chroma_format_idc == 2 {
        return Err(H265ParamsError::UnsupportedChromaFormat(
            sps.chroma_format_idc,
        ));
    }
    // 4:4:4 with separate colour planes is ChromaArrayType 0 in disguise — three
    // monochrome-coded planes. No punktfunk output format can carry it and most
    // decode hardware refuses it; letting it through would fail later at the
    // driver (or worse, map planes wrongly) — the silent class this envelope
    // exists to catch.
    if sps.chroma_format_idc == 3 && sps.separate_colour_plane_flag {
        return Err(H265ParamsError::SeparateColourPlanes);
    }
    if sps.bit_depth_luma_minus8 != sps.bit_depth_chroma_minus8
        || !matches!(sps.bit_depth_luma_minus8, 0 | 2)
    {
        return Err(H265ParamsError::UnsupportedBitDepth {
            luma_minus8: sps.bit_depth_luma_minus8,
            chroma_minus8: sps.bit_depth_chroma_minus8,
        });
    }
    if sps
        .scc_extension
        .palette_predictor_initializers_present_flag
    {
        return Err(H265ParamsError::PalettePredictorInitializers);
    }
    Ok(())
}

/// Convert one VPS into the Std struct (owning wrapper). HRD/timing is skipped by
/// design (module docs); the DPB manager and profile/tier/level blocks ride
/// behind owned pointers.
pub fn vps_to_std_h265(vps: &Vps) -> Result<OwnedStdH265Vps, H265ParamsError> {
    let ptl_backing = Box::new(ptl_to_std(&vps.profile_tier_level)?);

    // SAFETY: StdVideoH265DecPicBufMgr is a plain-C bindgen struct of integer
    // arrays; all-zero is a valid value for every field.
    let mut dpb: hh::StdVideoH265DecPicBufMgr = unsafe { std::mem::zeroed() };
    dpb.max_latency_increase_plus1 = vps.max_latency_increase_plus1;
    for i in 0..7 {
        // The VPS arrays are u32 in the parser; the spec bounds both syntax
        // elements well inside u8 (MaxDpbSize <= 16), so an overflow is corrupt.
        dpb.max_dec_pic_buffering_minus1[i] = narrow(
            "vps_max_dec_pic_buffering_minus1",
            vps.max_dec_pic_buffering_minus1[i],
        )?;
        dpb.max_num_reorder_pics[i] =
            narrow("vps_max_num_reorder_pics", vps.max_num_reorder_pics[i])?;
    }
    let dpb_backing = Box::new(dpb);

    // SAFETY: StdVideoH265VideoParameterSet is a plain-C bindgen struct of a
    // bitfield word, integers and const pointers; all-zero is valid for every
    // field (null pointers) and is the baseline the writes below fill.
    let mut std: hh::StdVideoH265VideoParameterSet = unsafe { std::mem::zeroed() };
    std.flags
        .set_vps_temporal_id_nesting_flag(u32::from(vps.temporal_id_nesting_flag));
    std.flags
        .set_vps_sub_layer_ordering_info_present_flag(u32::from(
            vps.sub_layer_ordering_info_present_flag,
        ));
    // vps_timing_info_present_flag and vps_poc_proportional_to_timing_flag stay
    // 0 with their fields: the HRD/timing skip (module docs) must be
    // self-consistent — a present-flag over a null pHrdParameters would be the
    // exact half-truth this module exists to avoid.
    std.vps_video_parameter_set_id = vps.video_parameter_set_id;
    std.vps_max_sub_layers_minus1 = vps.max_sub_layers_minus1;
    std.pDecPicBufMgr = &*dpb_backing;
    std.pProfileTierLevel = &*ptl_backing;

    Ok(OwnedStdH265Vps {
        std: Box::new(std),
        _ptl_backing: ptl_backing,
        _dpb_backing: dpb_backing,
    })
}

/// A minimal Std VPS synthesized from the SPS that references it, for streams
/// whose VPS NALU was lost upstream (the parser attaches the VPS to the SPS only
/// when it saw one — `sps.vps` is `None` otherwise). Every stream is REQUIRED to
/// carry a VPS (7.4.2.1), and Vulkan requires the parameters object to hold the
/// VPS the SPS names, so the session layer needs SOMETHING to add; this fallback
/// carries exactly the facts the SPS restates (ids, sub-layer count,
/// profile/tier/level, DPB sizing) — which is also everything a decode session
/// could consult, since the VPS's own additions (timing, layer sets) are all in
/// the deliberate-skip category (module docs).
pub fn fallback_vps_from_sps(sps: &Sps) -> Result<OwnedStdH265Vps, H265ParamsError> {
    let ptl_backing = Box::new(ptl_to_std(&sps.profile_tier_level)?);
    let dpb_backing = Box::new(sps_dec_pic_buf_mgr(sps));

    // SAFETY: as in vps_to_std_h265 — all-zero is a valid baseline.
    let mut std: hh::StdVideoH265VideoParameterSet = unsafe { std::mem::zeroed() };
    std.vps_video_parameter_set_id = sps.video_parameter_set_id;
    std.vps_max_sub_layers_minus1 = sps.max_sub_layers_minus1;
    std.flags
        .set_vps_temporal_id_nesting_flag(u32::from(sps.temporal_id_nesting_flag));
    std.flags
        .set_vps_sub_layer_ordering_info_present_flag(u32::from(
            sps.sub_layer_ordering_info_present_flag,
        ));
    std.pDecPicBufMgr = &*dpb_backing;
    std.pProfileTierLevel = &*ptl_backing;

    Ok(OwnedStdH265Vps {
        std: Box::new(std),
        _ptl_backing: ptl_backing,
        _dpb_backing: dpb_backing,
    })
}

/// The SPS's sub-layer ordering arrays as the Std DPB-manager block. Infallible:
/// the parser's SPS arrays are already `u8` where the Std block wants `u8`.
fn sps_dec_pic_buf_mgr(sps: &Sps) -> hh::StdVideoH265DecPicBufMgr {
    // SAFETY: plain-C bindgen struct of integer arrays; all-zero is valid.
    let mut dpb: hh::StdVideoH265DecPicBufMgr = unsafe { std::mem::zeroed() };
    for i in 0..7 {
        dpb.max_latency_increase_plus1[i] = u32::from(sps.max_latency_increase_plus1[i]);
    }
    dpb.max_dec_pic_buffering_minus1 = sps.max_dec_pic_buffering_minus1;
    dpb.max_num_reorder_pics = sps.max_num_reorder_pics;
    dpb
}

/// Convert one SPS into the Std struct (owning wrapper), mapping every field the
/// H.265 decode profile consumes. VUI is skipped by design; SCC palette data is
/// rejected, never dropped (module docs).
pub fn sps_to_std_h265(sps: &Sps) -> Result<OwnedStdH265Sps, H265ParamsError> {
    check_envelope(sps)?;
    if sps.num_short_term_ref_pic_sets > 64 {
        return Err(H265ParamsError::TooManyShortTermRpsSets(
            sps.num_short_term_ref_pic_sets,
        ));
    }
    if sps.num_long_term_ref_pics_sps > 32 {
        return Err(H265ParamsError::TooManyLongTermSpsPics(
            sps.num_long_term_ref_pics_sps,
        ));
    }

    let ptl_backing = Box::new(ptl_to_std(&sps.profile_tier_level)?);
    let dpb_backing = Box::new(sps_dec_pic_buf_mgr(sps));

    let scaling_backing = sps
        .scaling_list_data_present_flag
        .then(|| scaling_lists_to_std(&sps.scaling_list).map(Box::new))
        .transpose()?;

    // The COUNT field and the pointer derive from the one condition (the H.264
    // module's stale-count rule): a declared candidate count only ever rides
    // over a real array of exactly that many converted sets.
    let st_rps_backing = (sps.num_short_term_ref_pic_sets > 0)
        .then(
            || -> Result<Box<[hh::StdVideoH265ShortTermRefPicSet]>, H265ParamsError> {
                let count = usize::from(sps.num_short_term_ref_pic_sets);
                let mut sets = Vec::with_capacity(count);
                for index in 0..count {
                    let set = sps
                        .short_term_ref_pic_set
                        .get(index)
                        .ok_or(H265ParamsError::MissingShortTermRps { index })?;
                    sets.push(st_rps_to_std(index, set)?);
                }
                Ok(sets.into_boxed_slice())
            },
        )
        .transpose()?;

    // Backed whenever the FLAG is set, even with zero SPS candidates: the header
    // annotates `pLongTermRefPicsSps` "must be a valid pointer if
    // long_term_ref_pics_present_flag is set", and FFmpeg's vulkan_hevc passes it
    // unconditionally — a set flag over a null pointer is untested territory in
    // every driver. `flag=1, num=0` is not a corner case here: it is exactly the
    // punktfunk LTR/RFI-recovery stream shape (slice-signalled long-term pics,
    // no SPS candidates — pf-bitstream's own LTR synthesizer emits it), so the
    // all-zero struct (the correct content for num=0) must be present.
    let lt_backing = sps.long_term_ref_pics_present_flag.then(|| {
        // SAFETY: plain-C bindgen struct of a mask and an integer array;
        // all-zero is valid.
        let mut lt: hh::StdVideoH265LongTermRefPicsSps = unsafe { std::mem::zeroed() };
        for i in 0..usize::from(sps.num_long_term_ref_pics_sps) {
            if sps.used_by_curr_pic_lt_sps_flag[i] {
                lt.used_by_curr_pic_lt_sps_flag |= 1 << i;
            }
        }
        lt.lt_ref_pic_poc_lsb_sps = sps.lt_ref_pic_poc_lsb_sps;
        Box::new(lt)
    });

    // SAFETY: StdVideoH265SequenceParameterSet is a plain-C bindgen struct of a
    // bitfield word, integers and const pointers; all-zero is valid for every
    // field (null pointers) and is the "everything absent" baseline the field
    // writes below build on. Same idiom as the H.264 module.
    let mut std: hh::StdVideoH265SequenceParameterSet = unsafe { std::mem::zeroed() };

    std.flags
        .set_sps_temporal_id_nesting_flag(u32::from(sps.temporal_id_nesting_flag));
    std.flags
        .set_separate_colour_plane_flag(u32::from(sps.separate_colour_plane_flag));
    std.flags
        .set_conformance_window_flag(u32::from(sps.conformance_window_flag));
    std.flags
        .set_sps_sub_layer_ordering_info_present_flag(u32::from(
            sps.sub_layer_ordering_info_present_flag,
        ));
    std.flags
        .set_scaling_list_enabled_flag(u32::from(sps.scaling_list_enabled_flag));
    // When enabled-but-absent, the driver applies the Table 7-5/7-6 defaults
    // itself (7.4.5's inference) — declaring data we did not convert would be
    // wrong in exactly the way the null-pointer/flag pairing rules forbid.
    std.flags
        .set_sps_scaling_list_data_present_flag(u32::from(sps.scaling_list_data_present_flag));
    std.flags
        .set_amp_enabled_flag(u32::from(sps.amp_enabled_flag));
    std.flags.set_sample_adaptive_offset_enabled_flag(u32::from(
        sps.sample_adaptive_offset_enabled_flag,
    ));
    std.flags
        .set_pcm_enabled_flag(u32::from(sps.pcm_enabled_flag));
    std.flags
        .set_pcm_loop_filter_disabled_flag(u32::from(sps.pcm_loop_filter_disabled_flag));
    std.flags
        .set_long_term_ref_pics_present_flag(u32::from(sps.long_term_ref_pics_present_flag));
    std.flags
        .set_sps_temporal_mvp_enabled_flag(u32::from(sps.temporal_mvp_enabled_flag));
    std.flags.set_strong_intra_smoothing_enabled_flag(u32::from(
        sps.strong_intra_smoothing_enabled_flag,
    ));
    // vui_parameters_present_flag stays 0: decode sessions consume no VUI
    // (module docs); colour rides the PicturePlan.
    std.flags
        .set_sps_extension_present_flag(u32::from(sps.extension_present_flag));
    std.flags
        .set_sps_range_extension_flag(u32::from(sps.range_extension_flag));
    let rext = &sps.range_extension;
    std.flags
        .set_transform_skip_rotation_enabled_flag(u32::from(
            rext.transform_skip_rotation_enabled_flag,
        ));
    std.flags.set_transform_skip_context_enabled_flag(u32::from(
        rext.transform_skip_context_enabled_flag,
    ));
    std.flags
        .set_implicit_rdpcm_enabled_flag(u32::from(rext.implicit_rdpcm_enabled_flag));
    std.flags
        .set_explicit_rdpcm_enabled_flag(u32::from(rext.explicit_rdpcm_enabled_flag));
    std.flags
        .set_extended_precision_processing_flag(u32::from(rext.extended_precision_processing_flag));
    std.flags
        .set_intra_smoothing_disabled_flag(u32::from(rext.intra_smoothing_disabled_flag));
    std.flags.set_high_precision_offsets_enabled_flag(u32::from(
        rext.high_precision_offsets_enabled_flag,
    ));
    std.flags
        .set_persistent_rice_adaptation_enabled_flag(u32::from(
            rext.persistent_rice_adaptation_enabled_flag,
        ));
    std.flags.set_cabac_bypass_alignment_enabled_flag(u32::from(
        rext.cabac_bypass_alignment_enabled_flag,
    ));
    let scc = &sps.scc_extension;
    std.flags
        .set_sps_scc_extension_flag(u32::from(sps.scc_extension_flag));
    // Faithful even though the planner's envelope gate rejects SCC
    // self-referencing before a plan exists — conversion is not envelope-coupled
    // beyond its own representability (the H.264 frame_mbs_only precedent).
    std.flags
        .set_sps_curr_pic_ref_enabled_flag(u32::from(scc.curr_pic_ref_enabled_flag));
    std.flags
        .set_palette_mode_enabled_flag(u32::from(scc.palette_mode_enabled_flag));
    // sps_palette_predictor_initializers_present_flag stays 0: check_envelope
    // rejected any SPS that sets it, so flag and (null) pPredictorPaletteEntries
    // can never disagree.
    std.flags
        .set_intra_boundary_filtering_disabled_flag(u32::from(
            scc.intra_boundary_filtering_disabled_flag,
        ));

    // Chroma format code points equal the chroma_format_idc values (0..3).
    std.chroma_format_idc = u32::from(sps.chroma_format_idc);
    std.pic_width_in_luma_samples = u32::from(sps.pic_width_in_luma_samples);
    std.pic_height_in_luma_samples = u32::from(sps.pic_height_in_luma_samples);
    std.sps_video_parameter_set_id = sps.video_parameter_set_id;
    std.sps_max_sub_layers_minus1 = sps.max_sub_layers_minus1;
    std.sps_seq_parameter_set_id = sps.seq_parameter_set_id;
    std.bit_depth_luma_minus8 = sps.bit_depth_luma_minus8;
    std.bit_depth_chroma_minus8 = sps.bit_depth_chroma_minus8;
    std.log2_max_pic_order_cnt_lsb_minus4 = sps.log2_max_pic_order_cnt_lsb_minus4;
    std.log2_min_luma_coding_block_size_minus3 = sps.log2_min_luma_coding_block_size_minus3;
    std.log2_diff_max_min_luma_coding_block_size = sps.log2_diff_max_min_luma_coding_block_size;
    std.log2_min_luma_transform_block_size_minus2 = sps.log2_min_luma_transform_block_size_minus2;
    std.log2_diff_max_min_luma_transform_block_size =
        sps.log2_diff_max_min_luma_transform_block_size;
    std.max_transform_hierarchy_depth_inter = sps.max_transform_hierarchy_depth_inter;
    std.max_transform_hierarchy_depth_intra = sps.max_transform_hierarchy_depth_intra;
    std.num_short_term_ref_pic_sets = sps.num_short_term_ref_pic_sets;
    std.num_long_term_ref_pics_sps = sps.num_long_term_ref_pics_sps;
    std.pcm_sample_bit_depth_luma_minus1 = sps.pcm_sample_bit_depth_luma_minus1;
    std.pcm_sample_bit_depth_chroma_minus1 = sps.pcm_sample_bit_depth_chroma_minus1;
    std.log2_min_pcm_luma_coding_block_size_minus3 = sps.log2_min_pcm_luma_coding_block_size_minus3;
    std.log2_diff_max_min_pcm_luma_coding_block_size =
        sps.log2_diff_max_min_pcm_luma_coding_block_size;
    std.palette_max_size = scc.palette_max_size;
    std.delta_palette_max_predictor_size = scc.delta_palette_max_predictor_size;
    std.motion_vector_resolution_control_idc = scc.motion_vector_resolution_control_idc;
    std.sps_num_palette_predictor_initializers_minus1 =
        scc.num_palette_predictor_initializer_minus1;
    std.conf_win_left_offset = sps.conf_win_left_offset;
    std.conf_win_right_offset = sps.conf_win_right_offset;
    std.conf_win_top_offset = sps.conf_win_top_offset;
    std.conf_win_bottom_offset = sps.conf_win_bottom_offset;

    std.pProfileTierLevel = &*ptl_backing;
    std.pDecPicBufMgr = &*dpb_backing;
    if let Some(backing) = &scaling_backing {
        std.pScalingLists = &**backing;
    }
    if let Some(backing) = &st_rps_backing {
        std.pShortTermRefPicSet = backing.as_ptr();
    }
    if let Some(backing) = &lt_backing {
        std.pLongTermRefPicsSps = &**backing;
    }
    // pSequenceParameterSetVui and pPredictorPaletteEntries stay null (module
    // docs / check_envelope).

    Ok(OwnedStdH265Sps {
        std: Box::new(std),
        _ptl_backing: ptl_backing,
        _dpb_backing: dpb_backing,
        _scaling_backing: scaling_backing,
        _st_rps_backing: st_rps_backing,
        _lt_backing: lt_backing,
    })
}

/// Convert one PPS into the Std struct (owning wrapper), mapping every field the
/// H.265 decode profile consumes. SCC palette data is rejected, never dropped;
/// every narrower Std field is checked, never truncated.
pub fn pps_to_std_h265(pps: &Pps) -> Result<OwnedStdH265Pps, H265ParamsError> {
    if pps
        .scc_extension
        .palette_predictor_initializers_present_flag
    {
        return Err(H265ParamsError::PalettePredictorInitializers);
    }

    let scaling_backing = pps
        .scaling_list_data_present_flag
        .then(|| scaling_lists_to_std(&pps.scaling_list).map(Box::new))
        .transpose()?;

    // SAFETY: StdVideoH265PictureParameterSet is a plain-C bindgen struct of a
    // bitfield word, integers, integer arrays and const pointers; all-zero is
    // valid for every field (null pointers) and is the baseline the writes fill.
    let mut std: hh::StdVideoH265PictureParameterSet = unsafe { std::mem::zeroed() };

    std.flags
        .set_dependent_slice_segments_enabled_flag(u32::from(
            pps.dependent_slice_segments_enabled_flag,
        ));
    std.flags
        .set_output_flag_present_flag(u32::from(pps.output_flag_present_flag));
    std.flags
        .set_sign_data_hiding_enabled_flag(u32::from(pps.sign_data_hiding_enabled_flag));
    std.flags
        .set_cabac_init_present_flag(u32::from(pps.cabac_init_present_flag));
    std.flags
        .set_constrained_intra_pred_flag(u32::from(pps.constrained_intra_pred_flag));
    std.flags
        .set_transform_skip_enabled_flag(u32::from(pps.transform_skip_enabled_flag));
    std.flags
        .set_cu_qp_delta_enabled_flag(u32::from(pps.cu_qp_delta_enabled_flag));
    std.flags
        .set_pps_slice_chroma_qp_offsets_present_flag(u32::from(
            pps.slice_chroma_qp_offsets_present_flag,
        ));
    std.flags
        .set_weighted_pred_flag(u32::from(pps.weighted_pred_flag));
    std.flags
        .set_weighted_bipred_flag(u32::from(pps.weighted_bipred_flag));
    std.flags
        .set_transquant_bypass_enabled_flag(u32::from(pps.transquant_bypass_enabled_flag));
    std.flags
        .set_tiles_enabled_flag(u32::from(pps.tiles_enabled_flag));
    std.flags
        .set_entropy_coding_sync_enabled_flag(u32::from(pps.entropy_coding_sync_enabled_flag));
    std.flags
        .set_uniform_spacing_flag(u32::from(pps.uniform_spacing_flag));
    std.flags
        .set_loop_filter_across_tiles_enabled_flag(u32::from(
            pps.loop_filter_across_tiles_enabled_flag,
        ));
    std.flags
        .set_pps_loop_filter_across_slices_enabled_flag(u32::from(
            pps.loop_filter_across_slices_enabled_flag,
        ));
    std.flags
        .set_deblocking_filter_control_present_flag(u32::from(
            pps.deblocking_filter_control_present_flag,
        ));
    std.flags
        .set_deblocking_filter_override_enabled_flag(u32::from(
            pps.deblocking_filter_override_enabled_flag,
        ));
    std.flags
        .set_pps_deblocking_filter_disabled_flag(u32::from(pps.deblocking_filter_disabled_flag));
    std.flags
        .set_pps_scaling_list_data_present_flag(u32::from(pps.scaling_list_data_present_flag));
    std.flags
        .set_lists_modification_present_flag(u32::from(pps.lists_modification_present_flag));
    std.flags
        .set_slice_segment_header_extension_present_flag(u32::from(
            pps.slice_segment_header_extension_present_flag,
        ));
    std.flags
        .set_pps_extension_present_flag(u32::from(pps.extension_present_flag));
    let rext = &pps.range_extension;
    std.flags
        .set_cross_component_prediction_enabled_flag(u32::from(
            rext.cross_component_prediction_enabled_flag,
        ));
    std.flags
        .set_chroma_qp_offset_list_enabled_flag(u32::from(rext.chroma_qp_offset_list_enabled_flag));
    let scc = &pps.scc_extension;
    std.flags
        .set_pps_curr_pic_ref_enabled_flag(u32::from(scc.curr_pic_ref_enabled_flag));
    std.flags
        .set_residual_adaptive_colour_transform_enabled_flag(u32::from(
            scc.residual_adaptive_colour_transform_enabled_flag,
        ));
    std.flags
        .set_pps_slice_act_qp_offsets_present_flag(u32::from(
            scc.slice_act_qp_offsets_present_flag,
        ));
    // pps_palette_predictor_initializers_present_flag stays 0 (rejected above).
    std.flags
        .set_monochrome_palette_flag(u32::from(scc.monochrome_palette_flag));
    std.flags
        .set_pps_range_extension_flag(u32::from(pps.range_extension_flag));

    std.pps_pic_parameter_set_id = pps.pic_parameter_set_id;
    std.pps_seq_parameter_set_id = pps.seq_parameter_set_id;
    // The VPS id the Std PPS names is the one its OWN SPS references — the
    // parser resolved that chain at parse time.
    std.sps_video_parameter_set_id = pps.sps.video_parameter_set_id;
    std.num_extra_slice_header_bits = pps.num_extra_slice_header_bits;
    std.num_ref_idx_l0_default_active_minus1 = pps.num_ref_idx_l0_default_active_minus1;
    std.num_ref_idx_l1_default_active_minus1 = pps.num_ref_idx_l1_default_active_minus1;
    std.init_qp_minus26 = pps.init_qp_minus26;
    std.diff_cu_qp_delta_depth = pps.diff_cu_qp_delta_depth;
    std.pps_cb_qp_offset = pps.cb_qp_offset;
    std.pps_cr_qp_offset = pps.cr_qp_offset;
    std.pps_beta_offset_div2 = pps.beta_offset_div2;
    std.pps_tc_offset_div2 = pps.tc_offset_div2;
    std.log2_parallel_merge_level_minus2 = pps.log2_parallel_merge_level_minus2;
    std.log2_max_transform_skip_block_size_minus2 = narrow(
        "log2_max_transform_skip_block_size_minus2",
        rext.log2_max_transform_skip_block_size_minus2,
    )?;
    std.diff_cu_chroma_qp_offset_depth = narrow(
        "diff_cu_chroma_qp_offset_depth",
        rext.diff_cu_chroma_qp_offset_depth,
    )?;
    std.chroma_qp_offset_list_len_minus1 = narrow(
        "chroma_qp_offset_list_len_minus1",
        rext.chroma_qp_offset_list_len_minus1,
    )?;
    for i in 0..6 {
        std.cb_qp_offset_list[i] = narrow("cb_qp_offset_list", rext.cb_qp_offset_list[i])?;
        std.cr_qp_offset_list[i] = narrow("cr_qp_offset_list", rext.cr_qp_offset_list[i])?;
    }
    std.log2_sao_offset_scale_luma = narrow(
        "log2_sao_offset_scale_luma",
        rext.log2_sao_offset_scale_luma,
    )?;
    std.log2_sao_offset_scale_chroma = narrow(
        "log2_sao_offset_scale_chroma",
        rext.log2_sao_offset_scale_chroma,
    )?;
    std.pps_act_y_qp_offset_plus5 = scc.act_y_qp_offset_plus5;
    std.pps_act_cb_qp_offset_plus5 = scc.act_cb_qp_offset_plus5;
    std.pps_act_cr_qp_offset_plus3 = scc.act_cr_qp_offset_plus3;
    std.pps_num_palette_predictor_initializers = scc.num_palette_predictor_initializers;
    std.luma_bit_depth_entry_minus8 = scc.luma_bit_depth_entry_minus8;
    std.chroma_bit_depth_entry_minus8 = scc.chroma_bit_depth_entry_minus8;
    std.num_tile_columns_minus1 = pps.num_tile_columns_minus1;
    std.num_tile_rows_minus1 = pps.num_tile_rows_minus1;
    for i in 0..19 {
        std.column_width_minus1[i] = narrow("column_width_minus1", pps.column_width_minus1[i])?;
    }
    for i in 0..21 {
        std.row_height_minus1[i] = narrow("row_height_minus1", pps.row_height_minus1[i])?;
    }

    if let Some(backing) = &scaling_backing {
        std.pScalingLists = &**backing;
    }
    // pPredictorPaletteEntries stays null (rejected above).

    Ok(OwnedStdH265Pps {
        std: Box::new(std),
        _scaling_backing: scaling_backing,
    })
}

#[cfg(test)]
mod tests {
    use cros_codecs::codec::h265::parser::PpsRangeExtension;
    use cros_codecs::codec::h265::parser::PpsSccExtension;
    use cros_codecs::codec::h265::parser::ProfileTierLevel;
    use cros_codecs::codec::h265::parser::SpsRangeExtension;
    use std::rc::Rc;

    use super::*;

    /// An SPS exercising every mapped field with distinct values. Flags carry a
    /// deliberate mixed pattern asserted bit-for-bit below;
    /// `vui_parameters_present_flag` is true at the SOURCE precisely because the
    /// conversion must NOT copy it (the VUI skip).
    fn full_sps() -> Sps {
        Sps {
            video_parameter_set_id: 2,
            max_sub_layers_minus1: 1,
            temporal_id_nesting_flag: true,
            profile_tier_level: ProfileTierLevel {
                general_profile_idc: 2, // Main 10
                general_tier_flag: true,
                general_progressive_source_flag: true,
                general_interlaced_source_flag: false,
                general_non_packed_constraint_flag: true,
                general_frame_only_constraint_flag: false,
                general_level_idc: Level::L4_1,
                ..Default::default()
            },
            seq_parameter_set_id: 5,
            chroma_format_idc: 1,
            pic_width_in_luma_samples: 1920,
            pic_height_in_luma_samples: 1080,
            conformance_window_flag: true,
            conf_win_left_offset: 1,
            conf_win_right_offset: 2,
            conf_win_top_offset: 3,
            conf_win_bottom_offset: 4,
            bit_depth_luma_minus8: 2,
            bit_depth_chroma_minus8: 2,
            log2_max_pic_order_cnt_lsb_minus4: 6,
            sub_layer_ordering_info_present_flag: true,
            max_dec_pic_buffering_minus1: [5, 6, 0, 0, 0, 0, 0],
            max_num_reorder_pics: [1, 2, 0, 0, 0, 0, 0],
            max_latency_increase_plus1: [7, 8, 0, 0, 0, 0, 0],
            log2_min_luma_coding_block_size_minus3: 1,
            log2_diff_max_min_luma_coding_block_size: 2,
            log2_min_luma_transform_block_size_minus2: 1,
            log2_diff_max_min_luma_transform_block_size: 3,
            max_transform_hierarchy_depth_inter: 2,
            max_transform_hierarchy_depth_intra: 3,
            scaling_list_enabled_flag: true,
            scaling_list_data_present_flag: false,
            amp_enabled_flag: true,
            sample_adaptive_offset_enabled_flag: false,
            pcm_enabled_flag: true,
            pcm_sample_bit_depth_luma_minus1: 7,
            pcm_sample_bit_depth_chroma_minus1: 9,
            log2_min_pcm_luma_coding_block_size_minus3: 1,
            log2_diff_max_min_pcm_luma_coding_block_size: 2,
            pcm_loop_filter_disabled_flag: true,
            num_short_term_ref_pic_sets: 0,
            long_term_ref_pics_present_flag: false,
            temporal_mvp_enabled_flag: true,
            strong_intra_smoothing_enabled_flag: false,
            vui_parameters_present_flag: true,
            extension_present_flag: true,
            range_extension_flag: true,
            range_extension: SpsRangeExtension {
                transform_skip_rotation_enabled_flag: true,
                transform_skip_context_enabled_flag: false,
                implicit_rdpcm_enabled_flag: true,
                explicit_rdpcm_enabled_flag: false,
                extended_precision_processing_flag: true,
                intra_smoothing_disabled_flag: false,
                high_precision_offsets_enabled_flag: true,
                persistent_rice_adaptation_enabled_flag: false,
                cabac_bypass_alignment_enabled_flag: true,
            },
            ..Default::default()
        }
    }

    /// A PPS over `sps` exercising every mapped field with distinct values —
    /// the vendored `Pps` derives no `Default`, so the literal is spelled out
    /// once here (the h264 `full_pps` idiom).
    fn full_pps(sps: Sps) -> Pps {
        Pps {
            pic_parameter_set_id: 3,
            seq_parameter_set_id: 5,
            dependent_slice_segments_enabled_flag: true,
            output_flag_present_flag: false,
            num_extra_slice_header_bits: 2,
            sign_data_hiding_enabled_flag: true,
            cabac_init_present_flag: false,
            num_ref_idx_l0_default_active_minus1: 2,
            num_ref_idx_l1_default_active_minus1: 1,
            init_qp_minus26: -3,
            constrained_intra_pred_flag: true,
            transform_skip_enabled_flag: false,
            cu_qp_delta_enabled_flag: true,
            diff_cu_qp_delta_depth: 2,
            cb_qp_offset: -4,
            cr_qp_offset: 5,
            slice_chroma_qp_offsets_present_flag: false,
            weighted_pred_flag: true,
            weighted_bipred_flag: false,
            transquant_bypass_enabled_flag: true,
            tiles_enabled_flag: true,
            entropy_coding_sync_enabled_flag: false,
            num_tile_columns_minus1: 1,
            num_tile_rows_minus1: 2,
            uniform_spacing_flag: false,
            column_width_minus1: {
                let mut w = [0u32; 19];
                w[0] = 17;
                w[1] = 12;
                w
            },
            row_height_minus1: {
                let mut h = [0u32; 21];
                h[0] = 9;
                h[1] = 8;
                h[2] = 16;
                h
            },
            loop_filter_across_tiles_enabled_flag: true,
            loop_filter_across_slices_enabled_flag: false,
            deblocking_filter_control_present_flag: true,
            deblocking_filter_override_enabled_flag: false,
            deblocking_filter_disabled_flag: true,
            beta_offset_div2: -2,
            tc_offset_div2: 3,
            scaling_list_data_present_flag: false,
            scaling_list: Default::default(),
            lists_modification_present_flag: true,
            log2_parallel_merge_level_minus2: 1,
            slice_segment_header_extension_present_flag: false,
            extension_present_flag: true,
            range_extension_flag: true,
            range_extension: PpsRangeExtension {
                log2_max_transform_skip_block_size_minus2: 2,
                cross_component_prediction_enabled_flag: true,
                chroma_qp_offset_list_enabled_flag: true,
                diff_cu_chroma_qp_offset_depth: 1,
                chroma_qp_offset_list_len_minus1: 1,
                cb_qp_offset_list: [1, -2, 0, 0, 0, 0],
                cr_qp_offset_list: [-3, 4, 0, 0, 0, 0],
                log2_sao_offset_scale_luma: 1,
                log2_sao_offset_scale_chroma: 2,
            },
            scc_extension_flag: false,
            scc_extension: PpsSccExtension::default(),
            qp_bd_offset_y: 0,
            sps: Rc::new(sps),
        }
    }

    #[test]
    fn every_mapped_sps_field_and_flag_round_trips_exactly() {
        let sps = full_sps();
        let owned = sps_to_std_h265(&sps).unwrap();
        let std = owned.std();

        // The fixture's mixed pattern, bit for bit.
        assert_eq!(std.flags.sps_temporal_id_nesting_flag(), 1);
        assert_eq!(std.flags.separate_colour_plane_flag(), 0);
        assert_eq!(std.flags.conformance_window_flag(), 1);
        assert_eq!(std.flags.sps_sub_layer_ordering_info_present_flag(), 1);
        assert_eq!(std.flags.scaling_list_enabled_flag(), 1);
        assert_eq!(std.flags.sps_scaling_list_data_present_flag(), 0);
        assert_eq!(std.flags.amp_enabled_flag(), 1);
        assert_eq!(std.flags.sample_adaptive_offset_enabled_flag(), 0);
        assert_eq!(std.flags.pcm_enabled_flag(), 1);
        assert_eq!(std.flags.pcm_loop_filter_disabled_flag(), 1);
        assert_eq!(std.flags.long_term_ref_pics_present_flag(), 0);
        assert_eq!(std.flags.sps_temporal_mvp_enabled_flag(), 1);
        assert_eq!(std.flags.strong_intra_smoothing_enabled_flag(), 0);
        assert_eq!(
            std.flags.vui_parameters_present_flag(),
            0,
            "true at the source, skipped by design"
        );
        assert_eq!(std.flags.sps_extension_present_flag(), 1);
        assert_eq!(std.flags.sps_range_extension_flag(), 1);
        // The range-extension flags, alternating T/F per the fixture.
        assert_eq!(std.flags.transform_skip_rotation_enabled_flag(), 1);
        assert_eq!(std.flags.transform_skip_context_enabled_flag(), 0);
        assert_eq!(std.flags.implicit_rdpcm_enabled_flag(), 1);
        assert_eq!(std.flags.explicit_rdpcm_enabled_flag(), 0);
        assert_eq!(std.flags.extended_precision_processing_flag(), 1);
        assert_eq!(std.flags.intra_smoothing_disabled_flag(), 0);
        assert_eq!(std.flags.high_precision_offsets_enabled_flag(), 1);
        assert_eq!(std.flags.persistent_rice_adaptation_enabled_flag(), 0);
        assert_eq!(std.flags.cabac_bypass_alignment_enabled_flag(), 1);
        assert_eq!(std.flags.sps_scc_extension_flag(), 0);
        assert_eq!(std.flags.sps_curr_pic_ref_enabled_flag(), 0);
        assert_eq!(std.flags.palette_mode_enabled_flag(), 0);
        assert_eq!(
            std.flags.sps_palette_predictor_initializers_present_flag(),
            0
        );
        assert_eq!(std.flags.intra_boundary_filtering_disabled_flag(), 0);

        assert_eq!(
            std.chroma_format_idc,
            hh::StdVideoH265ChromaFormatIdc_STD_VIDEO_H265_CHROMA_FORMAT_IDC_420
        );
        assert_eq!(std.pic_width_in_luma_samples, 1920);
        assert_eq!(std.pic_height_in_luma_samples, 1080);
        assert_eq!(std.sps_video_parameter_set_id, 2);
        assert_eq!(std.sps_max_sub_layers_minus1, 1);
        assert_eq!(std.sps_seq_parameter_set_id, 5);
        assert_eq!(std.bit_depth_luma_minus8, 2);
        assert_eq!(std.bit_depth_chroma_minus8, 2);
        assert_eq!(std.log2_max_pic_order_cnt_lsb_minus4, 6);
        assert_eq!(std.log2_min_luma_coding_block_size_minus3, 1);
        assert_eq!(std.log2_diff_max_min_luma_coding_block_size, 2);
        assert_eq!(std.log2_min_luma_transform_block_size_minus2, 1);
        assert_eq!(std.log2_diff_max_min_luma_transform_block_size, 3);
        assert_eq!(std.max_transform_hierarchy_depth_inter, 2);
        assert_eq!(std.max_transform_hierarchy_depth_intra, 3);
        assert_eq!(std.num_short_term_ref_pic_sets, 0);
        assert_eq!(std.num_long_term_ref_pics_sps, 0);
        assert_eq!(std.pcm_sample_bit_depth_luma_minus1, 7);
        assert_eq!(
            std.pcm_sample_bit_depth_chroma_minus1, 9,
            "distinct from luma"
        );
        assert_eq!(std.log2_min_pcm_luma_coding_block_size_minus3, 1);
        assert_eq!(std.log2_diff_max_min_pcm_luma_coding_block_size, 2);
        assert_eq!(std.conf_win_left_offset, 1);
        assert_eq!(std.conf_win_right_offset, 2);
        assert_eq!(std.conf_win_top_offset, 3);
        assert_eq!(std.conf_win_bottom_offset, 4);

        // The always-present pointer-backed blocks.
        assert!(!std.pProfileTierLevel.is_null());
        // SAFETY: pProfileTierLevel targets `owned`'s boxed backing, alive here.
        let ptl = unsafe { &*std.pProfileTierLevel };
        assert_eq!(ptl.flags.general_tier_flag(), 1);
        assert_eq!(ptl.flags.general_progressive_source_flag(), 1);
        assert_eq!(ptl.flags.general_interlaced_source_flag(), 0);
        assert_eq!(ptl.flags.general_non_packed_constraint_flag(), 1);
        assert_eq!(ptl.flags.general_frame_only_constraint_flag(), 0);
        assert_eq!(
            ptl.general_profile_idc,
            hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN_10
        );
        assert_eq!(
            ptl.general_level_idc,
            hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1
        );
        assert!(!std.pDecPicBufMgr.is_null());
        // SAFETY: pDecPicBufMgr targets `owned`'s boxed backing, alive here.
        let dpb = unsafe { &*std.pDecPicBufMgr };
        assert_eq!(&dpb.max_dec_pic_buffering_minus1[..2], &[5, 6]);
        assert_eq!(&dpb.max_num_reorder_pics[..2], &[1, 2]);
        assert_eq!(&dpb.max_latency_increase_plus1[..2], &[7, 8]);

        // The absent-by-content and absent-by-design pointers.
        assert!(
            std.pScalingLists.is_null(),
            "enabled but data-absent: driver defaults"
        );
        assert!(std.pShortTermRefPicSet.is_null());
        assert!(std.pLongTermRefPicsSps.is_null());
        assert!(std.pSequenceParameterSetVui.is_null());
        assert!(std.pPredictorPaletteEntries.is_null());
    }

    #[test]
    fn profile_and_level_code_points_map_or_reject() {
        for (idc, expect) in [
            (
                1u8,
                hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN,
            ),
            (
                2,
                hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN_10,
            ),
            (
                3,
                hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN_STILL_PICTURE,
            ),
            (
                4,
                hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSIONS,
            ),
        ] {
            assert_eq!(profile_to_std(idc).unwrap(), expect);
        }
        // High Throughput (5) and SCC (9) exist on the wire but not in Vulkan.
        for idc in [0u8, 5, 9, 11] {
            assert_eq!(
                profile_to_std(idc).unwrap_err(),
                H265ParamsError::UnmappableProfileIdc(idc)
            );
        }

        // Every Table A.8 level maps to its ascending index-coded point.
        let pairs = [
            (
                Level::L1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_1_0,
            ),
            (
                Level::L2,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_2_0,
            ),
            (
                Level::L2_1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_2_1,
            ),
            (
                Level::L3,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_3_0,
            ),
            (
                Level::L3_1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_3_1,
            ),
            (
                Level::L4,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_0,
            ),
            (
                Level::L4_1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1,
            ),
            (
                Level::L5,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_0,
            ),
            (
                Level::L5_1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_1,
            ),
            (
                Level::L5_2,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_5_2,
            ),
            (
                Level::L6,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_0,
            ),
            (
                Level::L6_1,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_1,
            ),
            (
                Level::L6_2,
                hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_2,
            ),
        ];
        let mut prev = None;
        for (level, expect) in pairs {
            assert_eq!(level_to_std(level), expect);
            if let Some(prev) = prev {
                assert!(expect > prev, "code points must ascend for the caps gate");
            }
            prev = Some(expect);
        }
    }

    #[test]
    fn the_owned_backings_survive_moving_the_wrapper() {
        // Box the wrapper AFTER conversion: a move relocating the wrapper itself
        // must not invalidate its pointers, because the backing is heap-pinned
        // (the h264 POC-offset test, one codec over).
        let owned = Box::new(sps_to_std_h265(&full_sps()).unwrap());
        let std = owned.std();
        // SAFETY: both pointers target `owned`'s boxed backings, alive in scope.
        let (ptl, dpb) = unsafe { (&*std.pProfileTierLevel, &*std.pDecPicBufMgr) };
        assert_eq!(
            ptl.general_profile_idc,
            hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN_10
        );
        assert_eq!(dpb.max_dec_pic_buffering_minus1[0], 5);
    }

    /// Scribble over the stack the conversion's frames just used.
    ///
    /// The discriminator in the move tests is READING a block back, and pointer
    /// equality cannot stand in for it: the Std struct carries its pointers by
    /// VALUE, so a stale one is copied along with the struct and still compares
    /// equal. An inlined backing therefore shows up only as wrong CONTENT — and
    /// only if the dead slot has actually been reused by then. This makes that
    /// certain instead of lucky: after it runs, a pointer into a dead local reads
    /// back `0xA5`s rather than, by chance, its old contents.
    #[inline(never)]
    fn clobber_the_dead_stack() {
        let mut scratch = [0xA5u8; 16 * 1024];
        std::hint::black_box(&mut scratch);
    }

    /// All three wrappers may be MOVED — into the session's stored parameters, out
    /// of a `Result`, into a `Vec` that later reallocates — without disturbing the
    /// addresses a driver has already been given.
    ///
    /// Not a Rust triviality worth skipping: it is the whole reason
    /// [`crate::session_h265`] can fix its use-after-free by STORING these values
    /// alongside the parameters object rather than by boxing or pinning them. It
    /// holds because every backing is `Box`ed; an "optimisation" that inlined any
    /// one of them as a field would keep every other test in this crate green, keep
    /// compiling, and hand the driver a pointer into a moved-from stack slot. The
    /// H.265 and Main 10 parity legs would catch it on hardware — this catches it in
    /// ordinary CI. H.265 has the most surface of the three codecs: seven pointers
    /// across the SPS alone, and this exercises every one a stream can populate.
    /// (`params_av1::moving_the_wrapper_leaves_the_driver_s_pointers_put` and
    /// `params::`'s are the same test one codec over.)
    #[test]
    fn moving_the_wrapper_leaves_the_driver_s_pointers_put() {
        // An SPS carrying every embedded pointer it can: profile/tier/level and
        // DPB manager (always), plus scaling lists, short-term RPS candidates and
        // long-term SPS candidates.
        let mut sps = full_sps();
        sps.scaling_list_data_present_flag = true;
        sps.scaling_list.scaling_list_4x4 = std::array::from_fn(|i| [10 + i as u8; 16]);
        sps.num_short_term_ref_pic_sets = 1;
        let mut st = ShortTermRefPicSet {
            num_negative_pics: 1,
            ..Default::default()
        };
        st.delta_poc_s0[0] = -1;
        st.used_by_curr_pic_s0[0] = true;
        sps.short_term_ref_pic_set = vec![st];
        sps.long_term_ref_pics_present_flag = true;
        sps.num_long_term_ref_pics_sps = 1;
        sps.lt_ref_pic_poc_lsb_sps[0] = 11;
        sps.used_by_curr_pic_lt_sps_flag[0] = true;
        // A PPS carrying its one, and a VPS carrying its two.
        let mut pps = full_pps(sps.clone());
        pps.scaling_list_data_present_flag = true;
        pps.scaling_list.scaling_list_4x4 = std::array::from_fn(|i| [60 + i as u8; 16]);
        let vps = Vps {
            video_parameter_set_id: 2,
            max_sub_layers_minus1: 1,
            profile_tier_level: full_sps().profile_tier_level,
            // Distinct from the SPS's [5, 6, …] so a read-back names which block
            // it came from rather than merely that some block was readable.
            max_dec_pic_buffering_minus1: [3, 4, 0, 0, 0, 0, 0],
            ..Default::default()
        };

        let owned_vps = vps_to_std_h265(&vps).expect("the VPS converts");
        let owned_sps = sps_to_std_h265(&sps).expect("a Main 10 SPS converts");
        let owned_pps = pps_to_std_h265(&pps).expect("its PPS converts");
        let vps_ptrs = (
            owned_vps.std().pProfileTierLevel,
            owned_vps.std().pDecPicBufMgr,
        );
        let sps_ptrs = (
            owned_sps.std().pProfileTierLevel,
            owned_sps.std().pDecPicBufMgr,
            owned_sps.std().pScalingLists,
            owned_sps.std().pShortTermRefPicSet,
            owned_sps.std().pLongTermRefPicsSps,
        );
        let pps_lists = owned_pps.std().pScalingLists;
        for (what, ptr) in [
            ("vps pProfileTierLevel", vps_ptrs.0.cast::<()>()),
            ("vps pDecPicBufMgr", vps_ptrs.1.cast()),
            ("sps pProfileTierLevel", sps_ptrs.0.cast()),
            ("sps pDecPicBufMgr", sps_ptrs.1.cast()),
            ("sps pScalingLists", sps_ptrs.2.cast()),
            ("sps pShortTermRefPicSet", sps_ptrs.3.cast()),
            ("sps pLongTermRefPicsSps", sps_ptrs.4.cast()),
            ("pps pScalingLists", pps_lists.cast()),
        ] {
            assert!(!ptr.is_null(), "{what} is attached by this fixture");
        }

        // Every move the session's stored parameters put them through: out of the
        // conversion, into a `Vec`, through a reallocation of that `Vec` as later
        // Adds push more sets in, and along with the whole `StoredParamsH265` value
        // as it is installed by `mem::replace`.
        let stored_vps = vec![owned_vps];
        let stored_sps = vec![owned_sps];
        let mut stored_pps = vec![owned_pps];
        for id in 1..crate::session_h265::MAX_STD_PPS as u8 {
            let mut more = full_pps(sps.clone());
            more.pic_parameter_set_id = id;
            stored_pps.push(pps_to_std_h265(&more).expect("converts"));
        }
        assert!(
            stored_pps.capacity() > 1,
            "the pushes reallocated, which is the case being pinned"
        );
        let stored = (stored_vps, stored_sps, stored_pps, 0u8);
        let (stored_vps, stored_sps, stored_pps, _) = stored;

        let moved_vps = stored_vps[0].std();
        assert_eq!(
            (moved_vps.pProfileTierLevel, moved_vps.pDecPicBufMgr),
            vps_ptrs
        );
        let moved_sps = stored_sps[0].std();
        assert_eq!(
            (
                moved_sps.pProfileTierLevel,
                moved_sps.pDecPicBufMgr,
                moved_sps.pScalingLists,
                moved_sps.pShortTermRefPicSet,
                moved_sps.pLongTermRefPicsSps,
            ),
            sps_ptrs
        );
        assert_eq!(stored_pps[0].std().pScalingLists, pps_lists);

        // The assertions that actually bite. Pointer equality above cannot fail —
        // the Std struct carries the value, so a stale pointer is copied along with
        // it — but an inlined backing leaves those pointers addressing dead locals
        // in the conversions' returned frames, which this has just overwritten.
        clobber_the_dead_stack();
        // They still address live blocks holding the fixture's own values, not
        // stale copies.
        // Every one of the eight, so no single backing can be inlined without this
        // failing — an earlier draft read only six and let exactly that through.
        // SAFETY: `stored_*` are alive here and own every one of these blocks.
        let (vps_ptl, vps_dpb) = unsafe { (&*vps_ptrs.0, &*vps_ptrs.1) };
        // SAFETY: as above.
        let (sps_ptl, sps_dpb, sps_scaling, sps_st, sps_lt) = unsafe {
            (
                &*sps_ptrs.0,
                &*sps_ptrs.1,
                &*sps_ptrs.2,
                &*sps_ptrs.3,
                &*sps_ptrs.4,
            )
        };
        // SAFETY: as above.
        let pps_scaling = unsafe { &*pps_lists };
        assert_eq!(
            vps_ptl.general_level_idc,
            hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1,
            "vps pProfileTierLevel"
        );
        assert_eq!(
            &vps_dpb.max_dec_pic_buffering_minus1[..2],
            &[3, 4],
            "vps pDecPicBufMgr"
        );
        assert_eq!(
            sps_ptl.general_level_idc,
            hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1,
            "sps pProfileTierLevel"
        );
        assert_eq!(
            &sps_dpb.max_dec_pic_buffering_minus1[..2],
            &[5, 6],
            "sps pDecPicBufMgr"
        );
        assert_eq!(sps_scaling.ScalingList4x4[5], [15; 16], "sps pScalingLists");
        assert_eq!(sps_st.num_negative_pics, 1, "sps pShortTermRefPicSet");
        assert_eq!(
            sps_lt.lt_ref_pic_poc_lsb_sps[0], 11,
            "sps pLongTermRefPicsSps"
        );
        assert_eq!(pps_scaling.ScalingList4x4[5], [65; 16], "pps pScalingLists");
    }

    #[test]
    fn sps_scaling_lists_convert_verbatim_including_the_32x32_pair_and_dc_values() {
        let mut sps = full_sps();
        sps.scaling_list_data_present_flag = true;
        // Distinct fill bytes per list; the 32x32 lists live at PARSER matrix
        // ids 0 and 3 (7.4.5 steps matrixId by 3 at sizeId 3) and must land at
        // Std indices 0 and 1.
        sps.scaling_list.scaling_list_4x4 = std::array::from_fn(|i| [10 + i as u8; 16]);
        sps.scaling_list.scaling_list_8x8 = std::array::from_fn(|i| [20 + i as u8; 64]);
        sps.scaling_list.scaling_list_16x16 = std::array::from_fn(|i| [30 + i as u8; 64]);
        sps.scaling_list.scaling_list_32x32 = std::array::from_fn(|i| [40 + i as u8; 64]);
        sps.scaling_list.scaling_list_dc_coef_minus8_16x16 = [-7, 0, 8, 100, 200, 247];
        sps.scaling_list.scaling_list_dc_coef_minus8_32x32 = [42, 0, 0, 99, 0, 0];

        let owned = sps_to_std_h265(&sps).unwrap();
        let std = owned.std();
        assert_eq!(std.flags.sps_scaling_list_data_present_flag(), 1);
        assert!(!std.pScalingLists.is_null());
        // SAFETY: pScalingLists targets `owned`'s boxed backing, alive here.
        let lists = unsafe { &*std.pScalingLists };
        for i in 0..6 {
            assert_eq!(lists.ScalingList4x4[i], [10 + i as u8; 16], "4x4 list {i}");
            assert_eq!(lists.ScalingList8x8[i], [20 + i as u8; 64], "8x8 list {i}");
            assert_eq!(
                lists.ScalingList16x16[i],
                [30 + i as u8; 64],
                "16x16 list {i}"
            );
        }
        assert_eq!(
            lists.ScalingList32x32[0], [40; 64],
            "intra = parser index 0"
        );
        assert_eq!(
            lists.ScalingList32x32[1], [43; 64],
            "inter = parser index 3"
        );
        // The Std DC fields carry the +8 VALUE, not the minus8 syntax element.
        assert_eq!(lists.ScalingListDCCoef16x16, [1, 8, 16, 108, 208, 255]);
        assert_eq!(lists.ScalingListDCCoef32x32, [50, 107]);
    }

    #[test]
    fn short_term_rps_candidates_reencode_to_the_std_syntax_exactly() {
        let mut sps = full_sps();
        sps.num_short_term_ref_pic_sets = 2;
        // Candidate 0: DeltaPocS0 = [-1, -3] (steps 1, 2), DeltaPocS1 = [2]
        // (step 2), with mixed used_by flags.
        let mut set0 = ShortTermRefPicSet {
            num_negative_pics: 2,
            num_positive_pics: 1,
            ..Default::default()
        };
        set0.delta_poc_s0[0] = -1;
        set0.delta_poc_s0[1] = -3;
        set0.used_by_curr_pic_s0[0] = true;
        set0.used_by_curr_pic_s0[1] = false;
        set0.delta_poc_s1[0] = 2;
        set0.used_by_curr_pic_s1[0] = true;
        // Candidate 1: as the parser leaves a PREDICTED set — resolved arrays
        // with the prediction syntax still recorded. The conversion must emit
        // the resolved non-predicted form, ignoring the prediction fields.
        let mut set1 = ShortTermRefPicSet {
            inter_ref_pic_set_prediction_flag: true,
            delta_idx_minus1: 0,
            abs_delta_rps_minus1: 0,
            num_negative_pics: 1,
            ..Default::default()
        };
        set1.delta_poc_s0[0] = -2;
        set1.used_by_curr_pic_s0[0] = true;
        sps.short_term_ref_pic_set = vec![set0, set1];

        let owned = sps_to_std_h265(&sps).unwrap();
        let std = owned.std();
        assert_eq!(std.num_short_term_ref_pic_sets, 2);
        assert!(!std.pShortTermRefPicSet.is_null());
        // SAFETY: pShortTermRefPicSet targets `owned`'s boxed slice of exactly
        // num_short_term_ref_pic_sets entries, alive for this whole scope.
        let sets = unsafe { std::slice::from_raw_parts(std.pShortTermRefPicSet, 2) };

        assert_eq!(sets[0].num_negative_pics, 2);
        assert_eq!(sets[0].num_positive_pics, 1);
        assert_eq!(
            &sets[0].delta_poc_s0_minus1[..2],
            &[0, 1],
            "steps 1 and 2, minus 1"
        );
        assert_eq!(sets[0].delta_poc_s1_minus1[0], 1, "step 2, minus 1");
        assert_eq!(sets[0].used_by_curr_pic_s0_flag, 0b01);
        assert_eq!(sets[0].used_by_curr_pic_s1_flag, 0b1);

        assert_eq!(
            sets[1].flags.inter_ref_pic_set_prediction_flag(),
            0,
            "resolved form: the prediction is flattened, never re-declared"
        );
        assert_eq!(sets[1].delta_idx_minus1, 0);
        assert_eq!(sets[1].num_negative_pics, 1);
        assert_eq!(sets[1].delta_poc_s0_minus1[0], 1);
    }

    #[test]
    fn long_term_sps_candidates_ride_with_mask_and_poc_lsbs() {
        let mut sps = full_sps();
        sps.long_term_ref_pics_present_flag = true;
        sps.num_long_term_ref_pics_sps = 3;
        sps.lt_ref_pic_poc_lsb_sps[0] = 11;
        sps.lt_ref_pic_poc_lsb_sps[1] = 22;
        sps.lt_ref_pic_poc_lsb_sps[2] = 33;
        sps.used_by_curr_pic_lt_sps_flag[0] = true;
        sps.used_by_curr_pic_lt_sps_flag[2] = true;

        let owned = sps_to_std_h265(&sps).unwrap();
        let std = owned.std();
        assert_eq!(std.flags.long_term_ref_pics_present_flag(), 1);
        assert_eq!(std.num_long_term_ref_pics_sps, 3);
        assert!(!std.pLongTermRefPicsSps.is_null());
        // SAFETY: pLongTermRefPicsSps targets `owned`'s boxed backing, alive here.
        let lt = unsafe { &*std.pLongTermRefPicsSps };
        assert_eq!(lt.used_by_curr_pic_lt_sps_flag, 0b101);
        assert_eq!(&lt.lt_ref_pic_poc_lsb_sps[..3], &[11, 22, 33]);
    }

    /// `flag=1, num=0` is not a corner case: it is the punktfunk LTR/RFI
    /// recovery stream shape (slice-signalled long-term pics, zero SPS
    /// candidates — pf-bitstream's LTR synthesizer emits exactly this). The
    /// header requires a valid `pLongTermRefPicsSps` whenever the flag is set;
    /// a set flag over a null pointer is untested territory in every driver.
    #[test]
    fn long_term_flag_without_sps_candidates_still_backs_the_pointer() {
        let mut sps = full_sps();
        sps.long_term_ref_pics_present_flag = true;
        sps.num_long_term_ref_pics_sps = 0;

        let owned = sps_to_std_h265(&sps).unwrap();
        let std = owned.std();
        assert_eq!(std.flags.long_term_ref_pics_present_flag(), 1);
        assert_eq!(std.num_long_term_ref_pics_sps, 0);
        assert!(!std.pLongTermRefPicsSps.is_null());
        // SAFETY: pLongTermRefPicsSps targets `owned`'s boxed backing, alive here.
        let lt = unsafe { &*std.pLongTermRefPicsSps };
        assert_eq!(lt.used_by_curr_pic_lt_sps_flag, 0);
        assert!(lt.lt_ref_pic_poc_lsb_sps.iter().all(|&lsb| lsb == 0));
    }

    #[test]
    fn envelope_rejections_fail_closed_instead_of_approximating() {
        // 4:2:2 — legal H.265, outside the punktfunk envelope.
        let mut sps = full_sps();
        sps.chroma_format_idc = 2;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::UnsupportedChromaFormat(2)
        );
        // Monochrome likewise.
        sps.chroma_format_idc = 0;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::UnsupportedChromaFormat(0)
        );
        // 4:4:4 with separate colour planes = ChromaArrayType 0 in disguise.
        sps.chroma_format_idc = 3;
        sps.separate_colour_plane_flag = true;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::SeparateColourPlanes
        );
        sps.separate_colour_plane_flag = false;
        // Past 3 is not legal H.265 at all.
        sps.chroma_format_idc = 4;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::InvalidChromaFormatIdc(4)
        );

        // 12-bit and mismatched depths: no punktfunk output format carries them.
        let mut sps = full_sps();
        sps.bit_depth_luma_minus8 = 4;
        sps.bit_depth_chroma_minus8 = 4;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::UnsupportedBitDepth {
                luma_minus8: 4,
                chroma_minus8: 4
            }
        );
        let mut sps = full_sps();
        sps.bit_depth_chroma_minus8 = 0;
        assert!(matches!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::UnsupportedBitDepth { .. }
        ));

        // 4:4:4 at 8 and 10 bits IS in the envelope (RExt profile).
        let mut sps = full_sps();
        sps.profile_tier_level.general_profile_idc = 4;
        sps.chroma_format_idc = 3;
        sps.bit_depth_luma_minus8 = 0;
        sps.bit_depth_chroma_minus8 = 0;
        let owned = sps_to_std_h265(&sps).unwrap();
        assert_eq!(
            owned.std().chroma_format_idc,
            hh::StdVideoH265ChromaFormatIdc_STD_VIDEO_H265_CHROMA_FORMAT_IDC_444
        );

        // An unmappable profile.
        let mut sps = full_sps();
        sps.profile_tier_level.general_profile_idc = 9; // SCC
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::UnmappableProfileIdc(9)
        );

        // SCC palette predictor initializers: the one pointer we refuse to fake,
        // on both parameter sets.
        let mut sps = full_sps();
        sps.scc_extension
            .palette_predictor_initializers_present_flag = true;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::PalettePredictorInitializers
        );
        let mut pps = full_pps(full_sps());
        pps.scc_extension
            .palette_predictor_initializers_present_flag = true;
        assert_eq!(
            pps_to_std_h265(&pps).unwrap_err(),
            H265ParamsError::PalettePredictorInitializers
        );
    }

    #[test]
    fn oversized_or_corrupt_rps_tables_are_rejected_not_padded() {
        // More candidates than the spec's 64.
        let mut sps = full_sps();
        sps.num_short_term_ref_pic_sets = 65;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::TooManyShortTermRpsSets(65)
        );

        // A declared count the parser never resolved.
        let mut sps = full_sps();
        sps.num_short_term_ref_pic_sets = 1;
        sps.short_term_ref_pic_set = Vec::new();
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::MissingShortTermRps { index: 0 }
        );

        // A set with more entries on one side than the Std arrays hold.
        let mut sps = full_sps();
        sps.num_short_term_ref_pic_sets = 1;
        sps.short_term_ref_pic_set = vec![ShortTermRefPicSet {
            num_negative_pics: 17,
            ..Default::default()
        }];
        assert!(matches!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::RpsEntryOverflow { set: 0, .. }
        ));

        // A non-monotonic DeltaPoc array cannot re-encode as minus1 syntax.
        let mut sps = full_sps();
        sps.num_short_term_ref_pic_sets = 1;
        let mut set = ShortTermRefPicSet {
            num_negative_pics: 2,
            ..Default::default()
        };
        set.delta_poc_s0[0] = -3;
        set.delta_poc_s0[1] = -1; // must be strictly decreasing
        sps.short_term_ref_pic_set = vec![set];
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::NonMonotonicRps { set: 0 }
        );

        // Too many long-term SPS candidates.
        let mut sps = full_sps();
        sps.long_term_ref_pics_present_flag = true;
        sps.num_long_term_ref_pics_sps = 33;
        assert_eq!(
            sps_to_std_h265(&sps).unwrap_err(),
            H265ParamsError::TooManyLongTermSpsPics(33)
        );
    }

    #[test]
    fn every_mapped_pps_field_and_flag_round_trips_exactly() {
        let pps = full_pps(full_sps());
        let owned = pps_to_std_h265(&pps).unwrap();
        let std = owned.std();

        // The fixture's mixed pattern, bit for bit.
        assert_eq!(std.flags.dependent_slice_segments_enabled_flag(), 1);
        assert_eq!(std.flags.output_flag_present_flag(), 0);
        assert_eq!(std.flags.sign_data_hiding_enabled_flag(), 1);
        assert_eq!(std.flags.cabac_init_present_flag(), 0);
        assert_eq!(std.flags.constrained_intra_pred_flag(), 1);
        assert_eq!(std.flags.transform_skip_enabled_flag(), 0);
        assert_eq!(std.flags.cu_qp_delta_enabled_flag(), 1);
        assert_eq!(std.flags.pps_slice_chroma_qp_offsets_present_flag(), 0);
        assert_eq!(std.flags.weighted_pred_flag(), 1);
        assert_eq!(std.flags.weighted_bipred_flag(), 0);
        assert_eq!(std.flags.transquant_bypass_enabled_flag(), 1);
        assert_eq!(std.flags.tiles_enabled_flag(), 1);
        assert_eq!(std.flags.entropy_coding_sync_enabled_flag(), 0);
        assert_eq!(std.flags.uniform_spacing_flag(), 0);
        assert_eq!(std.flags.loop_filter_across_tiles_enabled_flag(), 1);
        assert_eq!(std.flags.pps_loop_filter_across_slices_enabled_flag(), 0);
        assert_eq!(std.flags.deblocking_filter_control_present_flag(), 1);
        assert_eq!(std.flags.deblocking_filter_override_enabled_flag(), 0);
        assert_eq!(std.flags.pps_deblocking_filter_disabled_flag(), 1);
        assert_eq!(std.flags.pps_scaling_list_data_present_flag(), 0);
        assert_eq!(std.flags.lists_modification_present_flag(), 1);
        assert_eq!(std.flags.slice_segment_header_extension_present_flag(), 0);
        assert_eq!(std.flags.pps_extension_present_flag(), 1);
        assert_eq!(std.flags.cross_component_prediction_enabled_flag(), 1);
        assert_eq!(std.flags.chroma_qp_offset_list_enabled_flag(), 1);
        assert_eq!(std.flags.pps_curr_pic_ref_enabled_flag(), 0);
        assert_eq!(
            std.flags.residual_adaptive_colour_transform_enabled_flag(),
            0
        );
        assert_eq!(std.flags.pps_slice_act_qp_offsets_present_flag(), 0);
        assert_eq!(
            std.flags.pps_palette_predictor_initializers_present_flag(),
            0
        );
        assert_eq!(std.flags.monochrome_palette_flag(), 0);
        assert_eq!(std.flags.pps_range_extension_flag(), 1);

        assert_eq!(std.pps_pic_parameter_set_id, 3);
        assert_eq!(std.pps_seq_parameter_set_id, 5);
        assert_eq!(
            std.sps_video_parameter_set_id, 2,
            "resolved through the PPS's own SPS"
        );
        assert_eq!(std.num_extra_slice_header_bits, 2);
        assert_eq!(std.num_ref_idx_l0_default_active_minus1, 2);
        assert_eq!(std.num_ref_idx_l1_default_active_minus1, 1);
        assert_eq!(std.init_qp_minus26, -3);
        assert_eq!(std.diff_cu_qp_delta_depth, 2);
        assert_eq!(std.pps_cb_qp_offset, -4);
        assert_eq!(std.pps_cr_qp_offset, 5);
        assert_eq!(std.pps_beta_offset_div2, -2);
        assert_eq!(std.pps_tc_offset_div2, 3);
        assert_eq!(std.log2_parallel_merge_level_minus2, 1);
        assert_eq!(std.log2_max_transform_skip_block_size_minus2, 2);
        assert_eq!(std.diff_cu_chroma_qp_offset_depth, 1);
        assert_eq!(std.chroma_qp_offset_list_len_minus1, 1);
        assert_eq!(&std.cb_qp_offset_list[..2], &[1, -2]);
        assert_eq!(&std.cr_qp_offset_list[..2], &[-3, 4]);
        assert_eq!(std.log2_sao_offset_scale_luma, 1);
        assert_eq!(std.log2_sao_offset_scale_chroma, 2);
        assert_eq!(std.num_tile_columns_minus1, 1);
        assert_eq!(std.num_tile_rows_minus1, 2);
        assert_eq!(&std.column_width_minus1[..2], &[17, 12]);
        assert_eq!(&std.row_height_minus1[..3], &[9, 8, 16]);
        assert!(std.pScalingLists.is_null());
        assert!(std.pPredictorPaletteEntries.is_null());
    }

    #[test]
    fn a_pps_field_past_its_std_width_is_an_error_not_a_truncation() {
        let mut pps = full_pps(full_sps());
        pps.column_width_minus1[0] = 70_000; // past u16
        assert!(matches!(
            pps_to_std_h265(&pps).unwrap_err(),
            H265ParamsError::FieldOverflow {
                field: "column_width_minus1",
                value: 70_000
            }
        ));

        let mut pps = full_pps(full_sps());
        pps.range_extension.log2_sao_offset_scale_luma = 300; // past u8
        assert!(matches!(
            pps_to_std_h265(&pps).unwrap_err(),
            H265ParamsError::FieldOverflow { .. }
        ));
    }

    #[test]
    fn pps_scaling_lists_ride_behind_the_owned_pointer() {
        let mut pps = full_pps(full_sps());
        pps.scaling_list_data_present_flag = true;
        pps.scaling_list.scaling_list_4x4 = std::array::from_fn(|i| [60 + i as u8; 16]);
        let owned = Box::new(pps_to_std_h265(&pps).unwrap());
        assert_eq!(owned.std().flags.pps_scaling_list_data_present_flag(), 1);
        // SAFETY: pScalingLists targets `owned`'s boxed backing, alive here.
        let lists = unsafe { &*owned.std().pScalingLists };
        assert_eq!(lists.ScalingList4x4[5], [65; 16]);
    }

    #[test]
    fn a_vps_converts_with_hrd_and_timing_skipped_by_design() {
        let vps = Vps {
            video_parameter_set_id: 2,
            max_sub_layers_minus1: 1,
            temporal_id_nesting_flag: true,
            sub_layer_ordering_info_present_flag: true,
            profile_tier_level: full_sps().profile_tier_level,
            max_dec_pic_buffering_minus1: [5, 6, 0, 0, 0, 0, 0],
            max_num_reorder_pics: [1, 2, 0, 0, 0, 0, 0],
            max_latency_increase_plus1: [7, 8, 0, 0, 0, 0, 0],
            // Timing present at the SOURCE: the skip must not copy it.
            timing_info_present_flag: true,
            num_units_in_tick: 1000,
            time_scale: 60_000,
            ..Default::default()
        };
        let owned = vps_to_std_h265(&vps).unwrap();
        let std = owned.std();
        assert_eq!(std.vps_video_parameter_set_id, 2);
        assert_eq!(std.vps_max_sub_layers_minus1, 1);
        assert_eq!(std.flags.vps_temporal_id_nesting_flag(), 1);
        assert_eq!(std.flags.vps_sub_layer_ordering_info_present_flag(), 1);
        assert_eq!(
            std.flags.vps_timing_info_present_flag(),
            0,
            "true at the source, skipped by design (HRD/timing)"
        );
        assert_eq!(std.vps_num_units_in_tick, 0);
        assert_eq!(std.vps_time_scale, 0);
        assert!(std.pHrdParameters.is_null());
        // SAFETY: both pointers target `owned`'s boxed backings, alive here.
        let (ptl, dpb) = unsafe { (&*std.pProfileTierLevel, &*std.pDecPicBufMgr) };
        assert_eq!(
            ptl.general_profile_idc,
            hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN_10
        );
        assert_eq!(&dpb.max_dec_pic_buffering_minus1[..2], &[5, 6]);
        assert_eq!(&dpb.max_latency_increase_plus1[..2], &[7, 8]);

        // A VPS whose DPB sizing overflows the Std u8 fields is corrupt.
        let mut hostile = vps;
        hostile.max_dec_pic_buffering_minus1[0] = 300;
        assert!(matches!(
            vps_to_std_h265(&hostile).unwrap_err(),
            H265ParamsError::FieldOverflow { .. }
        ));
    }

    #[test]
    fn the_fallback_vps_restates_exactly_what_the_sps_knows() {
        let sps = full_sps();
        let owned = fallback_vps_from_sps(&sps).unwrap();
        let std = owned.std();
        assert_eq!(std.vps_video_parameter_set_id, sps.video_parameter_set_id);
        assert_eq!(std.vps_max_sub_layers_minus1, sps.max_sub_layers_minus1);
        // SAFETY: both pointers target `owned`'s boxed backings, alive here.
        let (ptl, dpb) = unsafe { (&*std.pProfileTierLevel, &*std.pDecPicBufMgr) };
        assert_eq!(
            ptl.general_level_idc,
            hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_4_1
        );
        assert_eq!(
            dpb.max_dec_pic_buffering_minus1,
            sps.max_dec_pic_buffering_minus1
        );
        assert_eq!(dpb.max_num_reorder_pics, sps.max_num_reorder_pics);
    }

    #[test]
    fn the_25fps_vectors_own_parameter_sets_convert_cleanly() {
        use std::io::Cursor;

        use cros_codecs::codec::h265::parser::Nalu;
        use cros_codecs::codec::h265::parser::NaluType;
        use cros_codecs::codec::h265::parser::Parser;

        // The same vendored vector pf-bitstream's h265 tests plan, same path.
        const TEST_25FPS: &[u8] = include_bytes!(
            "../../pf-bitstream/vendor/cros-codecs/src/codec/h265/test_data/test-25fps.h265"
        );

        let mut cursor = Cursor::new(TEST_25FPS);
        let mut parser = Parser::default();
        let (mut vps_seen, mut sps_seen, mut pps_seen) = (false, false, false);
        while let Ok(nalu) = Nalu::next(&mut cursor) {
            match nalu.header.type_ {
                NaluType::VpsNut if !vps_seen => {
                    let vps = parser.parse_vps(&nalu).expect("the vector's VPS parses");
                    vps_to_std_h265(vps).expect("the vector's VPS converts");
                    vps_seen = true;
                }
                NaluType::SpsNut if !sps_seen => {
                    let sps = parser.parse_sps(&nalu).expect("the vector's SPS parses");
                    let owned = sps_to_std_h265(sps).expect("the vector's SPS converts");
                    let std = owned.std();
                    // The vector's own goldens: 320x240 8-bit 4:2:0 Main.
                    assert_eq!(std.pic_width_in_luma_samples, 320, "the vector is 320x240");
                    assert_eq!(std.pic_height_in_luma_samples, 240);
                    assert_eq!(std.bit_depth_luma_minus8, 0);
                    assert_eq!(
                        std.chroma_format_idc,
                        hh::StdVideoH265ChromaFormatIdc_STD_VIDEO_H265_CHROMA_FORMAT_IDC_420
                    );
                    // SAFETY: pProfileTierLevel targets `owned`'s boxed backing.
                    let ptl = unsafe { &*std.pProfileTierLevel };
                    assert_eq!(
                        ptl.general_profile_idc,
                        hh::StdVideoH265ProfileIdc_STD_VIDEO_H265_PROFILE_IDC_MAIN
                    );
                    sps_seen = true;
                }
                NaluType::PpsNut if !pps_seen => {
                    let pps = parser.parse_pps(&nalu).expect("the vector's PPS parses");
                    let owned = pps_to_std_h265(pps).expect("the vector's PPS converts");
                    assert_eq!(owned.std().pps_pic_parameter_set_id, 0);
                    pps_seen = true;
                }
                _ => {}
            }
            if vps_seen && sps_seen && pps_seen {
                break;
            }
        }
        assert!(
            vps_seen && sps_seen && pps_seen,
            "the vector opens with VPS + SPS + PPS"
        );
    }

    /// The over-declared-level clamp (the AMF 6.2-on-everything field case):
    /// lowering writes the ceiling into the PTL backing the driver will read;
    /// a ceiling at or above the declared level changes nothing.
    #[test]
    fn clamp_level_lowers_the_ptl_and_only_lowers() {
        let sps = full_sps();
        let declared = level_to_std(sps.profile_tier_level.general_level_idc);

        let mut owned = sps_to_std_h265(&sps).unwrap();
        // SAFETY: pProfileTierLevel targets `owned`'s boxed backing.
        let level = unsafe { (*owned.std().pProfileTierLevel).general_level_idc };
        assert_eq!(level, declared);
        // A ceiling above the declared level is a no-op.
        owned.clamp_level(hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_6_2);
        // SAFETY: as above.
        let level = unsafe { (*owned.std().pProfileTierLevel).general_level_idc };
        assert_eq!(level, declared);
        // A ceiling below it is written through — and the pointer still targets
        // the wrapper's own backing (the clamp mutates in place, never re-points).
        let ceiling = hh::StdVideoH265LevelIdc_STD_VIDEO_H265_LEVEL_IDC_3_1;
        assert!(ceiling < declared, "fixture declares above 3.1");
        owned.clamp_level(ceiling);
        // SAFETY: as above.
        let level = unsafe { (*owned.std().pProfileTierLevel).general_level_idc };
        assert_eq!(level, ceiling);

        let mut owned_vps = fallback_vps_from_sps(&sps).unwrap();
        owned_vps.clamp_level(ceiling);
        // SAFETY: as above, the VPS wrapper's own backing.
        let vps_level = unsafe { (*owned_vps.std().pProfileTierLevel).general_level_idc };
        assert!(vps_level <= ceiling);
    }
}
