waterkit-codec 0.1.1

Hardware-aware video codec with deterministic timing and wgpu texture output
use crate::{CodecError, DecodedPixelLayout};

pub fn decoded_pixel_layout(
    is_hevc: bool,
    config: Option<&[u8]>,
) -> Result<DecodedPixelLayout, CodecError> {
    if !is_hevc {
        return Ok(DecodedPixelLayout::Nv12);
    }
    let config = config.ok_or_else(|| {
        CodecError::InitializationFailed(
            "HEVC codec configuration is required to select an output bit depth".into(),
        )
    })?;
    let payload = strip_box_header(config, *b"hvcC");
    if payload.len() < 19 {
        return Err(CodecError::InitializationFailed(
            "invalid hvcC payload: missing bit-depth fields".into(),
        ));
    }
    let luma_bit_depth = 8 + (payload[17] & 0x07);
    let chroma_bit_depth = 8 + (payload[18] & 0x07);
    match (luma_bit_depth, chroma_bit_depth) {
        (8, 8) => Ok(DecodedPixelLayout::Nv12),
        (10, 10) => Ok(DecodedPixelLayout::P010),
        _ => Err(CodecError::Unsupported(format!(
            "hardware decode supports 8-bit NV12 and 10-bit P010, not {luma_bit_depth}-bit luma/{chroma_bit_depth}-bit chroma"
        ))),
    }
}

pub fn strip_box_header(config: &[u8], box_type: [u8; 4]) -> &[u8] {
    if config.len() >= 8 && config[4..8] == box_type {
        &config[8..]
    } else {
        config
    }
}

#[cfg(test)]
mod tests {
    use super::decoded_pixel_layout;
    use crate::DecodedPixelLayout;

    #[test]
    fn reads_hevc_bit_depth_from_boxed_hvcc() {
        let mut config = vec![0_u8; 8 + 23];
        config[4..8].copy_from_slice(b"hvcC");
        config[8] = 1;
        config[8 + 17] = 2;
        config[8 + 18] = 2;
        assert_eq!(
            decoded_pixel_layout(true, Some(&config)).expect("valid Main10 configuration"),
            DecodedPixelLayout::P010
        );
    }
}