/// Minimal AV1 `show_existing_frame` envelope parsing.
///
/// This parser deliberately stops at the uncompressed-header envelope. It
/// validates the fields needed to display a previously decoded reference
/// frame, but it does not claim to decode inter prediction or reference
/// pixels. The reduced-still parser remains in `av1_frame_header.mbt` and is
/// intentionally independent from this API.
///|
/// Sequence-level syntax needed by `show_existing_frame` (§5.9.2).
pub(all) struct Av1ShowExistingFrameConfig {
/// Whether decoder model information is present in the active sequence.
decoder_model_info_present : Bool
/// `equal_picture_interval` from the operating point timing parameters.
equal_picture_interval : Bool
/// `frame_presentation_time` width minus one (§5.9.31).
frame_presentation_time_length_minus_1 : Int
/// Whether frame IDs are present in the sequence header.
frame_id_numbers_present : Bool
/// `additional_frame_id_length_minus_1` from the sequence header.
additional_frame_id_len_minus1 : Int
/// `delta_frame_id_length_minus_2` from the sequence header.
delta_frame_id_length_minus2 : Int
/// The current reference-frame type for each of the eight map slots.
/// Supplying fewer than eight entries is rejected so an encoded map index
/// can never silently address an absent slot.
reference_frame_types : Array[Int]
}
///|
/// Parsed fields from an AV1 `show_existing_frame` header.
///
/// `frame_presentation_time` and `display_frame_id` are optional because the
/// corresponding sequence features are optional. `reference_frame_type` is
/// metadata from the caller's reference-frame state; it does not decode any
/// pixels.
pub(all) struct Av1ShowExistingFrameEnvelope {
show_existing_frame : Bool
frame_to_show_map_idx : Int
reference_frame_type : Int
frame_presentation_time : Int64?
display_frame_id : Int?
header_bits : Int
header_bytes : Int
}
///|
/// Parse the minimal `show_existing_frame` prefix of an AV1 frame header.
///
/// The first bit must be one. The parser then consumes the three-bit map
/// index, the conditional temporal-point timing field, and the conditional
/// frame ID, rejecting truncation, invalid field widths, and map indices for
/// which the supplied reference state has no slot. Remaining frame-header
/// syntax is intentionally outside this envelope and is not interpreted.
pub fn av1_parse_show_existing_frame(
frame_payload : Array[Byte],
config : Av1ShowExistingFrameConfig,
) -> Av1ShowExistingFrameEnvelope? {
if config.reference_frame_types.length() < 8 {
return None
}
let reader : Av1FrameBits = { data: frame_payload, bit_pos: 0, }
let show_existing_frame = match reader.take(1) {
Some(v) => v == 1
None => return None
}
if !show_existing_frame {
// This API is intentionally scoped to the reference-display branch. A
// regular frame header must be parsed by the full frame-state path.
return None
}
let frame_to_show_map_idx = match reader.take(3) {
Some(v) => v
None => return None
}
if frame_to_show_map_idx < 0 ||
frame_to_show_map_idx >= config.reference_frame_types.length() {
return None
}
let mut frame_presentation_time : Int64? = None
if config.decoder_model_info_present && !config.equal_picture_interval {
let count = config.frame_presentation_time_length_minus_1 + 1
if count < 1 || count > 32 {
return None
}
frame_presentation_time = match av1_frame_timing_value(reader, count) {
Some(v) => Some(v)
None => return None
}
}
let mut display_frame_id : Int? = None
if config.frame_id_numbers_present {
if config.additional_frame_id_len_minus1 < 0 ||
config.delta_frame_id_length_minus2 < 0 {
return None
}
let count = config.additional_frame_id_len_minus1 +
config.delta_frame_id_length_minus2 +
3
if count < 3 || count > 16 {
return None
}
display_frame_id = match reader.take(count) {
Some(v) => Some(v)
None => return None
}
}
Some({
show_existing_frame,
frame_to_show_map_idx,
reference_frame_type: config.reference_frame_types[frame_to_show_map_idx],
frame_presentation_time,
display_frame_id,
header_bits: reader.bit_pos,
header_bytes: (reader.bit_pos + 7) / 8,
})
}
///|
/// Timing syntax is unsigned and may use all 32 bits. Read bounded halves and
/// widen before combining so values above 2^31-1 stay positive on every target.
fn av1_frame_timing_value(reader : Av1FrameBits, count : Int) -> Int64? {
if count < 1 || count > 32 {
return None
}
if count <= 16 {
return reader.take(count).map(value => value.to_int64())
}
let high = match reader.take(count - 16) {
Some(value) => value
None => return None
}
let low = match reader.take(16) {
Some(value) => value
None => return None
}
Some((high.to_int64() << 16) | low.to_int64())
}
///|
/// Explicitly named alias for callers that prefer the envelope terminology.
pub fn av1_parse_show_existing_frame_envelope(
frame_payload : Array[Byte],
config : Av1ShowExistingFrameConfig,
) -> Av1ShowExistingFrameEnvelope? {
av1_parse_show_existing_frame(frame_payload, config)
}