This commit is contained in:
2024-05-03 01:42:45 +02:00
parent f63799bc25
commit b8abea334d
3 changed files with 514 additions and 57 deletions
+426 -15
View File
@@ -1,5 +1,6 @@
package avif
import "core:fmt"
import "core:io"
OBUType :: enum u8 {
@@ -14,17 +15,76 @@ OBUType :: enum u8 {
PADDING = 15,
}
// TODO: write a nice bitstream reader
// ??? Still don't know how I want this to work
BitstreamReader :: struct {
data: []byte,
pos: i64, // Number of bits read from the data slice
OBUError :: enum {
ReservedOBU,
}
ColorPrimaries :: enum u8 {
BT_709 = 1,
UNSPECIFIED = 2,
BT_470_M = 4,
BT_470_B_G = 5,
BT_601 = 6,
SMPTE_240 = 7,
GENERIC_FILM = 8,
BT_2020 = 9,
XYZ = 10,
SMPTE_431 = 11,
SMPTE_432 = 12,
EBU_3213 = 22,
}
TransferCharacteristic :: enum u8 {
RESERVED_0 = 0,
BT_709 = 1,
UNSPECIFIED = 2,
RESERVED_3 = 3,
BT_470_M = 4,
BT_470_B_G = 5,
BT_601 = 6,
SMPTE_240 = 7,
LINEAR = 8,
LOG_100 = 9,
LOG_100_SQRT10 = 10,
IEC_61966 = 11,
BT_1361 = 12,
SRGB = 13,
BT_2020_10_BIT = 14,
BT_2020_12_BIT = 15,
SMPTE_2084 = 16,
SMPTE_428 = 17,
HLG = 18,
}
MatrixCoefficient :: enum u8 {
IDENTITY = 0,
BT_709 = 1,
UNSPECIFIED = 2,
RESERVED_3 = 3,
FCC = 4,
BT_470_B_G = 5,
BT_601 = 6,
SMPTE_240 = 7,
SMPTE_YCGCO = 8,
BT_2020_NCL = 9,
BT_2020_CL = 10,
SMPTE_2085 = 11,
CHROMAT_NCL = 12,
CHROMAT_CL = 13,
ICTCP = 14,
}
ChromeSamplePosition :: enum u8 {
UNKNOWN = 0,
VERTICAL = 1,
COLOCATED = 2,
RESERVED = 3,
}
OBUHeader :: bit_field u8 {
obu_reserved: u8 | 1,
obu_has_size_field: u8 | 1,
obu_extension_flag: u8 | 1,
obu_has_size_field: b8 | 1,
obu_extension_flag: b8 | 1,
obu_type: OBUType | 4,
obu_forbidden_bit: u8 | 1,
}
@@ -35,29 +95,361 @@ OBUExtensionHeader :: bit_field u8 {
temporal_id: u8 | 3,
}
read_bit :: proc() -> b8 {
// TODO: idfk
// This should read a single bit from the bitstream and advance the bitstream position by 1
read_obu :: proc(r: ^Reader) -> (err: Error) {
header := read_bitfield(r, OBUHeader) or_return
size: u64
return false
fmt.println(header)
if header.obu_extension_flag {
ext_header := read_bitfield(r, OBUExtensionHeader) or_return
fmt.println(ext_header)
}
if header.obu_has_size_field {
size = leb128(r)
} else {
// TODO: is this correct ???
// The spec is NOT clear about wtf sz is, so I assume it's the box size without the header.
// It's also possibly the remaining box size, we'll have to check how other decoders do it.
size = u64(r.box.size - BOX_HEADER_SIZE - 1 - u32(header.obu_extension_flag))
}
// TODO: get bit position
//start_pos := get_position()
//// TODO:
//if header.obu_type != .SEQUENCE_HEADER && header.obu_type != .TEMPORAL_DELIMITER && OperatingPointIdc != 0 && header.obu_extension_flag == 1 {
// in_temporal_layer := (OperatingPointIdc >> temporal_id) & 1
// in_spatial_layer := (OperatingPointIdc >> (spatial_id + 8)) & 1
// if in_temporal_layer == 0 || in_spatial_layer == 0 {
// drop_obu()
// return
// }
//}
fmt.println("OBU size:", size)
if header.obu_type != .SEQUENCE_HEADER &&
header.obu_type != .TEMPORAL_DELIMITER &&
header.obu_type != .FRAME_HEADER &&
header.obu_type != .TILE_GROUP &&
header.obu_type != .METADATA &&
header.obu_type != .FRAME &&
header.obu_type != .REDUNDANT_FRAME_HEADER &&
header.obu_type != .TILE_LIST &&
header.obu_type != .PADDING {
return .ReservedOBU
}
#partial switch header.obu_type {
case .TEMPORAL_DELIMITER:
// do nothing. the temporal OBU has an empty payload
case .SEQUENCE_HEADER:
parse_sequence_header_obu(r)
case .FRAME:
// TODO:
}
// TODO:
//current_pos := get_position()
//payload_bits := current_pos - start_pos
//if size > 0 && header.obu_type != .TILE_GROUP && header.obu_type != .TILE_LIST && header.obu_type != .FRAME {
// trailing_bits(size * 8 - payload_bits)
//}
return nil
}
f :: proc(n: int) -> u64 {
//timing_info :: proc(r: ^Reader) {
// num_units_in_display_tick = f(r, 32)
// time_scale = f(r, 32)
// equal_picture_interval = f(r, 32)
// if equal_picture_interval == 1 {
// num_ticks_per_picture_minus_1 = uvlc(r)
// }
//}
//
//decoder_model_info :: proc(r: ^Reader) {
// buffer_delay_length_minus_1 = f(r, 5)
// num_units_in_decoding_tick = f(r, 32)
// buffer_removal_time_length_minus_1 = f(r, 5)
// frame_presentation_time_length_minus_1 = f(r, 5)
//}
//
//operating_parameters_info :: proc(r: ^Reader, op: u8) {
// n = buffer_delay_length_minus_1 + 1
// decoder_buffer_delay[op] = f(r, n)
// encoder_buffer_delay[op] = f(r, n)
// low_delay_mode_flag[op] = f(r, 1)
//}
//
//color_config :: proc(r: ^Reader) {
// high_bitdepth = f(r, 1)
//
// if seq_profile == 2 && high_bitdepth == 1 {
// twelve_bit = f(r, 1)
// BitDepth = twelve_bit == 1 ? 12 : 10
// } else if seq_profile <= 2 {
// BitDepth = high_bitdepth == 1 ? 10 : 8
// }
//
// if seq_profile == 1 {
// mono_chrome = 0
// } else {
// mono_chrome = f(r, 1)
// }
//
// num_planes = mono_chrome == 1 ? 1 : 3
// color_description_present_flag = f(r, 1)
//
// if color_description_present_flag == 1 {
// color_primaries = auto_cast f(r, 8)
// transfer_characteristic = auto_cast f(r, 8)
// matrix_coefficients = auto_cast f(r, 8)
// } else {
// color_primaries = .UNSPECIFIED
// transfer_characteristic = .UNSPECIFIED
// matrix_coefficients = .UNSPECIFIED
// }
//
// if mono_chrome == 1 {
// color_range = f(r, 1)
// subsampling_x = 1
// subsampling_y = 1
// chroma_sample_position = .UNKNOWN
// separate_uv_delta_q = 0
// return
// } else if color_primaries == .BT_709 && transfer_characteristic == .SRGB && matrix_coefficients == .IDENTITY {
// color_range = 1
// subsampling_x = 0
// subsampling_y = 0
// } else {
// color_range = f(r, 1)
//
// if seq_profile == 0 {
// subsampling_x = 1
// subsampling_y = 1
// } else if seq_profile == 1 {
// subsampling_x = 0
// subsampling_y = 0
// } else {
// if BitDepth == 12 {
// subsampling_x = f(r, 1)
//
// if subsampling_x == 1 {
// subsampling_y = f(r, 1)
// } else {
// subsampling_y = 0
// }
// } else {
// subsampling_x = 1
// subsampling_y = 0
// }
// }
//
// if subsampling_x == 1 && subsampling_y == 1 {
// chroma_sample_position = auto_cast f(r, 2)
// }
// }
//
// separate_uv_delta_q = f(r, 1)
//}
parse_sequence_header_obu :: proc(r: ^Reader) {
seq_profile := f(r, 3)
still_picture := f(r, 1)
reduced_still_picture_header := f(r, 1)
timing_info_present_flag: u8
decoder_model_info_present_flag: u8
initial_display_delay_present_flag: u8
operating_points_cnt_minus_1: u8
if reduced_still_picture_header == 1 {
// TODO: should these be saved as state ??
timing_info_present_flag = 0
decoder_model_info_present_flag = 0
initial_display_delay_present_flag = 0
operating_points_cnt_minus_1 = 0
//operating_point_idc[ 0 ] = 0
//seq_level_idx[ 0 ]
//seq_tier[ 0 ] = 0
//decoder_model_present_for_this_op[ 0 ] = 0
//initial_display_delay_present_for_this_op[ 0 ] = 0
} else {
//timing_info_present_flag = auto_cast f(r, 1)
//if timing_info_present_flag == 1 {
// timing_info(r)
// decoder_model_info_present_flag = auto_cast f(r, 1)
// if decoder_model_info_present_flag == 1 {
// decoder_model_info(r)
// }
//} else {
// decoder_model_info_present_flag = 0
//}
//initial_display_delay_present_flag = auto_cast f(r, 1)
//operating_points_cnt_minus_1 = auto_cast f(r, 5)
//for i in 0 ..=operating_points_cnt_minus_1 {
// operating_point_idc[i] = f(r, 12)
// seq_level_idx[i] = f(r, 5)
// if seq_level_idx[i] > 7 {
// seq_tier[i] = f(r, 1)
// } else {
// seq_tier[i] = 0
// }
// if decoder_model_info_present_flag == 1 {
// decoder_model_present_for_this_op[i] = f(r, 1)
// if decoder_model_present_for_this_op[i] == 1 {
// operating_parameters_info(r, i)
// }
// } else {
// decoder_model_present_for_this_op[i] = 0
// }
// if initial_display_delay_present_flag == 1 {
// initial_display_delay_present_for_this_op[i] = f(r, 1)
// if initial_display_delay_present_for_this_op[i] == 1 {
// initial_display_delay_minus_1[i] = f(r, 4)
// }
// }
//}
}
fmt.println("seq_profile:", seq_profile)
fmt.println("still_picture:", still_picture)
fmt.println("reduced_still_picture_header:", reduced_still_picture_header)
fmt.println("timing_info_present_flag:", timing_info_present_flag)
fmt.println("decoder_model_info_present_flag:", decoder_model_info_present_flag)
fmt.println("initial_display_delay_present_flag:", initial_display_delay_present_flag)
fmt.println("operating_points_cnt_minus_1:", operating_points_cnt_minus_1)
//operating_point := choose_operating_point()
//operating_point_idc_one := operating_point_idc[operating_point]
frame_width_bits_minus_1 := f(r, 4)
frame_height_bits_minus_1 := f(r, 4)
n := frame_width_bits_minus_1 + 1
max_frame_width_minus_1 := f(r, auto_cast n)
n = frame_height_bits_minus_1 + 1
max_frame_height_minus_1 := f(r, auto_cast n)
frame_id_numbers_present_flag: u8
delta_frame_id_length_minus_2: u8
additional_frame_id_length_minus_1: u8
if reduced_still_picture_header == 1 {
frame_id_numbers_present_flag = 0
} else {
frame_id_numbers_present_flag = auto_cast f(r, 1)
}
if frame_id_numbers_present_flag == 1 {
delta_frame_id_length_minus_2 = auto_cast f(r, 4)
additional_frame_id_length_minus_1 = auto_cast f(r, 3)
}
use_128x128_superblock := f(r, 1)
enable_filter_intra := f(r, 1)
enable_intra_edge_filter := f(r, 1)
fmt.println("frame_width_bits_minus_1:", frame_width_bits_minus_1)
fmt.println("frame_height_bits_minus_1:", frame_height_bits_minus_1)
fmt.println("max_frame_width_minus_1:", max_frame_width_minus_1)
fmt.println("max_frame_height_minus_1:", max_frame_height_minus_1)
fmt.println("frame_id_numbers_present_flag:", frame_id_numbers_present_flag)
fmt.println("delta_frame_id_length_minus_2:", delta_frame_id_length_minus_2)
fmt.println("additional_frame_id_length_minus_1:", additional_frame_id_length_minus_1)
fmt.println("use_128x128_superblock:", use_128x128_superblock)
fmt.println("enable_filter_intra:", enable_filter_intra)
fmt.println("enable_intra_edge_filter:", enable_intra_edge_filter)
//if reduced_still_picture_header == 1 {
// enable_interintra_compound = 0
// enable_masked_compound = 0
// enable_warped_motion = 0
// enable_dual_filter = 0
// enable_order_hint = 0
// enable_jnt_comp = 0
// enable_ref_frame_mvs = 0
// seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS
// seq_force_integer_mv = SELECT_INTEGER_MV
// OrderHintBits = 0
//} else {
// enable_interintra_compount = f(r, 1)
// enable_masked_compound = f(r, 1)
// enable_warped_motion = f(r, 1)
// enable_dual_filter = f(r, 1)
// enable_order_hint = f(r, 1)
// if enable_order_hint == 1 {
// enable_jnt_comp = f(r, 1)
// enable_ref_frame_mvs = f(r, 1)
// } else {
// enable_jnt_comp = 0
// enable_ref_frame_mvs = 0
// }
// seq_choose_screen_content_tools = f(r, 1)
// if seq_choose_screen_content_tools == 1 {
// seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS
// } else {
// seq_force_screen_content_tools = f(r, 1)
// }
// if seq_force_screen_content_tools > 0 {
// seq_choose_integer_mv = f(r, 1)
// if seq_choose_integer_mv == 1 {
// seq_force_integer_mv = SELECT_INTEGER_MV
// } else {
// seq_force_integer_mv = f(r, 1)
// }
// } else {
// seq_force_integer_mv = SELECT_INTEGER_MV
// }
// if enable_order_hint == 1 {
// order_hint_bits_minus_1 = f(r, 3)
// OrderHintBits = order_hint_bits_minus_1 + 1
// } else {
// OrderHintBits = 0
// }
//}
//enable_superres = f(r, 1)
//enable_cdef = f(r, 1)
//enable_restoration = f(r, 1)
//color_config()
//film_grain_params_present = f(r, 1)
}
f :: proc(r: ^Reader, n: int) -> u64 {
x: u64 = 0
for i in 0 ..< n {
x = 2 * x + auto_cast read_bit()
// TODO: maybe get rid of or_break and propagate the error??
x = 2 * x + auto_cast read_bit(r) or_break
}
return x
}
leb128 :: proc() -> u64 {
leb128 :: proc(r: ^Reader) -> u64 {
value: u64 = 0
leb128_bytes := 0
for i: u64 = 0; i < 8; i += 1 {
leb128_byte := f(8)
leb128_byte := f(r, 8)
value |= ((leb128_byte & 0x7f) << (i * 7))
leb128_bytes += 1
@@ -68,3 +460,22 @@ leb128 :: proc() -> u64 {
return value
}
uvlc :: proc(r: ^Reader) -> u64 {
leading_zeros: u64 = 0
for {
done := f(r, 1)
if done == 1 {
break
}
leading_zeros += 1
}
if leading_zeros >= 32 {
return (1 << 32) - 1
}
value := f(r, auto_cast leading_zeros)
return value + (1 << leading_zeros) - 1
}