#![forbid(unsafe_code)]
use super::bitstream::RbspWriter;
const OBU_SEQUENCE_HEADER: u8 = 1;
const OBU_TEMPORAL_DELIMITER: u8 = 2;
pub(super) const OBU_FRAME: u8 = 6;
const SEQ_PROFILE_MAIN: u32 = 0;
pub(super) fn write_leb128(out: &mut Vec<u8>, mut value: u64) {
loop {
let mut byte = (value & 0x7f) as u8;
value >>= 7;
if value == 0 {
out.push(byte);
break;
}
byte |= 0x80;
out.push(byte);
}
}
pub(super) const fn obu_header_byte(obu_type: u8) -> u8 {
(obu_type << 3) | 0b10
}
fn wrap_obu(obu_type: u8, payload: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(payload.len() + 3);
out.push(obu_header_byte(obu_type));
write_leb128(&mut out, payload.len() as u64);
out.extend_from_slice(payload);
out
}
const fn bit_length(value: u32) -> u32 {
32 - value.leading_zeros()
}
const fn tile_log2(blk_size: u32, target: u32) -> u32 {
let mut k = 0;
while (blk_size << k) < target {
k += 1;
}
k
}
fn write_tile_info(w: &mut RbspWriter, mi_cols: u32, mi_rows: u32) {
const MAX_TILE_WIDTH: u32 = 4096;
const MAX_TILE_AREA: u32 = 4096 * 2304;
const MAX_TILE_COLS: u32 = 64;
const MAX_TILE_ROWS: u32 = 64;
const SB_SHIFT: u32 = 4; const SB_SIZE: u32 = SB_SHIFT + 2;
let sb_cols = (mi_cols + 15) >> SB_SHIFT;
let sb_rows = (mi_rows + 15) >> SB_SHIFT;
let max_tile_width_sb = MAX_TILE_WIDTH >> SB_SIZE;
let max_tile_area_sb = MAX_TILE_AREA >> (2 * SB_SIZE);
let min_log2_tile_cols = tile_log2(max_tile_width_sb, sb_cols);
let max_log2_tile_cols = tile_log2(1, sb_cols.min(MAX_TILE_COLS));
let max_log2_tile_rows = tile_log2(1, sb_rows.min(MAX_TILE_ROWS));
let min_log2_tiles = min_log2_tile_cols.max(tile_log2(max_tile_area_sb, sb_rows * sb_cols));
w.write_bit(1);
let tile_cols_log2 = min_log2_tile_cols;
if tile_cols_log2 < max_log2_tile_cols {
w.write_bit(0); }
let min_log2_tile_rows = min_log2_tiles.saturating_sub(tile_cols_log2);
let tile_rows_log2 = min_log2_tile_rows;
if tile_rows_log2 < max_log2_tile_rows {
w.write_bit(0); }
if tile_cols_log2 > 0 || tile_rows_log2 > 0 {
w.write_bits(
0,
u8::try_from(tile_cols_log2 + tile_rows_log2).unwrap_or(31),
);
w.write_bits(0, 2);
}
}
fn write_sequence_header(
w: &mut RbspWriter,
width: u32,
height: u32,
seq_level_idx: u8,
seq_tier: u8,
) {
w.write_bits(SEQ_PROFILE_MAIN, 3); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bits(0, 5); w.write_bits(0, 12); w.write_bits(u32::from(seq_level_idx), 5); if seq_level_idx > 7 {
w.write_bit(seq_tier); }
let width_bits = bit_length(width - 1).max(1);
let height_bits = bit_length(height - 1).max(1);
w.write_bits(width_bits - 1, 4); w.write_bits(height_bits - 1, 4); w.write_bits(width - 1, u8::try_from(width_bits).unwrap_or(16)); w.write_bits(height - 1, u8::try_from(height_bits).unwrap_or(16));
w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0);
w.write_bit(0); w.write_bit(0); w.write_bit(0);
w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bits(0, 2); w.write_bit(0);
w.write_bit(0);
w.rbsp_trailing_bits(); }
fn write_frame_header(w: &mut RbspWriter, base_q_idx: u8, width: u32, height: u32) {
w.write_bit(0); w.write_bits(0, 2); w.write_bit(1);
w.write_bit(1);
w.write_bit(0);
w.write_bit(0);
let mi_cols = 2 * ((width + 7) >> 3);
let mi_rows = 2 * ((height + 7) >> 3);
write_tile_info(w, mi_cols, mi_rows);
w.write_u8(base_q_idx); w.write_bit(0); w.write_bit(0); w.write_bit(0); w.write_bit(0);
w.write_bit(0);
w.write_bit(0);
w.write_bits(0, 6); w.write_bits(0, 6); w.write_bits(0, 3); w.write_bit(0);
w.write_bit(0);
w.write_bit(0);
w.byte_align_zero(); }
pub(super) fn build_av1_session_prefix(
width: u32,
height: u32,
seq_level_idx: u8,
seq_tier: u8,
) -> Vec<u8> {
let mut seq_w = RbspWriter::new();
write_sequence_header(&mut seq_w, width, height, seq_level_idx, seq_tier);
let seq_header_bytes = seq_w.finish();
let mut out = wrap_obu(OBU_TEMPORAL_DELIMITER, &[]);
out.extend(wrap_obu(OBU_SEQUENCE_HEADER, &seq_header_bytes));
out
}
pub(super) fn build_av1_frame_header_bytes(base_q_idx: u8, width: u32, height: u32) -> Vec<u8> {
let mut w = RbspWriter::new();
write_frame_header(&mut w, base_q_idx, width, height);
w.finish()
}