///|
/// Bounded eight-slot AV1 reference-frame image state.
///
/// This stores decoded RGBA images for the show-existing branch. Inter
/// prediction and motion compensation remain outside this small state layer.
pub(all) struct Av1ReferenceState {
images : Array[Image?]
frame_types : Array[Int]
}
///|
/// Create an empty eight-slot reference state.
pub fn av1_reference_state() -> Av1ReferenceState {
{ images: Array::make(8, None), frame_types: Array::make(8, -1), }
}
///|
/// Store a decoded image in one AV1 reference slot.
pub fn av1_reference_store(
state : Av1ReferenceState,
slot : Int,
image : Image,
frame_type : Int,
) -> Bool {
if slot < 0 || slot >= 8 || frame_type < 0 || frame_type > 3 {
return false
}
state.images[slot] = Some(image.copy())
state.frame_types[slot] = frame_type
true
}
///|
/// Resolve a parsed show-existing envelope against stored reference pixels.
pub fn av1_reference_show_existing(
state : Av1ReferenceState,
envelope : Av1ShowExistingFrameEnvelope,
) -> Image? {
if envelope.frame_to_show_map_idx < 0 || envelope.frame_to_show_map_idx >= 8 {
return None
}
state.images[envelope.frame_to_show_map_idx].map(fn(image) { image.copy() })
}
///|
/// Resolve a show-existing frame header directly to a copy of its stored RGBA
/// image. This is the bounded inter-frame entry; motion-compensated blocks are
/// intentionally handled by a later planar decoder stage.
pub fn av1_decode_show_existing_frame(
frame_payload : Array[Byte],
state : Av1ReferenceState,
config : Av1ShowExistingFrameConfig,
) -> Image? {
let envelope = match av1_parse_show_existing_frame(frame_payload, config) {
Some(value) => value
None => return None
}
av1_reference_show_existing(state, envelope)
}
///|
test "reference state stores and resolves show-existing pixels" {
let state = av1_reference_state()
let image = Image::new(2, 1)
image.set_pixel(0, 0, b'\x10', b'\x20', b'\x30', b'\xFF')
assert_true(av1_reference_store(state, 3, image, 0))
let config : Av1ShowExistingFrameConfig = {
decoder_model_info_present: false,
equal_picture_interval: false,
frame_presentation_time_length_minus_1: 0,
frame_id_numbers_present: false,
additional_frame_id_len_minus1: 0,
delta_frame_id_length_minus2: 0,
reference_frame_types: [0, 1, 2, 3, 4, 5, 6, 7],
}
let envelope = av1_parse_show_existing_frame([b'\xB0'], config).unwrap()
let shown = av1_reference_show_existing(state, envelope).unwrap()
assert_eq(shown.get_pixel(0, 0), (b'\x10', b'\x20', b'\x30', b'\xFF'))
assert_true(
av1_reference_show_existing(state, {
show_existing_frame: true,
frame_to_show_map_idx: 2,
reference_frame_type: 2,
frame_presentation_time: None,
display_frame_id: None,
header_bits: 4,
header_bytes: 1,
})
is None,
)
let decoded = av1_decode_show_existing_frame([b'\xB0'], state, config).unwrap()
decoded.set_pixel(0, 0, b'\x99', b'\x99', b'\x99', b'\xFF')
assert_eq(shown.get_pixel(0, 0), (b'\x10', b'\x20', b'\x30', b'\xFF'))
}