General
This section presents the syntax structures in a tabular form. The meaning of
each of the syntax elements is presented in Syntax Structures.
This specification defines a low-overhead bitstream format as a sequence of the OBU syntactical elements defined in this section.
When using this format, obu_has_size_field must be equal to 1.
For applications requiring a format where it is easier to skip through frames or temporal units,
a length-delimited bitstream format is defined in Annex B.
Derived specifications, such as container formats enabling storage of AV1 videos together with audio or
subtitles, should indicate which of these formats they rely on.
Other methods of packing OBUs into a bitstream format are also allowed.
OBU syntax
General OBU syntax
open_bitstream_unit( sz ) { |
Type |
obu_header() |
|
if ( obu_has_size_field ) { |
|
obu_size |
leb128() |
} else { |
|
obu_size = sz - 1 - obu_extension_flag |
|
} |
|
startPosition = get_position( ) |
|
if ( obu_type != OBU_SEQUENCE_HEADER && |
|
obu_type != OBU_TEMPORAL_DELIMITER && |
|
OperatingPointIdc != 0 && |
|
obu_extension_flag == 1 ) |
|
{ |
|
inTemporalLayer = (OperatingPointIdc >> temporal_id ) & 1 |
|
inSpatialLayer = (OperatingPointIdc >> ( spatial_id + 8 ) ) & 1 |
|
if ( !inTemporalLayer || ! inSpatialLayer ) { |
|
drop_obu( ) |
|
return |
|
} |
|
} |
|
if ( obu_type == OBU_SEQUENCE_HEADER ) |
|
sequence_header_obu( ) |
|
else if ( obu_type == OBU_TEMPORAL_DELIMITER ) |
|
temporal_delimiter_obu( ) |
|
else if ( obu_type == OBU_FRAME_HEADER ) |
|
frame_header_obu( ) |
|
else if ( obu_type == OBU_REDUNDANT_FRAME_HEADER ) |
|
frame_header_obu( ) |
|
else if ( obu_type == OBU_TILE_GROUP ) |
|
tile_group_obu( obu_size ) |
|
else if ( obu_type == OBU_METADATA ) |
|
metadata_obu( ) |
|
else if ( obu_type == OBU_FRAME ) |
|
frame_obu( obu_size ) |
|
else if ( obu_type == OBU_TILE_LIST ) |
|
tile_list_obu( ) |
|
else if ( obu_type == OBU_PADDING ) |
|
padding_obu( ) |
|
else |
|
reserved_obu( ) |
|
currentPosition = get_position( ) |
|
payloadBits = currentPosition - startPosition |
|
if ( obu_size > 0 && obu_type != OBU_TILE_GROUP && |
|
obu_type != OBU_TILE_LIST && |
|
obu_type != OBU_FRAME ) { |
|
trailing_bits( obu_size * 8 - payloadBits ) |
|
} |
|
} |
|
obu_header() { |
Type |
obu_forbidden_bit |
f(1) |
obu_type |
f(4) |
obu_extension_flag |
f(1) |
obu_has_size_field |
f(1) |
obu_reserved_1bit |
f(1) |
if ( obu_extension_flag == 1 ) |
|
obu_extension_header() |
|
} |
|
obu_extension_header() { |
Type |
temporal_id |
f(3) |
spatial_id |
f(2) |
extension_header_reserved_3bits |
f(3) |
} |
|
Trailing bits syntax
trailing_bits( nbBits ) { |
Type |
trailing_one_bit |
f(1) |
nbBits-- |
|
while ( nbBits > 0 ) { |
|
trailing_zero_bit |
f(1) |
nbBits-- |
|
} |
|
} |
|
Byte alignment syntax
byte_alignment( ) { |
Type |
while ( get_position( ) & 7 ) |
|
zero_bit |
f(1) |
} |
|
Reserved OBU syntax
Note: Reserved OBUs do not have a defined syntax. The obu_type reserved
values are reserved for future use. Decoders should ignore the entire OBU if
they do not understand the obu_type. Ignoring the OBU can be done based on
obu_size. The last byte of the valid content of the payload data for this OBU type
is considered to be the last byte that is not equal to zero.
This rule is to prevent the dropping of valid bytes by systems that
interpret trailing zero bytes as a continuation of the trailing bits in an OBU.
This implies that when any payload data is present for this OBU type,
at least one byte of the payload data (including the trailing bit) shall not be equal to 0.
sequence_header_obu( ) { |
Type |
seq_profile |
f(3) |
still_picture |
f(1) |
reduced_still_picture_header |
f(1) |
if ( reduced_still_picture_header ) { |
|
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 ] |
f(5) |
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 |
f(1) |
if ( timing_info_present_flag ) { |
|
timing_info( ) |
|
decoder_model_info_present_flag |
f(1) |
if ( decoder_model_info_present_flag ) { |
|
decoder_model_info( ) |
|
} |
|
} else { |
|
decoder_model_info_present_flag = 0 |
|
} |
|
initial_display_delay_present_flag |
f(1) |
operating_points_cnt_minus_1 |
f(5) |
for ( i = 0; i <= operating_points_cnt_minus_1; i++ ) { |
|
operating_point_idc[ i ] |
f(12) |
seq_level_idx[ i ] |
f(5) |
if ( seq_level_idx[ i ] > 7 ) { |
|
seq_tier[ i ] |
f(1) |
} else { |
|
seq_tier[ i ] = 0 |
|
} |
|
if ( decoder_model_info_present_flag ) { |
|
decoder_model_present_for_this_op[ i ] |
f(1) |
if ( decoder_model_present_for_this_op[ i ] ) { |
|
operating_parameters_info( i ) |
|
} |
|
} else { |
|
decoder_model_present_for_this_op[ i ] = 0 |
|
} |
|
if ( initial_display_delay_present_flag ) { |
|
initial_display_delay_present_for_this_op[ i ] |
f(1) |
if ( initial_display_delay_present_for_this_op[ i ] ) { |
|
initial_display_delay_minus_1[ i ] |
f(4) |
} |
|
} |
|
} |
|
} |
|
operatingPoint = choose_operating_point( ) |
|
OperatingPointIdc = operating_point_idc[ operatingPoint ] |
|
frame_width_bits_minus_1 |
f(4) |
frame_height_bits_minus_1 |
f(4) |
n = frame_width_bits_minus_1 + 1 |
|
max_frame_width_minus_1 |
f(n) |
n = frame_height_bits_minus_1 + 1 |
|
max_frame_height_minus_1 |
f(n) |
if ( reduced_still_picture_header ) |
|
frame_id_numbers_present_flag = 0 |
|
else |
|
frame_id_numbers_present_flag |
f(1) |
if ( frame_id_numbers_present_flag ) { |
|
delta_frame_id_length_minus_2 |
f(4) |
additional_frame_id_length_minus_1 |
f(3) |
} |
|
use_128x128_superblock |
f(1) |
enable_filter_intra |
f(1) |
enable_intra_edge_filter |
f(1) |
if ( reduced_still_picture_header ) { |
|
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_compound |
f(1) |
enable_masked_compound |
f(1) |
enable_warped_motion |
f(1) |
enable_dual_filter |
f(1) |
enable_order_hint |
f(1) |
if ( enable_order_hint ) { |
|
enable_jnt_comp |
f(1) |
enable_ref_frame_mvs |
f(1) |
} else { |
|
enable_jnt_comp = 0 |
|
enable_ref_frame_mvs = 0 |
|
} |
|
seq_choose_screen_content_tools |
f(1) |
if ( seq_choose_screen_content_tools ) { |
|
seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS |
|
} else { |
|
seq_force_screen_content_tools |
f(1) |
} |
|
|
|
if ( seq_force_screen_content_tools > 0 ) { |
|
seq_choose_integer_mv |
f(1) |
if ( seq_choose_integer_mv ) { |
|
seq_force_integer_mv = SELECT_INTEGER_MV |
|
} else { |
|
seq_force_integer_mv |
f(1) |
} |
|
} else { |
|
seq_force_integer_mv = SELECT_INTEGER_MV |
|
} |
|
if ( enable_order_hint ) { |
|
order_hint_bits_minus_1 |
f(3) |
OrderHintBits = order_hint_bits_minus_1 + 1 |
|
} else { |
|
OrderHintBits = 0 |
|
} |
|
} |
|
enable_superres |
f(1) |
enable_cdef |
f(1) |
enable_restoration |
f(1) |
color_config( ) |
|
film_grain_params_present |
f(1) |
} |
|
Color config syntax
color_config( ) { |
Type |
high_bitdepth |
f(1) |
if ( seq_profile == 2 && high_bitdepth ) { |
|
twelve_bit |
f(1) |
BitDepth = twelve_bit ? 12 : 10 |
|
} else if ( seq_profile <= 2 ) { |
|
BitDepth = high_bitdepth ? 10 : 8 |
|
} |
|
if ( seq_profile == 1 ) { |
|
mono_chrome = 0 |
|
} else { |
|
mono_chrome |
f(1) |
} |
|
NumPlanes = mono_chrome ? 1 : 3 |
|
color_description_present_flag |
f(1) |
if ( color_description_present_flag ) { |
|
color_primaries |
f(8) |
transfer_characteristics |
f(8) |
matrix_coefficients |
f(8) |
} else { |
|
color_primaries = CP_UNSPECIFIED |
|
transfer_characteristics = TC_UNSPECIFIED |
|
matrix_coefficients = MC_UNSPECIFIED |
|
} |
|
if ( mono_chrome ) { |
|
color_range |
f(1) |
subsampling_x = 1 |
|
subsampling_y = 1 |
|
chroma_sample_position = CSP_UNKNOWN |
|
separate_uv_delta_q = 0 |
|
return |
|
} else if ( color_primaries == CP_BT_709 && |
|
transfer_characteristics == TC_SRGB && |
|
matrix_coefficients == MC_IDENTITY ) { |
|
color_range = 1 |
|
subsampling_x = 0 |
|
subsampling_y = 0 |
|
} else { |
|
color_range |
f(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(1) |
if ( subsampling_x ) |
|
subsampling_y |
f(1) |
else |
|
subsampling_y = 0 |
|
} else { |
|
subsampling_x = 1 |
|
subsampling_y = 0 |
|
} |
|
} |
|
if ( subsampling_x && subsampling_y ) { |
|
chroma_sample_position |
f(2) |
} |
|
} |
|
separate_uv_delta_q |
f(1) |
} |
|
Timing info syntax
timing_info( ) { |
Type |
num_units_in_display_tick |
f(32) |
time_scale |
f(32) |
equal_picture_interval |
f(1) |
if ( equal_picture_interval ) |
|
num_ticks_per_picture_minus_1 |
uvlc() |
} |
|
Decoder model info syntax
decoder_model_info( ) { |
Type |
buffer_delay_length_minus_1 |
f(5) |
num_units_in_decoding_tick |
f(32) |
buffer_removal_time_length_minus_1 |
f(5) |
frame_presentation_time_length_minus_1 |
f(5) |
} |
|
Operating parameters info syntax
operating_parameters_info( op ) { |
Type |
n = buffer_delay_length_minus_1 + 1 |
|
decoder_buffer_delay[ op ] |
f(n) |
encoder_buffer_delay[ op ] |
f(n) |
low_delay_mode_flag[ op ] |
f(1) |
} |
|
Temporal delimiter obu syntax
temporal_delimiter_obu( ) { |
Type |
SeenFrameHeader = 0 |
|
} |
|
Note: The temporal delimiter has an empty payload.
Padding OBU syntax
padding_obu( ) { |
Type |
for ( i = 0; i < obu_padding_length; i++ ) |
|
obu_padding_byte |
f(8) |
} |
|
Note: obu_padding_length is not coded in the bitstream but can be computed
based on obu_size minus the number of trailing bytes.
In practice, though, since this is
padding data meant to be skipped, decoders do not need to determine either
that length nor the number of trailing bytes. They can ignore the entire OBU.
Ignoring the OBU can be done based on obu_size.
The last byte of the valid content of the payload data for this OBU type
is considered to be the last byte that is not equal to zero.
This rule is to prevent the dropping of valid bytes by systems that
interpret trailing zero bytes as a continuation of the trailing bits in an OBU.
This implies that when any payload data is present for this OBU type,
at least one byte of the payload data (including the trailing bit) shall not be equal to 0.
metadata_obu( ) { |
Type |
metadata_type |
leb128() |
if ( metadata_type == METADATA_TYPE_ITUT_T35 ) |
|
metadata_itut_t35( ) |
|
else if ( metadata_type == METADATA_TYPE_HDR_CLL ) |
|
metadata_hdr_cll( ) |
|
else if ( metadata_type == METADATA_TYPE_HDR_MDCV ) |
|
metadata_hdr_mdcv( ) |
|
else if ( metadata_type == METADATA_TYPE_SCALABILITY ) |
|
metadata_scalability( ) |
|
else if ( metadata_type == METADATA_TYPE_TIMECODE ) |
|
metadata_timecode( ) |
|
} |
|
Note: The exact syntax of metadata_obu is not defined
in this specification when metadata_type is equal to
a value reserved for future use or a user private value.
Decoders should ignore the entire OBU if they do not understand the metadata_type.
The last byte of the valid content of the data is
considered to be the last byte that is not equal to zero. This rule is to
prevent the dropping of valid bytes by systems that interpret trailing zero
bytes as a padding continuation of the trailing bits in an OBU.
This implies that when any payload data is present for this OBU type,
at least one byte of the payload data (including the trailing bit) shall not be equal to 0.
metadata_itut_t35( ) { |
Type |
itu_t_t35_country_code |
f(8) |
if ( itu_t_t35_country_code == 0xFF ) { |
|
itu_t_t35_country_code_extension_byte |
f(8) |
} |
|
itu_t_t35_payload_bytes |
|
} |
|
Note: The exact syntax of itu_t_t35_payload_bytes is not defined
in this specification. External
specifications can define the syntax.
Decoders should ignore the entire OBU if they do not understand it.
The last byte of the valid content of the data is
considered to be the last byte that is not equal to zero. This rule is to
prevent the dropping of valid bytes by systems that interpret trailing zero
bytes as a padding continuation of the trailing bits in an OBU.
This implies that when any payload data is present for this OBU type,
at least one byte of the payload data (including the trailing bit) shall not be equal to 0.
Metadata high dynamic range content light level syntax
metadata_hdr_cll( ) { |
Type |
max_cll |
f(16) |
max_fall |
f(16) |
} |
|
metadata_hdr_mdcv( ) { |
Type |
for ( i = 0; i < 3; i++ ) { |
|
primary_chromaticity_x[ i ] |
f(16) |
primary_chromaticity_y[ i ] |
f(16) |
} |
|
white_point_chromaticity_x |
f(16) |
white_point_chromaticity_y |
f(16) |
luminance_max |
f(32) |
luminance_min |
f(32) |
} |
|
metadata_scalability( ) { |
Type |
scalability_mode_idc |
f(8) |
if ( scalability_mode_idc == SCALABILITY_SS ) |
|
scalability_structure( ) |
|
} |
|
Scalability structure syntax
scalability_structure( ) { |
Type |
spatial_layers_cnt_minus_1 |
f(2) |
spatial_layer_dimensions_present_flag |
f(1) |
spatial_layer_description_present_flag |
f(1) |
temporal_group_description_present_flag |
f(1) |
scalability_structure_reserved_3bits |
f(3) |
if ( spatial_layer_dimensions_present_flag ) { |
|
for ( i = 0; i <= spatial_layers_cnt_minus_1 ; i++ ) { |
|
spatial_layer_max_width[ i ] |
f(16) |
spatial_layer_max_height[ i ] |
f(16) |
} |
|
} |
|
if ( spatial_layer_description_present_flag ) { |
|
for ( i = 0; i <= spatial_layers_cnt_minus_1; i++ ) |
|
spatial_layer_ref_id[ i ] |
f(8) |
} |
|
if ( temporal_group_description_present_flag ) { |
|
temporal_group_size |
f(8) |
for ( i = 0; i < temporal_group_size; i++ ) { |
|
temporal_group_temporal_id[ i ] |
f(3) |
temporal_group_temporal_switching_up_point_flag[ i ] |
f(1) |
temporal_group_spatial_switching_up_point_flag[ i ] |
f(1) |
temporal_group_ref_cnt[ i ] |
f(3) |
for ( j = 0; j < temporal_group_ref_cnt[ i ]; j++ ) { |
|
temporal_group_ref_pic_diff[ i ][ j ] |
f(8) |
} |
|
} |
|
} |
|
} |
|
metadata_timecode( ) { |
Type |
counting_type |
f(5) |
full_timestamp_flag |
f(1) |
discontinuity_flag |
f(1) |
cnt_dropped_flag |
f(1) |
n_frames |
f(9) |
if ( full_timestamp_flag ) { |
|
seconds_value |
f(6) |
minutes_value |
f(6) |
hours_value |
f(5) |
} else { |
|
seconds_flag |
f(1) |
if ( seconds_flag ) { |
|
seconds_value |
f(6) |
minutes_flag |
f(1) |
if ( minutes_flag ) { |
|
minutes_value |
f(6) |
hours_flag |
f(1) |
if ( hours_flag ) { |
|
hours_value |
f(5) |
} |
|
} |
|
} |
|
} |
|
time_offset_length |
f(5) |
if ( time_offset_length > 0 ) { |
|
time_offset_value |
f(time_offset_length) |
} |
|
} |
|
frame_header_obu( ) { |
Type |
if ( SeenFrameHeader == 1 ) { |
|
frame_header_copy() |
|
} else { |
|
SeenFrameHeader = 1 |
|
uncompressed_header( ) |
|
if ( show_existing_frame ) { |
|
decode_frame_wrapup( ) |
|
SeenFrameHeader = 0 |
|
} else { |
|
TileNum = 0 |
|
SeenFrameHeader = 1 |
|
} |
|
} |
|
} |
|
uncompressed_header( ) { |
Type |
if ( frame_id_numbers_present_flag ) { |
|
idLen = ( additional_frame_id_length_minus_1 + |
|
delta_frame_id_length_minus_2 + 3 ) |
|
} |
|
allFrames = (1 << NUM_REF_FRAMES) - 1 |
|
if ( reduced_still_picture_header ) { |
|
show_existing_frame = 0 |
|
frame_type = KEY_FRAME |
|
FrameIsIntra = 1 |
|
show_frame = 1 |
|
showable_frame = 0 |
|
} else { |
|
show_existing_frame |
f(1) |
if ( show_existing_frame == 1 ) { |
|
frame_to_show_map_idx |
f(3) |
if ( decoder_model_info_present_flag && !equal_picture_interval ) { |
|
temporal_point_info( ) |
|
} |
|
refresh_frame_flags = 0 |
|
if ( frame_id_numbers_present_flag ) { |
|
display_frame_id |
f(idLen) |
} |
|
frame_type = RefFrameType[ frame_to_show_map_idx ] |
|
if ( frame_type == KEY_FRAME ) { |
|
refresh_frame_flags = allFrames |
|
} |
|
if ( film_grain_params_present ) { |
|
load_grain_params( frame_to_show_map_idx ) |
|
} |
|
return |
|
} |
|
frame_type |
f(2) |
FrameIsIntra = (frame_type == INTRA_ONLY_FRAME || |
|
frame_type == KEY_FRAME) |
|
show_frame |
f(1) |
if ( show_frame && decoder_model_info_present_flag && !equal_picture_interval ) { |
|
temporal_point_info( ) |
|
} |
|
if ( show_frame ) { |
|
showable_frame = frame_type != KEY_FRAME |
|
} else { |
|
showable_frame |
f(1) |
} |
|
if ( frame_type == SWITCH_FRAME || |
|
( frame_type == KEY_FRAME && show_frame ) ) |
|
error_resilient_mode = 1 |
|
else |
|
error_resilient_mode |
f(1) |
} |
|
if ( frame_type == KEY_FRAME && show_frame ) { |
|
for ( i = 0; i < NUM_REF_FRAMES; i++ ) { |
|
RefValid[ i ] = 0 |
|
RefOrderHint[ i ] = 0 |
|
} |
|
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
OrderHints[ LAST_FRAME + i ] = 0 |
|
} |
|
} |
|
disable_cdf_update |
f(1) |
if ( seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS ) { |
|
allow_screen_content_tools |
f(1) |
} else { |
|
allow_screen_content_tools = seq_force_screen_content_tools |
|
} |
|
if ( allow_screen_content_tools ) { |
|
if ( seq_force_integer_mv == SELECT_INTEGER_MV ) { |
|
force_integer_mv |
f(1) |
} else { |
|
force_integer_mv = seq_force_integer_mv |
|
} |
|
} else { |
|
force_integer_mv = 0 |
|
} |
|
if ( FrameIsIntra ) { |
|
force_integer_mv = 1 |
|
} |
|
if ( frame_id_numbers_present_flag ) { |
|
PrevFrameID = current_frame_id |
|
current_frame_id |
f(idLen) |
mark_ref_frames( idLen ) |
|
} else { |
|
current_frame_id = 0 |
|
} |
|
if ( frame_type == SWITCH_FRAME ) |
|
frame_size_override_flag = 1 |
|
else if ( reduced_still_picture_header ) |
|
frame_size_override_flag = 0 |
|
else |
|
frame_size_override_flag |
f(1) |
order_hint |
f(OrderHintBits) |
OrderHint = order_hint |
|
if ( FrameIsIntra || error_resilient_mode ) { |
|
primary_ref_frame = PRIMARY_REF_NONE |
|
} else { |
|
primary_ref_frame |
f(3) |
} |
|
if ( decoder_model_info_present_flag ) { |
|
buffer_removal_time_present_flag |
f(1) |
if ( buffer_removal_time_present_flag ) { |
|
for ( opNum = 0; opNum <= operating_points_cnt_minus_1; opNum++ ) { |
|
if ( decoder_model_present_for_this_op[ opNum ] ) { |
|
opPtIdc = operating_point_idc[ opNum ] |
|
inTemporalLayer = ( opPtIdc >> temporal_id ) & 1 |
|
inSpatialLayer = ( opPtIdc >> ( spatial_id + 8 ) ) & 1 |
|
if ( opPtIdc == 0 || ( inTemporalLayer && inSpatialLayer ) ) { |
|
n = buffer_removal_time_length_minus_1 + 1 |
|
buffer_removal_time[ opNum ] |
f(n) |
} |
|
} |
|
} |
|
} |
|
} |
|
allow_high_precision_mv = 0 |
|
use_ref_frame_mvs = 0 |
|
allow_intrabc = 0 |
|
if ( frame_type == SWITCH_FRAME || |
|
( frame_type == KEY_FRAME && show_frame ) ) { |
|
refresh_frame_flags = allFrames |
|
} else { |
|
refresh_frame_flags |
f(8) |
} |
|
if ( !FrameIsIntra || refresh_frame_flags != allFrames ) { |
|
if ( error_resilient_mode && enable_order_hint ) { |
|
for ( i = 0; i < NUM_REF_FRAMES; i++) { |
|
ref_order_hint[ i ] |
f(OrderHintBits) |
if ( ref_order_hint[ i ] != RefOrderHint[ i ] ) { |
|
RefValid[ i ] = 0 |
|
} |
|
} |
|
} |
|
} |
|
if ( FrameIsIntra ) { |
|
frame_size( ) |
|
render_size( ) |
|
if ( allow_screen_content_tools && UpscaledWidth == FrameWidth ) { |
|
allow_intrabc |
f(1) |
} |
|
} else { |
|
if ( !enable_order_hint ) { |
|
frame_refs_short_signaling = 0 |
|
} else { |
|
frame_refs_short_signaling |
f(1) |
if ( frame_refs_short_signaling ) { |
|
last_frame_idx |
f(3) |
gold_frame_idx |
f(3) |
set_frame_refs() |
|
} |
|
} |
|
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
if ( !frame_refs_short_signaling ) |
|
ref_frame_idx[ i ] |
f(3) |
if ( frame_id_numbers_present_flag ) { |
|
n = delta_frame_id_length_minus_2 + 2 |
|
delta_frame_id_minus_1 |
f(n) |
DeltaFrameId = delta_frame_id_minus_1 + 1 |
|
expectedFrameId[ i ] = ((current_frame_id + (1 << idLen) - |
|
DeltaFrameId ) % (1 << idLen)) |
|
} |
|
} |
|
if ( frame_size_override_flag && !error_resilient_mode ) { |
|
frame_size_with_refs( ) |
|
} else { |
|
frame_size( ) |
|
render_size( ) |
|
} |
|
if ( force_integer_mv ) { |
|
allow_high_precision_mv = 0 |
|
} else { |
|
allow_high_precision_mv |
f(1) |
} |
|
read_interpolation_filter( ) |
|
is_motion_mode_switchable |
f(1) |
if ( error_resilient_mode || !enable_ref_frame_mvs ) { |
|
use_ref_frame_mvs = 0 |
|
} else { |
|
use_ref_frame_mvs |
f(1) |
} |
|
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
refFrame = LAST_FRAME + i |
|
hint = RefOrderHint[ ref_frame_idx[ i ] ] |
|
OrderHints[ refFrame ] = hint |
|
if ( !enable_order_hint ) { |
|
RefFrameSignBias[ refFrame ] = 0 |
|
} else { |
|
RefFrameSignBias[ refFrame ] = get_relative_dist( hint, OrderHint) > 0 |
|
} |
|
} |
|
} |
|
if ( reduced_still_picture_header || disable_cdf_update ) |
|
disable_frame_end_update_cdf = 1 |
|
else |
|
disable_frame_end_update_cdf |
f(1) |
if ( primary_ref_frame == PRIMARY_REF_NONE ) { |
|
init_non_coeff_cdfs( ) |
|
setup_past_independence( ) |
|
} else { |
|
load_cdfs( ref_frame_idx[ primary_ref_frame ] ) |
|
load_previous( ) |
|
} |
|
if ( use_ref_frame_mvs == 1 ) |
|
motion_field_estimation( ) |
|
tile_info( ) |
|
quantization_params( ) |
|
segmentation_params( ) |
|
delta_q_params( ) |
|
delta_lf_params( ) |
|
if ( primary_ref_frame == PRIMARY_REF_NONE ) { |
|
init_coeff_cdfs( ) |
|
} else { |
|
load_previous_segment_ids( ) |
|
} |
|
CodedLossless = 1 |
|
for ( segmentId = 0; segmentId < MAX_SEGMENTS; segmentId++ ) { |
|
qindex = get_qindex( 1, segmentId ) |
|
LosslessArray[ segmentId ] = qindex == 0 && DeltaQYDc == 0 && |
|
DeltaQUAc == 0 && DeltaQUDc == 0 && |
|
DeltaQVAc == 0 && DeltaQVDc == 0 |
|
if ( !LosslessArray[ segmentId ] ) |
|
CodedLossless = 0 |
|
if ( using_qmatrix ) { |
|
if ( LosslessArray[ segmentId ] ) { |
|
SegQMLevel[ 0 ][ segmentId ] = 15 |
|
SegQMLevel[ 1 ][ segmentId ] = 15 |
|
SegQMLevel[ 2 ][ segmentId ] = 15 |
|
} else { |
|
SegQMLevel[ 0 ][ segmentId ] = qm_y |
|
SegQMLevel[ 1 ][ segmentId ] = qm_u |
|
SegQMLevel[ 2 ][ segmentId ] = qm_v |
|
} |
|
} |
|
} |
|
AllLossless = CodedLossless && ( FrameWidth == UpscaledWidth ) |
|
loop_filter_params( ) |
|
cdef_params( ) |
|
lr_params( ) |
|
read_tx_mode( ) |
|
frame_reference_mode( ) |
|
skip_mode_params( ) |
|
if ( FrameIsIntra || |
|
error_resilient_mode || |
|
!enable_warped_motion ) |
|
allow_warped_motion = 0 |
|
else |
|
allow_warped_motion |
f(1) |
reduced_tx_set |
f(1) |
global_motion_params( ) |
|
film_grain_params( ) |
|
} |
|
Get relative distance function
This function computes the distance between
two order hints by sign extending the result of subtracting the values.
get_relative_dist( a, b ) { |
Type |
if ( !enable_order_hint ) |
|
return 0 |
|
diff = a - b |
|
m = 1 << (OrderHintBits - 1) |
|
diff = (diff & (m - 1)) - (diff & m) |
|
return diff |
|
} |
|
Reference frame marking function
mark_ref_frames( idLen ) { |
Type |
diffLen = delta_frame_id_length_minus_2 + 2 |
|
for ( i = 0; i < NUM_REF_FRAMES; i++ ) { |
|
if ( current_frame_id > ( 1 << diffLen ) ) { |
|
if ( RefFrameId[ i ] > current_frame_id || |
|
RefFrameId[ i ] < ( current_frame_id - ( 1 << diffLen ) ) ) |
|
RefValid[ i ] = 0 |
|
} else { |
|
if ( RefFrameId[ i ] > current_frame_id && |
|
RefFrameId[ i ] < ( ( 1 << idLen ) + |
|
current_frame_id - |
|
( 1 << diffLen ) ) ) |
|
RefValid[ i ] = 0 |
|
} |
|
} |
|
} |
|
Frame size syntax
frame_size( ) { |
Type |
if ( frame_size_override_flag ) { |
|
n = frame_width_bits_minus_1 + 1 |
|
frame_width_minus_1 |
f(n) |
n = frame_height_bits_minus_1 + 1 |
|
frame_height_minus_1 |
f(n) |
FrameWidth = frame_width_minus_1 + 1 |
|
FrameHeight = frame_height_minus_1 + 1 |
|
} else { |
|
FrameWidth = max_frame_width_minus_1 + 1 |
|
FrameHeight = max_frame_height_minus_1 + 1 |
|
} |
|
superres_params( ) |
|
compute_image_size( ) |
|
} |
|
Render size syntax
render_size( ) { |
Type |
render_and_frame_size_different |
f(1) |
if ( render_and_frame_size_different == 1 ) { |
|
render_width_minus_1 |
f(16) |
render_height_minus_1 |
f(16) |
RenderWidth = render_width_minus_1 + 1 |
|
RenderHeight = render_height_minus_1 + 1 |
|
} else { |
|
RenderWidth = UpscaledWidth |
|
RenderHeight = FrameHeight |
|
} |
|
} |
|
Frame size with refs syntax
frame_size_with_refs( ) { |
Type |
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
found_ref |
f(1) |
if ( found_ref == 1 ) { |
|
UpscaledWidth = RefUpscaledWidth[ ref_frame_idx[ i ] ] |
|
FrameWidth = UpscaledWidth |
|
FrameHeight = RefFrameHeight[ ref_frame_idx[ i ] ] |
|
RenderWidth = RefRenderWidth[ ref_frame_idx[ i ] ] |
|
RenderHeight = RefRenderHeight[ ref_frame_idx[ i ] ] |
|
break |
|
} |
|
} |
|
if ( found_ref == 0 ) { |
|
frame_size( ) |
|
render_size( ) |
|
} else { |
|
superres_params( ) |
|
compute_image_size( ) |
|
} |
|
} |
|
Superres params syntax
superres_params() { |
Type |
if ( enable_superres ) |
|
use_superres |
f(1) |
else |
|
use_superres = 0 |
|
if ( use_superres ) { |
|
coded_denom |
f(SUPERRES_DENOM_BITS) |
SuperresDenom = coded_denom + SUPERRES_DENOM_MIN |
|
} else { |
|
SuperresDenom = SUPERRES_NUM |
|
} |
|
UpscaledWidth = FrameWidth |
|
FrameWidth = (UpscaledWidth * SUPERRES_NUM + |
|
(SuperresDenom / 2)) / SuperresDenom |
|
} |
|
Compute image size function
compute_image_size( ) { |
Type |
MiCols = 2 * ( ( FrameWidth + 7 ) >> 3 ) |
|
MiRows = 2 * ( ( FrameHeight + 7 ) >> 3 ) |
|
} |
|
Interpolation filter syntax
read_interpolation_filter( ) { |
Type |
is_filter_switchable |
f(1) |
if ( is_filter_switchable == 1 ) { |
|
interpolation_filter = SWITCHABLE |
|
} else { |
|
interpolation_filter |
f(2) |
} |
|
} |
|
Loop filter params syntax
loop_filter_params( ) { |
Type |
if ( CodedLossless || allow_intrabc ) { |
|
loop_filter_level[ 0 ] = 0 |
|
loop_filter_level[ 1 ] = 0 |
|
loop_filter_ref_deltas[ INTRA_FRAME ] = 1 |
|
loop_filter_ref_deltas[ LAST_FRAME ] = 0 |
|
loop_filter_ref_deltas[ LAST2_FRAME ] = 0 |
|
loop_filter_ref_deltas[ LAST3_FRAME ] = 0 |
|
loop_filter_ref_deltas[ BWDREF_FRAME ] = 0 |
|
loop_filter_ref_deltas[ GOLDEN_FRAME ] = -1 |
|
loop_filter_ref_deltas[ ALTREF_FRAME ] = -1 |
|
loop_filter_ref_deltas[ ALTREF2_FRAME ] = -1 |
|
for ( i = 0; i < 2; i++ ) { |
|
loop_filter_mode_deltas[ i ] = 0 |
|
} |
|
return |
|
} |
|
loop_filter_level[ 0 ] |
f(6) |
loop_filter_level[ 1 ] |
f(6) |
if ( NumPlanes > 1 ) { |
|
if ( loop_filter_level[ 0 ] || loop_filter_level[ 1 ] ) { |
|
loop_filter_level[ 2 ] |
f(6) |
loop_filter_level[ 3 ] |
f(6) |
} |
|
} |
|
loop_filter_sharpness |
f(3) |
loop_filter_delta_enabled |
f(1) |
if ( loop_filter_delta_enabled == 1 ) { |
|
loop_filter_delta_update |
f(1) |
if ( loop_filter_delta_update == 1 ) { |
|
for ( i = 0; i < TOTAL_REFS_PER_FRAME; i++ ) { |
|
update_ref_delta |
f(1) |
if ( update_ref_delta == 1 ) |
|
loop_filter_ref_deltas[ i ] |
su(1+6) |
} |
|
for ( i = 0; i < 2; i++ ) { |
|
update_mode_delta |
f(1) |
if ( update_mode_delta == 1 ) |
|
loop_filter_mode_deltas[ i ] |
su(1+6) |
} |
|
} |
|
} |
|
} |
|
Quantization params syntax
quantization_params( ) { |
Type |
base_q_idx |
f(8) |
DeltaQYDc = read_delta_q( ) |
|
if ( NumPlanes > 1 ) { |
|
if ( separate_uv_delta_q ) |
|
diff_uv_delta |
f(1) |
else |
|
diff_uv_delta = 0 |
|
DeltaQUDc = read_delta_q( ) |
|
DeltaQUAc = read_delta_q( ) |
|
if ( diff_uv_delta ) { |
|
DeltaQVDc = read_delta_q( ) |
|
DeltaQVAc = read_delta_q( ) |
|
} else { |
|
DeltaQVDc = DeltaQUDc |
|
DeltaQVAc = DeltaQUAc |
|
} |
|
} else { |
|
DeltaQUDc = 0 |
|
DeltaQUAc = 0 |
|
DeltaQVDc = 0 |
|
DeltaQVAc = 0 |
|
} |
|
using_qmatrix |
f(1) |
if ( using_qmatrix ) { |
|
qm_y |
f(4) |
qm_u |
f(4) |
if ( !separate_uv_delta_q ) |
|
qm_v = qm_u |
|
else |
|
qm_v |
f(4) |
} |
|
} |
|
Delta quantizer syntax
read_delta_q( ) { |
Type |
delta_coded |
f(1) |
if ( delta_coded ) { |
|
delta_q |
su(1+6) |
} else { |
|
delta_q = 0 |
|
} |
|
return delta_q |
|
} |
|
Segmentation params syntax
segmentation_params( ) { |
Type |
segmentation_enabled |
f(1) |
if ( segmentation_enabled == 1 ) { |
|
if ( primary_ref_frame == PRIMARY_REF_NONE ) { |
|
segmentation_update_map = 1 |
|
segmentation_temporal_update = 0 |
|
segmentation_update_data = 1 |
|
} else { |
|
segmentation_update_map |
f(1) |
if ( segmentation_update_map == 1 ) |
|
segmentation_temporal_update |
f(1) |
segmentation_update_data |
f(1) |
} |
|
if ( segmentation_update_data == 1 ) { |
|
for ( i = 0; i < MAX_SEGMENTS; i++ ) { |
|
for ( j = 0; j < SEG_LVL_MAX; j++ ) { |
|
feature_value = 0 |
|
feature_enabled |
f(1) |
FeatureEnabled[ i ][ j ] = feature_enabled |
|
clippedValue = 0 |
|
if ( feature_enabled == 1 ) { |
|
bitsToRead = Segmentation_Feature_Bits[ j ] |
|
limit = Segmentation_Feature_Max[ j ] |
|
if ( Segmentation_Feature_Signed[ j ] == 1 ) { |
|
feature_value |
su(1+bitsToRead) |
clippedValue = Clip3( -limit, limit, feature_value) |
|
} else { |
|
feature_value |
f(bitsToRead) |
clippedValue = Clip3( 0, limit, feature_value) |
|
} |
|
} |
|
FeatureData[ i ][ j ] = clippedValue |
|
} |
|
} |
|
} |
|
} else { |
|
for ( i = 0; i < MAX_SEGMENTS; i++ ) { |
|
for ( j = 0; j < SEG_LVL_MAX; j++ ) { |
|
FeatureEnabled[ i ][ j ] = 0 |
|
FeatureData[ i ][ j ] = 0 |
|
} |
|
} |
|
} |
|
SegIdPreSkip = 0 |
|
LastActiveSegId = 0 |
|
for ( i = 0; i < MAX_SEGMENTS; i++ ) { |
|
for ( j = 0; j < SEG_LVL_MAX; j++ ) { |
|
if ( FeatureEnabled[ i ][ j ] ) { |
|
LastActiveSegId = i |
|
if ( j >= SEG_LVL_REF_FRAME ) { |
|
SegIdPreSkip = 1 |
|
} |
|
} |
|
} |
|
} |
|
} |
|
The constant lookup tables used in this syntax are defined as:
Segmentation_Feature_Bits[ SEG_LVL_MAX ] = { 8, 6, 6, 6, 6, 3, 0, 0 }
Segmentation_Feature_Signed[ SEG_LVL_MAX ] = { 1, 1, 1, 1, 1, 0, 0, 0 }
Segmentation_Feature_Max[ SEG_LVL_MAX ] = {
255, MAX_LOOP_FILTER, MAX_LOOP_FILTER,
MAX_LOOP_FILTER, MAX_LOOP_FILTER, 7,
0, 0 }
Tile info syntax
tile_info ( ) { |
Type |
sbCols = use_128x128_superblock ? ( ( MiCols + 31 ) >> 5 ) : ( ( MiCols + 15 ) >> 4 ) |
|
sbRows = use_128x128_superblock ? ( ( MiRows + 31 ) >> 5 ) : ( ( MiRows + 15 ) >> 4 ) |
|
sbShift = use_128x128_superblock ? 5 : 4 |
|
sbSize = sbShift + 2 |
|
maxTileWidthSb = MAX_TILE_WIDTH >> sbSize |
|
maxTileAreaSb = MAX_TILE_AREA >> ( 2 * sbSize ) |
|
minLog2TileCols = tile_log2(maxTileWidthSb, sbCols) |
|
maxLog2TileCols = tile_log2(1, Min(sbCols, MAX_TILE_COLS)) |
|
maxLog2TileRows = tile_log2(1, Min(sbRows, MAX_TILE_ROWS)) |
|
minLog2Tiles = Max(minLog2TileCols, |
|
tile_log2(maxTileAreaSb, sbRows * sbCols)) |
|
|
|
uniform_tile_spacing_flag |
f(1) |
if ( uniform_tile_spacing_flag ) { |
|
TileColsLog2 = minLog2TileCols |
|
while ( TileColsLog2 < maxLog2TileCols ) { |
|
increment_tile_cols_log2 |
f(1) |
if ( increment_tile_cols_log2 == 1 ) |
|
TileColsLog2++ |
|
else |
|
break |
|
} |
|
tileWidthSb = (sbCols + (1 << TileColsLog2) - 1) >> TileColsLog2 |
|
i = 0 |
|
for ( startSb = 0; startSb < sbCols; startSb += tileWidthSb ) { |
|
MiColStarts[ i ] = startSb << sbShift |
|
i += 1 |
|
} |
|
MiColStarts[i] = MiCols |
|
TileCols = i |
|
|
|
minLog2TileRows = Max( minLog2Tiles - TileColsLog2, 0) |
|
TileRowsLog2 = minLog2TileRows |
|
while ( TileRowsLog2 < maxLog2TileRows ) { |
|
increment_tile_rows_log2 |
f(1) |
if ( increment_tile_rows_log2 == 1 ) |
|
TileRowsLog2++ |
|
else |
|
break |
|
} |
|
tileHeightSb = (sbRows + (1 << TileRowsLog2) - 1) >> TileRowsLog2 |
|
i = 0 |
|
for ( startSb = 0; startSb < sbRows; startSb += tileHeightSb ) { |
|
MiRowStarts[ i ] = startSb << sbShift |
|
i += 1 |
|
} |
|
MiRowStarts[i] = MiRows |
|
TileRows = i |
|
} else { |
|
widestTileSb = 0 |
|
startSb = 0 |
|
for ( i = 0; startSb < sbCols; i++ ) { |
|
MiColStarts[ i ] = startSb << sbShift |
|
maxWidth = Min(sbCols - startSb, maxTileWidthSb) |
|
width_in_sbs_minus_1 |
ns(maxWidth) |
sizeSb = width_in_sbs_minus_1 + 1 |
|
widestTileSb = Max( sizeSb, widestTileSb ) |
|
startSb += sizeSb |
|
} |
|
MiColStarts[i] = MiCols |
|
TileCols = i |
|
TileColsLog2 = tile_log2(1, TileCols) |
|
|
|
if ( minLog2Tiles > 0 ) |
|
maxTileAreaSb = (sbRows * sbCols) >> (minLog2Tiles + 1) |
|
else |
|
maxTileAreaSb = sbRows * sbCols |
|
maxTileHeightSb = Max( maxTileAreaSb / widestTileSb, 1 ) |
|
|
|
startSb = 0 |
|
for ( i = 0; startSb < sbRows; i++ ) { |
|
MiRowStarts[ i ] = startSb << sbShift |
|
maxHeight = Min(sbRows - startSb, maxTileHeightSb) |
|
height_in_sbs_minus_1 |
ns(maxHeight) |
sizeSb = height_in_sbs_minus_1 + 1 |
|
startSb += sizeSb |
|
} |
|
MiRowStarts[ i ] = MiRows |
|
TileRows = i |
|
TileRowsLog2 = tile_log2(1, TileRows) |
|
} |
|
if ( TileColsLog2 > 0 || TileRowsLog2 > 0 ) { |
|
context_update_tile_id |
f(TileRowsLog2 + TileColsLog2) |
tile_size_bytes_minus_1 |
f(2) |
TileSizeBytes = tile_size_bytes_minus_1 + 1 |
|
} else { |
|
context_update_tile_id = 0 |
|
} |
|
} |
|
Tile size calculation function
tile_log2 returns the smallest value for k such that blkSize << k is greater than or equal to target.
tile_log2( blkSize, target ) { |
Type |
for ( k = 0; (blkSize << k) < target; k++ ) { |
|
} |
|
return k |
|
} |
|
Quantizer index delta parameters syntax
delta_q_params( ) { |
Type |
delta_q_res = 0 |
|
delta_q_present = 0 |
|
if ( base_q_idx > 0 ) { |
|
delta_q_present |
f(1) |
} |
|
if ( delta_q_present ) { |
|
delta_q_res |
f(2) |
} |
|
} |
|
Loop filter delta parameters syntax
delta_lf_params( ) { |
Type |
delta_lf_present = 0 |
|
delta_lf_res = 0 |
|
delta_lf_multi = 0 |
|
if ( delta_q_present ) { |
|
if ( !allow_intrabc ) |
|
delta_lf_present |
f(1) |
if ( delta_lf_present ) { |
|
delta_lf_res |
f(2) |
delta_lf_multi |
f(1) |
} |
|
} |
|
} |
|
CDEF params syntax
cdef_params( ) { |
Type |
if ( CodedLossless || allow_intrabc || |
|
!enable_cdef) { |
|
cdef_bits = 0 |
|
cdef_y_pri_strength[0] = 0 |
|
cdef_y_sec_strength[0] = 0 |
|
cdef_uv_pri_strength[0] = 0 |
|
cdef_uv_sec_strength[0] = 0 |
|
CdefDamping = 3 |
|
return |
|
} |
|
cdef_damping_minus_3 |
f(2) |
CdefDamping = cdef_damping_minus_3 + 3 |
|
cdef_bits |
f(2) |
for ( i = 0; i < (1 << cdef_bits); i++ ) { |
|
cdef_y_pri_strength[i] |
f(4) |
cdef_y_sec_strength[i] |
f(2) |
if ( cdef_y_sec_strength[i] == 3 ) |
|
cdef_y_sec_strength[i] += 1 |
|
if ( NumPlanes > 1 ) { |
|
cdef_uv_pri_strength[i] |
f(4) |
cdef_uv_sec_strength[i] |
f(2) |
if ( cdef_uv_sec_strength[i] == 3 ) |
|
cdef_uv_sec_strength[i] += 1 |
|
} |
|
} |
|
} |
|
Loop restoration params syntax
lr_params( ) { |
Type |
if ( AllLossless || allow_intrabc || |
|
!enable_restoration ) { |
|
FrameRestorationType[0] = RESTORE_NONE |
|
FrameRestorationType[1] = RESTORE_NONE |
|
FrameRestorationType[2] = RESTORE_NONE |
|
UsesLr = 0 |
|
return |
|
} |
|
UsesLr = 0 |
|
usesChromaLr = 0 |
|
for ( i = 0; i < NumPlanes; i++ ) { |
|
lr_type |
f(2) |
FrameRestorationType[i] = Remap_Lr_Type[lr_type] |
|
if ( FrameRestorationType[i] != RESTORE_NONE ) { |
|
UsesLr = 1 |
|
if ( i > 0 ) { |
|
usesChromaLr = 1 |
|
} |
|
} |
|
} |
|
if ( UsesLr ) { |
|
if ( use_128x128_superblock ) { |
|
lr_unit_shift |
f(1) |
lr_unit_shift++ |
|
} else { |
|
lr_unit_shift |
f(1) |
if ( lr_unit_shift ) { |
|
lr_unit_extra_shift |
f(1) |
lr_unit_shift += lr_unit_extra_shift |
|
} |
|
} |
|
LoopRestorationSize[ 0 ] = RESTORATION_TILESIZE_MAX >> (2 - lr_unit_shift) |
|
if ( subsampling_x && subsampling_y && usesChromaLr ) { |
|
lr_uv_shift |
f(1) |
} else { |
|
lr_uv_shift = 0 |
|
} |
|
LoopRestorationSize[ 1 ] = LoopRestorationSize[ 0 ] >> lr_uv_shift |
|
LoopRestorationSize[ 2 ] = LoopRestorationSize[ 0 ] >> lr_uv_shift |
|
} |
|
} |
|
where Remap_Lr_Type is a constant lookup table specified as:
Remap_Lr_Type[4] = {
RESTORE_NONE, RESTORE_SWITCHABLE, RESTORE_WIENER, RESTORE_SGRPROJ
}
TX mode syntax
read_tx_mode( ) { |
Type |
if ( CodedLossless == 1 ) { |
|
TxMode = ONLY_4X4 |
|
} else { |
|
tx_mode_select |
f(1) |
if ( tx_mode_select ) { |
|
TxMode = TX_MODE_SELECT |
|
} else { |
|
TxMode = TX_MODE_LARGEST |
|
} |
|
} |
|
} |
|
Skip mode params syntax
skip_mode_params( ) { |
Type |
if ( FrameIsIntra || !reference_select || !enable_order_hint ) { |
|
skipModeAllowed = 0 |
|
} else { |
|
forwardIdx = -1 |
|
backwardIdx = -1 |
|
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
refHint = RefOrderHint[ ref_frame_idx[ i ] ] |
|
if ( get_relative_dist( refHint, OrderHint ) < 0 ) { |
|
if ( forwardIdx < 0 || |
|
get_relative_dist( refHint, forwardHint) > 0 ) { |
|
forwardIdx = i |
|
forwardHint = refHint |
|
} |
|
} else if ( get_relative_dist( refHint, OrderHint) > 0 ) { |
|
if ( backwardIdx < 0 || |
|
get_relative_dist( refHint, backwardHint) < 0 ) { |
|
backwardIdx = i |
|
backwardHint = refHint |
|
} |
|
} |
|
} |
|
if ( forwardIdx < 0 ) { |
|
skipModeAllowed = 0 |
|
} else if ( backwardIdx >= 0 ) { |
|
skipModeAllowed = 1 |
|
SkipModeFrame[ 0 ] = LAST_FRAME + Min(forwardIdx, backwardIdx) |
|
SkipModeFrame[ 1 ] = LAST_FRAME + Max(forwardIdx, backwardIdx) |
|
} else { |
|
secondForwardIdx = -1 |
|
for ( i = 0; i < REFS_PER_FRAME; i++ ) { |
|
refHint = RefOrderHint[ ref_frame_idx[ i ] ] |
|
if ( get_relative_dist( refHint, forwardHint ) < 0 ) { |
|
if ( secondForwardIdx < 0 || |
|
get_relative_dist( refHint, secondForwardHint ) > 0 ) { |
|
secondForwardIdx = i |
|
secondForwardHint = refHint |
|
} |
|
} |
|
} |
|
if ( secondForwardIdx < 0 ) { |
|
skipModeAllowed = 0 |
|
} else { |
|
skipModeAllowed = 1 |
|
SkipModeFrame[ 0 ] = LAST_FRAME + Min(forwardIdx, secondForwardIdx) |
|
SkipModeFrame[ 1 ] = LAST_FRAME + Max(forwardIdx, secondForwardIdx) |
|
} |
|
} |
|
} |
|
if ( skipModeAllowed ) { |
|
skip_mode_present |
f(1) |
} else { |
|
skip_mode_present = 0 |
|
} |
|
} |
|
Frame reference mode syntax
frame_reference_mode( ) { |
Type |
if ( FrameIsIntra ) { |
|
reference_select = 0 |
|
} else { |
|
reference_select |
f(1) |
} |
|
} |
|
Global motion params syntax
global_motion_params( ) { |
Type |
for ( ref = LAST_FRAME; ref <= ALTREF_FRAME; ref++ ) { |
|
GmType[ ref ] = IDENTITY |
|
for ( i = 0; i < 6; i++ ) { |
|
gm_params[ ref ][ i ] = ( ( i % 3 == 2 ) ? |
|
1 << WARPEDMODEL_PREC_BITS : 0 ) |
|
} |
|
} |
|
if ( FrameIsIntra ) |
|
return |
|
for ( ref = LAST_FRAME; ref <= ALTREF_FRAME; ref++ ) { |
|
is_global |
f(1) |
if ( is_global ) { |
|
is_rot_zoom |
f(1) |
if ( is_rot_zoom ) { |
|
type = ROTZOOM |
|
} else { |
|
is_translation |
f(1) |
type = is_translation ? TRANSLATION : AFFINE |
|
} |
|
} else { |
|
type = IDENTITY |
|
} |
|
GmType[ref] = type |
|
|
|
if ( type >= ROTZOOM ) { |
|
read_global_param(type,ref,2) |
|
read_global_param(type,ref,3) |
|
if ( type == AFFINE ) { |
|
read_global_param(type,ref,4) |
|
read_global_param(type,ref,5) |
|
} else { |
|
gm_params[ref][4] = -gm_params[ref][3] |
|
gm_params[ref][5] = gm_params[ref][2] |
|
} |
|
} |
|
if ( type >= TRANSLATION ) { |
|
read_global_param(type,ref,0) |
|
read_global_param(type,ref,1) |
|
} |
|
} |
|
} |
|
Global param syntax
read_global_param( type, ref, idx ) { |
Type |
absBits = GM_ABS_ALPHA_BITS |
|
precBits = GM_ALPHA_PREC_BITS |
|
if ( idx < 2 ) { |
|
if ( type == TRANSLATION ) { |
|
absBits = GM_ABS_TRANS_ONLY_BITS - !allow_high_precision_mv |
|
precBits = GM_TRANS_ONLY_PREC_BITS - !allow_high_precision_mv |
|
} else { |
|
absBits = GM_ABS_TRANS_BITS |
|
precBits = GM_TRANS_PREC_BITS |
|
} |
|
} |
|
precDiff = WARPEDMODEL_PREC_BITS - precBits |
|
round = (idx % 3) == 2 ? (1 << WARPEDMODEL_PREC_BITS) : 0 |
|
sub = (idx % 3) == 2 ? (1 << precBits) : 0 |
|
mx = (1 << absBits) |
|
r = (PrevGmParams[ref][idx] >> precDiff) - sub |
|
gm_params[ref][idx] = |
|
(decode_signed_subexp_with_ref( -mx, mx + 1, r )<< precDiff) + round |
|
} |
|
Note: When force_integer_mv is equal to 1, some fractional bits are still
read for the translation components. However, these fractional bits will be
discarded during the Setup Global MV process.
Decode signed subexp with ref syntax
decode_signed_subexp_with_ref( low, high, r ) { |
Type |
x = decode_unsigned_subexp_with_ref(high - low, r - low) |
|
return x + low |
|
} |
|
Note: decode_signed_subexp_with_ref will return a value
in the range low to high - 1 (inclusive).
Decode unsigned subexp with ref syntax
decode_unsigned_subexp_with_ref( mx, r ) { |
Type |
v = decode_subexp( mx ) |
|
if ( (r << 1) <= mx ) { |
|
return inverse_recenter(r, v) |
|
} else { |
|
return mx - 1 - inverse_recenter(mx - 1 - r, v) |
|
} |
|
} |
|
Note: decode_unsigned_subexp_with_ref will return a value
in the range 0 to mx - 1 (inclusive).
Decode subexp syntax
decode_subexp( numSyms ) { |
Type |
i = 0 |
|
mk = 0 |
|
k = 3 |
|
while ( 1 ) { |
|
b2 = i ? k + i - 1 : k |
|
a = 1 << b2 |
|
if ( numSyms <= mk + 3 * a ) { |
|
subexp_final_bits |
ns(numSyms - mk) |
return subexp_final_bits + mk |
|
} else { |
|
subexp_more_bits |
f(1) |
if ( subexp_more_bits ) { |
|
i++ |
|
mk += a |
|
} else { |
|
subexp_bits |
f(b2) |
return subexp_bits + mk |
|
} |
|
} |
|
} |
|
} |
|
Inverse recenter function
inverse_recenter( r, v ) { |
Type |
if ( v > 2 * r ) |
|
return v |
|
else if ( v & 1 ) |
|
return r - ((v + 1) >> 1) |
|
else |
|
return r + (v >> 1) |
|
} |
|
Film grain params syntax
film_grain_params( ) { |
Type |
if ( !film_grain_params_present || |
|
(!show_frame && !showable_frame) ) { |
|
reset_grain_params() |
|
return |
|
} |
|
apply_grain |
f(1) |
if ( !apply_grain ) { |
|
reset_grain_params() |
|
return |
|
} |
|
grain_seed |
f(16) |
if ( frame_type == INTER_FRAME ) |
|
update_grain |
f(1) |
else |
|
update_grain = 1 |
|
if ( !update_grain ) { |
|
film_grain_params_ref_idx |
f(3) |
tempGrainSeed = grain_seed |
|
load_grain_params( film_grain_params_ref_idx ) |
|
grain_seed = tempGrainSeed |
|
return |
|
} |
|
num_y_points |
f(4) |
for ( i = 0; i < num_y_points; i++ ) { |
|
point_y_value[ i ] |
f(8) |
point_y_scaling[ i ] |
f(8) |
} |
|
if ( mono_chrome ) { |
|
chroma_scaling_from_luma = 0 |
|
} else { |
|
chroma_scaling_from_luma |
f(1) |
} |
|
if ( mono_chrome || chroma_scaling_from_luma || |
|
( subsampling_x == 1 && subsampling_y == 1 && |
|
num_y_points == 0 ) |
|
) { |
|
num_cb_points = 0 |
|
num_cr_points = 0 |
|
} else { |
|
num_cb_points |
f(4) |
for ( i = 0; i < num_cb_points; i++ ) { |
|
point_cb_value[ i ] |
f(8) |
point_cb_scaling[ i ] |
f(8) |
} |
|
num_cr_points |
f(4) |
for ( i = 0; i < num_cr_points; i++ ) { |
|
point_cr_value[ i ] |
f(8) |
point_cr_scaling[ i ] |
f(8) |
} |
|
} |
|
grain_scaling_minus_8 |
f(2) |
ar_coeff_lag |
f(2) |
numPosLuma = 2 * ar_coeff_lag * ( ar_coeff_lag + 1 ) |
|
if ( num_y_points ) { |
|
numPosChroma = numPosLuma + 1 |
|
for ( i = 0; i < numPosLuma; i++ ) |
|
ar_coeffs_y_plus_128[ i ] |
f(8) |
} else { |
|
numPosChroma = numPosLuma |
|
} |
|
if ( chroma_scaling_from_luma || num_cb_points ) { |
|
for ( i = 0; i < numPosChroma; i++ ) |
|
ar_coeffs_cb_plus_128[ i ] |
f(8) |
} |
|
if ( chroma_scaling_from_luma || num_cr_points ) { |
|
for ( i = 0; i < numPosChroma; i++ ) |
|
ar_coeffs_cr_plus_128[ i ] |
f(8) |
} |
|
ar_coeff_shift_minus_6 |
f(2) |
grain_scale_shift |
f(2) |
if ( num_cb_points ) { |
|
cb_mult |
f(8) |
cb_luma_mult |
f(8) |
cb_offset |
f(9) |
} |
|
if ( num_cr_points ) { |
|
cr_mult |
f(8) |
cr_luma_mult |
f(8) |
cr_offset |
f(9) |
} |
|
overlap_flag |
f(1) |
clip_to_restricted_range |
f(1) |
} |
|
Temporal point info syntax
temporal_point_info( ) { |
Type |
n = frame_presentation_time_length_minus_1 + 1 |
|
frame_presentation_time |
f(n) |
} |
|
Frame OBU syntax
frame_obu( sz ) { |
Type |
startBitPos = get_position( ) |
|
frame_header_obu( ) |
|
byte_alignment( ) |
|
endBitPos = get_position( ) |
|
headerBytes = (endBitPos - startBitPos) / 8 |
|
sz -= headerBytes |
|
tile_group_obu( sz ) |
|
} |
|
Tile group OBU syntax
General tile group OBU syntax
tile_group_obu( sz ) { |
Type |
NumTiles = TileCols * TileRows |
|
startBitPos = get_position( ) |
|
tile_start_and_end_present_flag = 0 |
|
if ( NumTiles > 1 ) |
|
tile_start_and_end_present_flag |
f(1) |
if ( NumTiles == 1 || !tile_start_and_end_present_flag ) { |
|
tg_start = 0 |
|
tg_end = NumTiles - 1 |
|
} else { |
|
tileBits = TileColsLog2 + TileRowsLog2 |
|
tg_start |
f(tileBits) |
tg_end |
f(tileBits) |
} |
|
byte_alignment( ) |
|
endBitPos = get_position( ) |
|
headerBytes = (endBitPos - startBitPos) / 8 |
|
sz -= headerBytes |
|
|
|
for ( TileNum = tg_start; TileNum <= tg_end; TileNum++ ) { |
|
tileRow = TileNum / TileCols |
|
tileCol = TileNum % TileCols |
|
lastTile = TileNum == tg_end |
|
if ( lastTile ) { |
|
tileSize = sz |
|
} else { |
|
tile_size_minus_1 |
le(TileSizeBytes) |
tileSize = tile_size_minus_1 + 1 |
|
sz -= tileSize + TileSizeBytes |
|
} |
|
MiRowStart = MiRowStarts[ tileRow ] |
|
MiRowEnd = MiRowStarts[ tileRow + 1 ] |
|
MiColStart = MiColStarts[ tileCol ] |
|
MiColEnd = MiColStarts[ tileCol + 1 ] |
|
CurrentQIndex = base_q_idx |
|
init_symbol( tileSize ) |
|
decode_tile( ) |
|
exit_symbol( ) |
|
} |
|
if ( tg_end == NumTiles - 1 ) { |
|
if ( !disable_frame_end_update_cdf ) { |
|
frame_end_update_cdf( ) |
|
} |
|
decode_frame_wrapup( ) |
|
SeenFrameHeader = 0 |
|
} |
|
} |
|
Decode tile syntax
decode_tile( ) { |
Type |
clear_above_context( ) |
|
for ( i = 0; i < FRAME_LF_COUNT; i++ ) |
|
DeltaLF[ i ] = 0 |
|
for ( plane = 0; plane < NumPlanes; plane++ ) { |
|
for ( pass = 0; pass < 2; pass++ ) { |
|
RefSgrXqd[ plane ][ pass ] = Sgrproj_Xqd_Mid[ pass ] |
|
for ( i = 0; i < WIENER_COEFFS; i++ ) { |
|
RefLrWiener[ plane ][ pass ][ i ] = Wiener_Taps_Mid[ i ] |
|
} |
|
} |
|
} |
|
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64 |
|
sbSize4 = Num_4x4_Blocks_Wide[ sbSize ] |
|
for ( r = MiRowStart; r < MiRowEnd; r += sbSize4 ) { |
|
clear_left_context( ) |
|
for ( c = MiColStart; c < MiColEnd; c += sbSize4 ) { |
|
ReadDeltas = delta_q_present |
|
clear_cdef( r, c ) |
|
clear_block_decoded_flags( r, c, sbSize4 ) |
|
read_lr( r, c, sbSize ) |
|
decode_partition( r, c, sbSize ) |
|
} |
|
} |
|
} |
|
where Sgrproj_Xqd_Mid and Wiener_Taps_Mid are constant lookup tables specified as:
Wiener_Taps_Mid[3] = { 3, -7, 15 }
Sgrproj_Xqd_Mid[2] = { -32, 31 }
Clear block decoded flags function
clear_block_decoded_flags( r, c, sbSize4 ) { |
Type |
for ( plane = 0; plane < NumPlanes; plane++ ) { |
|
subX = (plane > 0) ? subsampling_x : 0 |
|
subY = (plane > 0) ? subsampling_y : 0 |
|
sbWidth4 = ( MiColEnd - c ) >> subX |
|
sbHeight4 = ( MiRowEnd - r ) >> subY |
|
for ( y = -1; y <= ( sbSize4 >> subY ); y++ ) |
|
for ( x = -1; x <= ( sbSize4 >> subX ); x++ ) { |
|
if ( y < 0 && x < sbWidth4 ) |
|
BlockDecoded[ plane ][ y ][ x ] = 1 |
|
else if ( x < 0 && y < sbHeight4 ) |
|
BlockDecoded[ plane ][ y ][ x ] = 1 |
|
else |
|
BlockDecoded[ plane ][ y ][ x ] = 0 |
|
} |
|
BlockDecoded[ plane ][ sbSize4 >> subY ][ -1 ] = 0 |
|
} |
|
} |
|
Decode partition syntax
decode_partition( r, c, bSize ) { |
Type |
if ( r >= MiRows || c >= MiCols ) |
|
return 0 |
|
AvailU = is_inside( r - 1, c ) |
|
AvailL = is_inside( r, c - 1 ) |
|
num4x4 = Num_4x4_Blocks_Wide[ bSize ] |
|
halfBlock4x4 = num4x4 >> 1 |
|
quarterBlock4x4 = halfBlock4x4 >> 1 |
|
hasRows = ( r + halfBlock4x4 ) < MiRows |
|
hasCols = ( c + halfBlock4x4 ) < MiCols |
|
if ( bSize < BLOCK_8X8 ) { |
|
partition = PARTITION_NONE |
|
} else if ( hasRows && hasCols ) { |
|
partition |
S() |
} else if ( hasCols ) { |
|
split_or_horz |
S() |
partition = split_or_horz ? PARTITION_SPLIT : PARTITION_HORZ |
|
} else if ( hasRows ) { |
|
split_or_vert |
S() |
partition = split_or_vert ? PARTITION_SPLIT : PARTITION_VERT |
|
} else { |
|
partition = PARTITION_SPLIT |
|
} |
|
subSize = Partition_Subsize[ partition ][ bSize ] |
|
splitSize = Partition_Subsize[ PARTITION_SPLIT ][ bSize ] |
|
if ( partition == PARTITION_NONE ) { |
|
decode_block( r, c, subSize ) |
|
} else if ( partition == PARTITION_HORZ ) { |
|
decode_block( r, c, subSize ) |
|
if ( hasRows ) |
|
decode_block( r + halfBlock4x4, c, subSize ) |
|
} else if ( partition == PARTITION_VERT ) { |
|
decode_block( r, c, subSize ) |
|
if ( hasCols ) |
|
decode_block( r, c + halfBlock4x4, subSize ) |
|
} else if ( partition == PARTITION_SPLIT ) { |
|
decode_partition( r, c, subSize ) |
|
decode_partition( r, c + halfBlock4x4, subSize ) |
|
decode_partition( r + halfBlock4x4, c, subSize ) |
|
decode_partition( r + halfBlock4x4, c + halfBlock4x4, subSize ) |
|
} else if ( partition == PARTITION_HORZ_A ) { |
|
decode_block( r, c, splitSize ) |
|
decode_block( r, c + halfBlock4x4, splitSize ) |
|
decode_block( r + halfBlock4x4, c, subSize ) |
|
} else if ( partition == PARTITION_HORZ_B ) { |
|
decode_block( r, c, subSize ) |
|
decode_block( r + halfBlock4x4, c, splitSize ) |
|
decode_block( r + halfBlock4x4, c + halfBlock4x4, splitSize ) |
|
} else if ( partition == PARTITION_VERT_A ) { |
|
decode_block( r, c, splitSize ) |
|
decode_block( r + halfBlock4x4, c, splitSize ) |
|
decode_block( r, c + halfBlock4x4, subSize ) |
|
} else if ( partition == PARTITION_VERT_B ) { |
|
decode_block( r, c, subSize ) |
|
decode_block( r, c + halfBlock4x4, splitSize ) |
|
decode_block( r + halfBlock4x4, c + halfBlock4x4, splitSize ) |
|
} else if ( partition == PARTITION_HORZ_4 ) { |
|
decode_block( r + quarterBlock4x4 * 0, c, subSize ) |
|
decode_block( r + quarterBlock4x4 * 1, c, subSize ) |
|
decode_block( r + quarterBlock4x4 * 2, c, subSize ) |
|
if ( r + quarterBlock4x4 * 3 < MiRows ) |
|
decode_block( r + quarterBlock4x4 * 3, c, subSize ) |
|
} else { |
|
decode_block( r, c + quarterBlock4x4 * 0, subSize ) |
|
decode_block( r, c + quarterBlock4x4 * 1, subSize ) |
|
decode_block( r, c + quarterBlock4x4 * 2, subSize ) |
|
if ( c + quarterBlock4x4 * 3 < MiCols ) |
|
decode_block( r, c + quarterBlock4x4 * 3, subSize ) |
|
} |
|
} |
|
Decode block syntax
decode_block( r, c, subSize ) { |
Type |
MiRow = r |
|
MiCol = c |
|
MiSize = subSize |
|
bw4 = Num_4x4_Blocks_Wide[ subSize ] |
|
bh4 = Num_4x4_Blocks_High[ subSize ] |
|
if ( bh4 == 1 && subsampling_y && (MiRow & 1) == 0 ) |
|
HasChroma = 0 |
|
else if ( bw4 == 1 && subsampling_x && (MiCol & 1) == 0 ) |
|
HasChroma = 0 |
|
else |
|
HasChroma = NumPlanes > 1 |
|
AvailU = is_inside( r - 1, c ) |
|
AvailL = is_inside( r, c - 1 ) |
|
AvailUChroma = AvailU |
|
AvailLChroma = AvailL |
|
if ( HasChroma ) { |
|
if ( subsampling_y && bh4 == 1 ) |
|
AvailUChroma = is_inside( r - 2, c ) |
|
if ( subsampling_x && bw4 == 1 ) |
|
AvailLChroma = is_inside( r, c - 2 ) |
|
} else { |
|
AvailUChroma = 0 |
|
AvailLChroma = 0 |
|
} |
|
mode_info( ) |
|
palette_tokens( ) |
|
read_block_tx_size( ) |
|
|
|
if ( skip ) |
|
reset_block_context( bw4, bh4 ) |
|
isCompound = RefFrame[ 1 ] > INTRA_FRAME |
|
for ( y = 0; y < bh4; y++ ) { |
|
for ( x = 0; x < bw4; x++ ) { |
|
YModes [ r + y ][ c + x ] = YMode |
|
if ( RefFrame[ 0 ] == INTRA_FRAME && HasChroma ) |
|
UVModes [ r + y ][ c + x ] = UVMode |
|
for ( refList = 0; refList < 2; refList++ ) |
|
RefFrames[ r + y ][ c + x ][ refList ] = RefFrame[ refList ] |
|
if ( is_inter ) { |
|
if ( !use_intrabc ) { |
|
CompGroupIdxs[ r + y ][ c + x ] = comp_group_idx |
|
CompoundIdxs[ r + y ][ c + x ] = compound_idx |
|
} |
|
for ( dir = 0; dir < 2; dir++ ) { |
|
InterpFilters[ r + y ][ c + x ][ dir ] = interp_filter[ dir ] |
|
} |
|
for ( refList = 0; refList < 1 + isCompound; refList++ ) { |
|
Mvs[ r + y ][ c + x ][ refList ] = Mv[ refList ] |
|
} |
|
} |
|
} |
|
} |
|
compute_prediction( ) |
|
residual( ) |
|
for ( y = 0; y < bh4; y++ ) { |
|
for ( x = 0; x < bw4; x++ ) { |
|
IsInters[ r + y ][ c + x ] = is_inter |
|
SkipModes[ r + y ][ c + x ] = skip_mode |
|
Skips[ r + y ][ c + x ] = skip |
|
TxSizes[ r + y ][ c + x ] = TxSize |
|
MiSizes[ r + y ][ c + x ] = MiSize |
|
SegmentIds[ r + y ][ c + x ] = segment_id |
|
PaletteSizes[ 0 ][ r + y ][ c + x ] = PaletteSizeY |
|
PaletteSizes[ 1 ][ r + y ][ c + x ] = PaletteSizeUV |
|
for ( i = 0; i < PaletteSizeY; i++ ) |
|
PaletteColors[ 0 ][ r + y ][ c + x ][ i ] = palette_colors_y[ i ] |
|
for ( i = 0; i < PaletteSizeUV; i++ ) |
|
PaletteColors[ 1 ][ r + y ][ c + x ][ i ] = palette_colors_u[ i ] |
|
for ( i = 0; i < FRAME_LF_COUNT; i++ ) |
|
DeltaLFs[ r + y ][ c + x ][ i ] = DeltaLF[ i ] |
|
} |
|
} |
|
} |
|
where reset_block_context( ) is specified as:
reset_block_context( bw4, bh4 ) {
for ( plane = 0; plane < 1 + 2 * HasChroma; plane++ ) {
subX = (plane > 0) ? subsampling_x : 0
subY = (plane > 0) ? subsampling_y : 0
for ( i = MiCol >> subX; i < ( ( MiCol + bw4 ) >> subX ); i++) {
AboveLevelContext[ plane ][ i ] = 0
AboveDcContext[ plane ][ i ] = 0
}
for ( i = MiRow >> subY; i < ( ( MiRow + bh4 ) >> subY ); i++) {
LeftLevelContext[ plane ][ i ] = 0
LeftDcContext[ plane ][ i ] = 0
}
}
}
Mode info syntax
mode_info( ) { |
Type |
if ( FrameIsIntra ) |
|
intra_frame_mode_info( ) |
|
else |
|
inter_frame_mode_info( ) |
|
} |
|
Intra frame mode info syntax
intra_frame_mode_info( ) { |
Type |
skip = 0 |
|
if ( SegIdPreSkip ) |
|
intra_segment_id( ) |
|
skip_mode = 0 |
|
read_skip( ) |
|
if ( !SegIdPreSkip ) |
|
intra_segment_id( ) |
|
read_cdef( ) |
|
read_delta_qindex( ) |
|
read_delta_lf( ) |
|
ReadDeltas = 0 |
|
RefFrame[ 0 ] = INTRA_FRAME |
|
RefFrame[ 1 ] = NONE |
|
if ( allow_intrabc ) { |
|
use_intrabc |
S() |
} else { |
|
use_intrabc = 0 |
|
} |
|
if ( use_intrabc ) { |
|
is_inter = 1 |
|
YMode = DC_PRED |
|
UVMode = DC_PRED |
|
motion_mode = SIMPLE |
|
compound_type = COMPOUND_AVERAGE |
|
PaletteSizeY = 0 |
|
PaletteSizeUV = 0 |
|
interp_filter[ 0 ] = BILINEAR |
|
interp_filter[ 1 ] = BILINEAR |
|
find_mv_stack( 0 ) |
|
assign_mv( 0 ) |
|
} else { |
|
is_inter = 0 |
|
intra_frame_y_mode |
S() |
YMode = intra_frame_y_mode |
|
intra_angle_info_y( ) |
|
if ( HasChroma ) { |
|
uv_mode |
S() |
UVMode = uv_mode |
|
if ( UVMode == UV_CFL_PRED ) { |
|
read_cfl_alphas( ) |
|
} |
|
intra_angle_info_uv( ) |
|
} |
|
PaletteSizeY = 0 |
|
PaletteSizeUV = 0 |
|
if ( MiSize >= BLOCK_8X8 && |
|
Block_Width[ MiSize ] <= 64 && |
|
Block_Height[ MiSize ] <= 64 && |
|
allow_screen_content_tools ) { |
|
palette_mode_info( ) |
|
} |
|
filter_intra_mode_info( ) |
|
} |
|
} |
|
Intra segment ID syntax
intra_segment_id( ) { |
Type |
if ( segmentation_enabled ) |
|
read_segment_id( ) |
|
else |
|
segment_id = 0 |
|
Lossless = LosslessArray[ segment_id ] |
|
} |
|
Read segment ID syntax
read_segment_id( ) { |
Type |
if ( AvailU && AvailL ) |
|
prevUL = SegmentIds[ MiRow - 1 ][ MiCol - 1 ] |
|
else |
|
prevUL = -1 |
|
if ( AvailU ) |
|
prevU = SegmentIds[ MiRow - 1 ][ MiCol ] |
|
else |
|
prevU = -1 |
|
if ( AvailL ) |
|
prevL = SegmentIds[ MiRow ][ MiCol - 1 ] |
|
else |
|
prevL = -1 |
|
if ( prevU == -1 ) |
|
pred = (prevL == -1) ? 0 : prevL |
|
else if ( prevL == -1 ) |
|
pred = prevU |
|
else |
|
pred = (prevUL == prevU) ? prevU : prevL |
|
if ( skip ) { |
|
segment_id = pred |
|
} else { |
|
segment_id |
S() |
segment_id = neg_deinterleave( segment_id, pred, |
|
LastActiveSegId + 1 ) |
|
} |
|
} |
|
where neg_deinterleave is a function defined as:
neg_deinterleave(diff, ref, max) {
if ( !ref )
return diff
if ( ref >= (max - 1) )
return max - diff - 1
if ( 2 * ref < max ) {
if ( diff <= 2 * ref ) {
if ( diff & 1 )
return ref + ((diff + 1) >> 1)
else
return ref - (diff >> 1)
}
return diff
} else {
if ( diff <= 2 * (max - ref - 1) ) {
if ( diff & 1 )
return ref + ((diff + 1) >> 1)
else
return ref - (diff >> 1)
}
return max - (diff + 1)
}
}
Skip mode syntax
read_skip_mode() { |
Type |
if ( seg_feature_active( SEG_LVL_SKIP ) || |
|
seg_feature_active( SEG_LVL_REF_FRAME ) || |
|
seg_feature_active( SEG_LVL_GLOBALMV ) || |
|
!skip_mode_present || |
|
Block_Width[ MiSize ] < 8 || |
|
Block_Height[ MiSize ] < 8 ) { |
|
skip_mode = 0 |
|
} else { |
|
skip_mode |
S() |
} |
|
} |
|
Skip syntax
read_skip() { |
Type |
if ( SegIdPreSkip && seg_feature_active( SEG_LVL_SKIP ) ) { |
|
skip = 1 |
|
} else { |
|
skip |
S() |
} |
|
} |
|
Quantizer index delta syntax
read_delta_qindex( ) { |
Type |
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64 |
|
if ( MiSize == sbSize && skip ) |
|
return |
|
if ( ReadDeltas ) { |
|
delta_q_abs |
S() |
if ( delta_q_abs == DELTA_Q_SMALL ) { |
|
delta_q_rem_bits |
L(3) |
delta_q_rem_bits++ |
|
delta_q_abs_bits |
L(delta_q_rem_bits) |
delta_q_abs = delta_q_abs_bits + (1 << delta_q_rem_bits) + 1 |
|
} |
|
if ( delta_q_abs ) { |
|
delta_q_sign_bit |
L(1) |
reducedDeltaQIndex = delta_q_sign_bit ? -delta_q_abs : delta_q_abs |
|
CurrentQIndex = Clip3(1, 255, |
|
CurrentQIndex + (reducedDeltaQIndex << delta_q_res)) |
|
} |
|
} |
|
} |
|
Loop filter delta syntax
read_delta_lf( ) { |
Type |
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64 |
|
if ( MiSize == sbSize && skip ) |
|
return |
|
if ( ReadDeltas && delta_lf_present ) { |
|
frameLfCount = 1 |
|
if ( delta_lf_multi ) { |
|
frameLfCount = ( NumPlanes > 1 ) ? FRAME_LF_COUNT : ( FRAME_LF_COUNT - 2 ) |
|
} |
|
for ( i = 0; i < frameLfCount; i++ ) { |
|
delta_lf_abs |
S() |
if ( delta_lf_abs == DELTA_LF_SMALL ) { |
|
delta_lf_rem_bits |
L(3) |
n = delta_lf_rem_bits + 1 |
|
delta_lf_abs_bits |
L(n) |
deltaLfAbs = delta_lf_abs_bits + |
|
( 1 << n ) + 1 |
|
} else { |
|
deltaLfAbs = delta_lf_abs |
|
} |
|
if ( deltaLfAbs ) { |
|
delta_lf_sign_bit |
L(1) |
reducedDeltaLfLevel = delta_lf_sign_bit ? |
|
-deltaLfAbs : |
|
deltaLfAbs |
|
DeltaLF[ i ] = Clip3( -MAX_LOOP_FILTER, MAX_LOOP_FILTER, DeltaLF[ i ] + |
|
(reducedDeltaLfLevel << delta_lf_res) ) |
|
} |
|
} |
|
} |
|
} |
|
Segmentation feature active function
seg_feature_active_idx( idx, feature ) { |
Type |
return segmentation_enabled && FeatureEnabled[ idx ][ feature ] |
|
} |
|
|
|
seg_feature_active( feature ) { |
|
return seg_feature_active_idx( segment_id, feature ) |
|
} |
|
TX size syntax
read_tx_size( allowSelect ) { |
Type |
if ( Lossless ) { |
|
TxSize = TX_4X4 |
|
return |
|
} |
|
maxRectTxSize = Max_Tx_Size_Rect[ MiSize ] |
|
maxTxDepth = Max_Tx_Depth[ MiSize ] |
|
TxSize = maxRectTxSize |
|
if ( MiSize > BLOCK_4X4 && allowSelect && TxMode == TX_MODE_SELECT ) { |
|
tx_depth |
S() |
for ( i = 0; i < tx_depth; i++ ) |
|
TxSize = Split_Tx_Size[ TxSize ] |
|
} |
|
} |
|
} |
|
The Max_Tx_Depth table specifies the maximum transform depth
for each block size:
Max_Tx_Depth[ BLOCK_SIZES ] = {
0, 1, 1, 1,
2, 2, 2, 3,
3, 3, 4, 4,
4, 4, 4, 4,
2, 2, 3, 3,
4, 4
}
Note: Max_Tx_Depth contains the number of times
the transform must be split to reach a 4x4 transform size.
This number can be greater than MAX_TX_DEPTH.
However, it is impossible to encode a transform depth
greater than MAX_TX_DEPTH because
tx_depth can only encode values in the range 0 to 2
Block TX size syntax
read_block_tx_size( ) { |
Type |
bw4 = Num_4x4_Blocks_Wide[ MiSize ] |
|
bh4 = Num_4x4_Blocks_High[ MiSize ] |
|
if ( TxMode == TX_MODE_SELECT && |
|
MiSize > BLOCK_4X4 && is_inter && |
|
!skip && !Lossless ) { |
|
maxTxSz = Max_Tx_Size_Rect[ MiSize ] |
|
txW4 = Tx_Width[ maxTxSz ] / MI_SIZE |
|
txH4 = Tx_Height[ maxTxSz ] / MI_SIZE |
|
for ( row = MiRow; row < MiRow + bh4; row += txH4 ) |
|
for ( col = MiCol; col < MiCol + bw4; col += txW4 ) |
|
read_var_tx_size( row, col, maxTxSz, 0 ) |
|
} else { |
|
read_tx_size(!skip || !is_inter) |
|
for ( row = MiRow; row < MiRow + bh4; row++ ) |
|
for ( col = MiCol; col < MiCol + bw4; col++ ) |
|
InterTxSizes[ row ][ col ] = TxSize |
|
} |
|
} |
|
Var TX size syntax
read_var_tx_size is used to read a transform size tree.
read_var_tx_size( row, col, txSz, depth) { |
Type |
if ( row >= MiRows || col >= MiCols ) |
|
return |
|
if ( txSz == TX_4X4 || depth == MAX_VARTX_DEPTH ) { |
|
txfm_split = 0 |
|
} else { |
|
txfm_split |
S() |
} |
|
w4 = Tx_Width[ txSz ] / MI_SIZE |
|
h4 = Tx_Height[ txSz ] / MI_SIZE |
|
if ( txfm_split ) { |
|
subTxSz = Split_Tx_Size[ txSz ] |
|
stepW = Tx_Width[ subTxSz ] / MI_SIZE |
|
stepH = Tx_Height[ subTxSz ] / MI_SIZE |
|
for ( i = 0; i < h4; i += stepH ) |
|
for ( j = 0; j < w4; j += stepW ) |
|
read_var_tx_size( row + i, col + j, subTxSz, depth+1) |
|
} else { |
|
for ( i = 0; i < h4; i++ ) |
|
for ( j = 0; j < w4; j++ ) |
|
InterTxSizes[ row + i ][ col + j ] = txSz |
|
TxSize = txSz |
|
} |
|
} |
|
Inter frame mode info syntax
inter_frame_mode_info( ) { |
Type |
use_intrabc = 0 |
|
LeftRefFrame[ 0 ] = AvailL ? RefFrames[ MiRow ][ MiCol-1 ][ 0 ] : INTRA_FRAME |
|
AboveRefFrame[ 0 ] = AvailU ? RefFrames[ MiRow-1 ][ MiCol ][ 0 ] : INTRA_FRAME |
|
LeftRefFrame[ 1 ] = AvailL ? RefFrames[ MiRow ][ MiCol-1 ][ 1 ] : NONE |
|
AboveRefFrame[ 1 ] = AvailU ? RefFrames[ MiRow-1 ][ MiCol ][ 1 ] : NONE |
|
LeftIntra = LeftRefFrame[ 0 ] <= INTRA_FRAME |
|
AboveIntra = AboveRefFrame[ 0 ] <= INTRA_FRAME |
|
LeftSingle = LeftRefFrame[ 1 ] <= INTRA_FRAME |
|
AboveSingle = AboveRefFrame[ 1 ] <= INTRA_FRAME |
|
skip = 0 |
|
inter_segment_id( 1 ) |
|
read_skip_mode( ) |
|
if ( skip_mode ) |
|
skip = 1 |
|
else |
|
read_skip( ) |
|
if ( !SegIdPreSkip ) |
|
inter_segment_id( 0 ) |
|
Lossless = LosslessArray[ segment_id ] |
|
read_cdef( ) |
|
read_delta_qindex( ) |
|
read_delta_lf( ) |
|
ReadDeltas = 0 |
|
read_is_inter( ) |
|
if ( is_inter ) |
|
inter_block_mode_info( ) |
|
else |
|
intra_block_mode_info( ) |
|
} |
|
Inter segment ID syntax
This is called before (preSkip equal to 1) and after (preSkip equal to 0) the skip syntax element has been read.
inter_segment_id( preSkip ) { |
Type |
if ( segmentation_enabled ) { |
|
predictedSegmentId = get_segment_id( ) |
|
if ( segmentation_update_map ) { |
|
if ( preSkip && !SegIdPreSkip ) { |
|
segment_id = 0 |
|
return |
|
} |
|
if ( !preSkip ) { |
|
if ( skip ) { |
|
seg_id_predicted = 0 |
|
for ( i = 0; i < Num_4x4_Blocks_Wide[ MiSize ]; i++ ) |
|
AboveSegPredContext[ MiCol + i ] = seg_id_predicted |
|
for ( i = 0; i < Num_4x4_Blocks_High[ MiSize ]; i++ ) |
|
LeftSegPredContext[ MiRow + i ] = seg_id_predicted |
|
read_segment_id( ) |
|
return |
|
} |
|
} |
|
if ( segmentation_temporal_update == 1 ) { |
|
seg_id_predicted |
S() |
if ( seg_id_predicted ) |
|
segment_id = predictedSegmentId |
|
else |
|
read_segment_id( ) |
|
for ( i = 0; i < Num_4x4_Blocks_Wide[ MiSize ]; i++ ) |
|
AboveSegPredContext[ MiCol + i ] = seg_id_predicted |
|
for ( i = 0; i < Num_4x4_Blocks_High[ MiSize ]; i++ ) |
|
LeftSegPredContext[ MiRow + i ] = seg_id_predicted |
|
} else { |
|
read_segment_id( ) |
|
} |
|
} else { |
|
segment_id = predictedSegmentId |
|
} |
|
} else { |
|
segment_id = 0 |
|
} |
|
} |
|
Is inter syntax
read_is_inter( ) { |
Type |
if ( skip_mode ) { |
|
is_inter = 1 |
|
} else if ( seg_feature_active ( SEG_LVL_REF_FRAME ) ) { |
|
is_inter = FeatureData[ segment_id ][ SEG_LVL_REF_FRAME ] != INTRA_FRAME |
|
} else if ( seg_feature_active ( SEG_LVL_GLOBALMV ) ) { |
|
is_inter = 1 |
|
} else { |
|
is_inter |
S() |
} |
|
} |
|
Get segment ID function
The predicted segment id is the smallest value found in the on-screen region
of the segmentation map covered by the current block.
get_segment_id( ) { |
Type |
bw4 = Num_4x4_Blocks_Wide[ MiSize ] |
|
bh4 = Num_4x4_Blocks_High[ MiSize ] |
|
xMis = Min( MiCols - MiCol, bw4 ) |
|
yMis = Min( MiRows - MiRow, bh4 ) |
|
seg = 7 |
|
for ( y = 0; y < yMis; y++ ) |
|
for ( x = 0; x < xMis; x++ ) |
|
seg = Min( seg, PrevSegmentIds[ MiRow + y ][ MiCol + x ] ) |
|
return seg |
|
} |
|
Intra block mode info syntax
intra_block_mode_info( ) { |
Type |
RefFrame[ 0 ] = INTRA_FRAME |
|
RefFrame[ 1 ] = NONE |
|
y_mode |
S() |
YMode = y_mode |
|
intra_angle_info_y( ) |
|
if ( HasChroma ) { |
|
uv_mode |
S() |
UVMode = uv_mode |
|
if ( UVMode == UV_CFL_PRED ) { |
|
read_cfl_alphas( ) |
|
} |
|
intra_angle_info_uv( ) |
|
} |
|
PaletteSizeY = 0 |
|
PaletteSizeUV = 0 |
|
if ( MiSize >= BLOCK_8X8 && |
|
Block_Width[ MiSize ] <= 64 && |
|
Block_Height[ MiSize ] <= 64 && |
|
allow_screen_content_tools ) |
|
palette_mode_info( ) |
|
filter_intra_mode_info( ) |
|
} |
|
Inter block mode info syntax
inter_block_mode_info( ) { |
Type |
PaletteSizeY = 0 |
|
PaletteSizeUV = 0 |
|
read_ref_frames( ) |
|
isCompound = RefFrame[ 1 ] > INTRA_FRAME |
|
find_mv_stack( isCompound ) |
|
if ( skip_mode ) { |
|
YMode = NEAREST_NEARESTMV |
|
} else if ( seg_feature_active( SEG_LVL_SKIP ) || |
|
seg_feature_active( SEG_LVL_GLOBALMV ) ) { |
|
YMode = GLOBALMV |
|
} else if ( isCompound ) { |
|
compound_mode |
S() |
YMode = NEAREST_NEARESTMV + compound_mode |
|
} else { |
|
new_mv |
S() |
if ( new_mv == 0 ) { |
|
YMode = NEWMV |
|
} else { |
|
zero_mv |
S() |
if ( zero_mv == 0 ) { |
|
YMode = GLOBALMV |
|
} else { |
|
ref_mv |
S() |
YMode = (ref_mv == 0) ? NEARESTMV : NEARMV |
|
} |
|
} |
|
} |
|
RefMvIdx = 0 |
|
if ( YMode == NEWMV || YMode == NEW_NEWMV ) { |
|
for ( idx = 0; idx < 2; idx++ ) { |
|
if ( NumMvFound > idx + 1 ) { |
|
drl_mode |
S() |
if ( drl_mode == 0 ) { |
|
RefMvIdx = idx |
|
break |
|
} |
|
RefMvIdx = idx + 1 |
|
} |
|
} |
|
} else if ( has_nearmv( ) ) { |
|
RefMvIdx = 1 |
|
for ( idx = 1; idx < 3; idx++ ) { |
|
if ( NumMvFound > idx + 1 ) { |
|
drl_mode |
S() |
if ( drl_mode == 0 ) { |
|
RefMvIdx = idx |
|
break |
|
} |
|
RefMvIdx = idx + 1 |
|
} |
|
} |
|
} |
|
assign_mv( isCompound ) |
|
read_interintra_mode( isCompound ) |
|
read_motion_mode( isCompound ) |
|
read_compound_type( isCompound ) |
|
if ( interpolation_filter == SWITCHABLE ) { |
|
for ( dir = 0; dir < ( enable_dual_filter ? 2 : 1 ); dir++ ) { |
|
if ( needs_interp_filter( ) ) { |
|
interp_filter[ dir ] |
S() |
} else { |
|
interp_filter[ dir ] = EIGHTTAP |
|
} |
|
} |
|
if ( !enable_dual_filter ) |
|
interp_filter[ 1 ] = interp_filter[ 0 ] |
|
} else { |
|
for ( dir = 0; dir < 2; dir++ ) |
|
interp_filter[ dir ] = interpolation_filter |
|
} |
|
} |
|
The function has_nearmv is defined as:
has_nearmv( ) {
return (YMode == NEARMV || YMode == NEAR_NEARMV
|| YMode == NEAR_NEWMV || YMode == NEW_NEARMV)
}
The function needs_interp_filter is defined as:
needs_interp_filter( ) {
large = (Min(Block_Width[MiSize], Block_Height[MiSize]) >= 8)
if ( skip_mode || motion_mode == LOCALWARP ) {
return 0
} else if ( large && YMode == GLOBALMV ) {
return GmType[ RefFrame[ 0 ] ] == TRANSLATION
} else if ( large && YMode == GLOBAL_GLOBALMV ) {
return GmType[ RefFrame[ 0 ] ] == TRANSLATION || GmType[ RefFrame[ 1 ] ] == TRANSLATION
} else {
return 1
}
}
Filter intra mode info syntax
filter_intra_mode_info( ) { |
Type |
use_filter_intra = 0 |
|
if ( enable_filter_intra && |
|
YMode == DC_PRED && PaletteSizeY == 0 && |
|
Max( Block_Width[ MiSize ], Block_Height[ MiSize ] ) <= 32 ) { |
|
use_filter_intra |
S() |
if ( use_filter_intra ) { |
|
filter_intra_mode |
S() |
} |
|
} |
|
} |
|
Ref frames syntax
read_ref_frames( ) { |
Type |
if ( skip_mode ) { |
|
RefFrame[ 0 ] = SkipModeFrame[ 0 ] |
|
RefFrame[ 1 ] = SkipModeFrame[ 1 ] |
|
} else if ( seg_feature_active( SEG_LVL_REF_FRAME ) ) { |
|
RefFrame[ 0 ] = FeatureData[ segment_id ][ SEG_LVL_REF_FRAME ] |
|
RefFrame[ 1 ] = NONE |
|
} else if ( seg_feature_active( SEG_LVL_SKIP ) || |
|
seg_feature_active( SEG_LVL_GLOBALMV ) ) { |
|
RefFrame[ 0 ] = LAST_FRAME |
|
RefFrame[ 1 ] = NONE |
|
} else { |
|
bw4 = Num_4x4_Blocks_Wide[ MiSize ] |
|
bh4 = Num_4x4_Blocks_High[ MiSize ] |
|
if ( reference_select && ( Min( bw4, bh4 ) >= 2 ) ) |
|
comp_mode |
S() |
else |
|
comp_mode = SINGLE_REFERENCE |
|
if ( comp_mode == COMPOUND_REFERENCE ) { |
|
comp_ref_type |
S() |
if ( comp_ref_type == UNIDIR_COMP_REFERENCE ) { |
|
uni_comp_ref |
S() |
if ( uni_comp_ref ) { |
|
RefFrame[0] = BWDREF_FRAME |
|
RefFrame[1] = ALTREF_FRAME |
|
} else { |
|
uni_comp_ref_p1 |
S() |
if ( uni_comp_ref_p1 ) { |
|
uni_comp_ref_p2 |
S() |
if ( uni_comp_ref_p2 ) { |
|
RefFrame[0] = LAST_FRAME |
|
RefFrame[1] = GOLDEN_FRAME |
|
} else { |
|
RefFrame[0] = LAST_FRAME |
|
RefFrame[1] = LAST3_FRAME |
|
} |
|
} else { |
|
RefFrame[0] = LAST_FRAME |
|
RefFrame[1] = LAST2_FRAME |
|
} |
|
} |
|
} else { |
|
comp_ref |
S() |
if ( comp_ref == 0 ) { |
|
comp_ref_p1 |
S() |
RefFrame[ 0 ] = comp_ref_p1 ? |
|
LAST2_FRAME : LAST_FRAME |
|
} else { |
|
comp_ref_p2 |
S() |
RefFrame[ 0 ] = comp_ref_p2 ? |
|
GOLDEN_FRAME : LAST3_FRAME |
|
} |
|
comp_bwdref |
S() |
if ( comp_bwdref == 0 ) { |
|
comp_bwdref_p1 |
S() |
RefFrame[ 1 ] = comp_bwdref_p1 ? |
|
ALTREF2_FRAME : BWDREF_FRAME |
|
} else { |
|
RefFrame[ 1 ] = ALTREF_FRAME |
|
} |
|
} |
|
} else { |
|
single_ref_p1 |
S() |
if ( single_ref_p1 ) { |
|
single_ref_p2 |
S() |
if ( single_ref_p2 == 0 ) { |
|
single_ref_p6 |
S() |
RefFrame[ 0 ] = single_ref_p6 ? |
|
ALTREF2_FRAME : BWDREF_FRAME |
|
} else { |
|
RefFrame[ 0 ] = ALTREF_FRAME |
|
} |
|
} else { |
|
single_ref_p3 |
S() |
if ( single_ref_p3 ) { |
|
single_ref_p5 |
S() |
RefFrame[ 0 ] = single_ref_p5 ? |
|
GOLDEN_FRAME : LAST3_FRAME |
|
} else { |
|
single_ref_p4 |
S() |
RefFrame[ 0 ] = single_ref_p4 ? |
|
LAST2_FRAME : LAST_FRAME |
|
} |
|
} |
|
RefFrame[ 1 ] = NONE |
|
} |
|
} |
|
} |
|
Assign MV syntax
assign_mv( isCompound ) { |
Type |
for ( i = 0; i < 1 + isCompound; i++ ) { |
|
if ( use_intrabc ) { |
|
compMode = NEWMV |
|
} else { |
|
compMode = get_mode( i ) |
|
} |
|
if ( use_intrabc ) { |
|
PredMv[ 0 ] = RefStackMv[ 0 ][ 0 ] |
|
if ( PredMv[ 0 ][ 0 ] == 0 && PredMv[ 0 ][ 1 ] == 0 ) { |
|
PredMv[ 0 ] = RefStackMv[ 1 ][ 0 ] |
|
} |
|
if ( PredMv[ 0 ][ 0 ] == 0 && PredMv[ 0 ][ 1 ] == 0 ) { |
|
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64 |
|
sbSize4 = Num_4x4_Blocks_High[ sbSize ] |
|
if ( MiRow - sbSize4 < MiRowStart ) { |
|
PredMv[ 0 ][ 0 ] = 0 |
|
PredMv[ 0 ][ 1 ] = -(sbSize4 * MI_SIZE + INTRABC_DELAY_PIXELS) * 8 |
|
} else { |
|
PredMv[ 0 ][ 0 ] = -(sbSize4 * MI_SIZE * 8) |
|
PredMv[ 0 ][ 1 ] = 0 |
|
} |
|
} |
|
} else if ( compMode == GLOBALMV ) { |
|
PredMv[ i ] = GlobalMvs[ i ] |
|
} else { |
|
pos = ( compMode == NEARESTMV ) ? 0 : RefMvIdx |
|
if ( compMode == NEWMV && NumMvFound <= 1 ) |
|
pos = 0 |
|
PredMv[ i ] = RefStackMv[ pos ][ i ] |
|
} |
|
if ( compMode == NEWMV ) { |
|
read_mv( i ) |
|
} else { |
|
Mv[ i ] = PredMv[ i ] |
|
} |
|
} |
|
} |
|
Read motion mode syntax
read_motion_mode( isCompound ) { |
Type |
if ( skip_mode ) { |
|
motion_mode = SIMPLE |
|
return |
|
} |
|
if ( !is_motion_mode_switchable ) { |
|
motion_mode = SIMPLE |
|
return |
|
} |
|
if ( Min( Block_Width[ MiSize ], |
|
Block_Height[ MiSize ] ) < 8 ) { |
|
motion_mode = SIMPLE |
|
return |
|
} |
|
if ( !force_integer_mv && |
|
( YMode == GLOBALMV || YMode == GLOBAL_GLOBALMV ) ) { |
|
if ( GmType[ RefFrame[ 0 ] ] > TRANSLATION ) { |
|
motion_mode = SIMPLE |
|
return |
|
} |
|
} |
|
if ( isCompound || RefFrame[ 1 ] == INTRA_FRAME || !has_overlappable_candidates( ) ) { |
|
motion_mode = SIMPLE |
|
return |
|
} |
|
find_warp_samples() |
|
if ( force_integer_mv || NumSamples == 0 || |
|
!allow_warped_motion || is_scaled( RefFrame[0] ) ) { |
|
use_obmc |
S() |
motion_mode = use_obmc ? OBMC : SIMPLE |
|
} else { |
|
motion_mode |
S() |
} |
|
} |
|
where is_scaled is a function that determines whether a
reference frame uses scaling and is specified as:
is_scaled( refFrame ) {
refIdx = ref_frame_idx[ refFrame - LAST_FRAME ]
xScale = ( ( RefUpscaledWidth[ refIdx ] << REF_SCALE_SHIFT ) + ( FrameWidth / 2 ) ) / FrameWidth
yScale = ( ( RefFrameHeight[ refIdx ] << REF_SCALE_SHIFT ) + ( FrameHeight / 2 ) ) / FrameHeight
noScale = 1 << REF_SCALE_SHIFT
return xScale != noScale || yScale != noScale
}
Read inter intra syntax
read_interintra_mode( isCompound ) { |
Type |
if ( !skip_mode && enable_interintra_compound && !isCompound && |
|
MiSize >= BLOCK_8X8 && MiSize <= BLOCK_32X32) { |
|
interintra |
S() |
if ( interintra ) { |
|
interintra_mode |
S() |
RefFrame[1] = INTRA_FRAME |
|
AngleDeltaY = 0 |
|
AngleDeltaUV = 0 |
|
use_filter_intra = 0 |
|
wedge_interintra |
S() |
if ( wedge_interintra ) { |
|
wedge_index |
S() |
wedge_sign = 0 |
|
} |
|
} |
|
} else { |
|
interintra = 0 |
|
} |
|
} |
|
Read compound type syntax
read_compound_type( isCompound ) { |
Type |
comp_group_idx = 0 |
|
compound_idx = 1 |
|
if ( skip_mode ) { |
|
compound_type = COMPOUND_AVERAGE |
|
return |
|
} |
|
if ( isCompound ) { |
|
n = Wedge_Bits[ MiSize ] |
|
if ( enable_masked_compound ) { |
|
comp_group_idx |
S() |
} |
|
if ( comp_group_idx == 0 ) { |
|
if ( enable_jnt_comp ) { |
|
compound_idx |
S() |
compound_type = compound_idx ? COMPOUND_AVERAGE : |
|
COMPOUND_DISTANCE |
|
} else { |
|
compound_type = COMPOUND_AVERAGE |
|
} |
|
} else { |
|
if ( n == 0 ) { |
|
compound_type = COMPOUND_DIFFWTD |
|
} else { |
|
compound_type |
S() |
} |
|
} |
|
if ( compound_type == COMPOUND_WEDGE ) { |
|
wedge_index |
S() |
wedge_sign |
L(1) |
} else if ( compound_type == COMPOUND_DIFFWTD ) { |
|
mask_type |
L(1) |
} |
|
} else { |
|
if ( interintra ) { |
|
compound_type = wedge_interintra ? COMPOUND_WEDGE : COMPOUND_INTRA |
|
} else { |
|
compound_type = COMPOUND_AVERAGE |
|
} |
|
} |
|
} |
|
Get mode function
get_mode( refList ) { |
Type |
if ( refList == 0 ) { |
|
if ( YMode < NEAREST_NEARESTMV ) |
|
compMode = YMode |
|
else if ( YMode == NEW_NEWMV || YMode == NEW_NEARESTMV || YMode == NEW_NEARMV ) |
|
compMode = NEWMV |
|
else if ( YMode == NEAREST_NEARESTMV || YMode == NEAREST_NEWMV ) |
|
compMode = NEARESTMV |
|
else if ( YMode == NEAR_NEARMV || YMode == NEAR_NEWMV ) |
|
compMode = NEARMV |
|
else |
|
compMode = GLOBALMV |
|
} else { |
|
if ( YMode == NEW_NEWMV || YMode == NEAREST_NEWMV || YMode == NEAR_NEWMV ) |
|
compMode = NEWMV |
|
else if ( YMode == NEAREST_NEARESTMV || YMode == NEW_NEARESTMV ) |
|
compMode = NEARESTMV |
|
else if ( YMode == NEAR_NEARMV || YMode == NEW_NEARMV ) |
|
compMode = NEARMV |
|
else |
|
compMode = GLOBALMV |
|
} |
|
return compMode |
|
} |
|
MV syntax
read_mv( ref ) { |
Type |
diffMv[ 0 ] = 0 |
|
diffMv[ 1 ] = 0 |
|
if ( use_intrabc ) { |
|
MvCtx = MV_INTRABC_CONTEXT |
|
} else { |
|
MvCtx = 0 |
|
} |
|
mv_joint |
S() |
if ( mv_joint == MV_JOINT_HZVNZ || mv_joint == MV_JOINT_HNZVNZ ) |
|
diffMv[ 0 ] = read_mv_component( 0 ) |
|
if ( mv_joint == MV_JOINT_HNZVZ || mv_joint == MV_JOINT_HNZVNZ ) |
|
diffMv[ 1 ] = read_mv_component( 1 ) |
|
Mv[ ref ][ 0 ] = PredMv[ ref ][ 0 ] + diffMv[ 0 ] |
|
Mv[ ref ][ 1 ] = PredMv[ ref ][ 1 ] + diffMv[ 1 ] |
|
} |
|
MV component syntax
read_mv_component( comp ) { |
Type |
mv_sign |
S() |
mv_class |
S() |
if ( mv_class == MV_CLASS_0 ) { |
|
mv_class0_bit |
S() |
if ( force_integer_mv ) |
|
mv_class0_fr = 3 |
|
else |
|
mv_class0_fr |
S() |
if ( allow_high_precision_mv ) |
|
mv_class0_hp |
S() |
else |
|
mv_class0_hp = 1 |
|
mag = ( ( mv_class0_bit << 3 ) | |
|
( mv_class0_fr << 1 ) | |
|
mv_class0_hp ) + 1 |
|
} else { |
|
d = 0 |
|
for ( i = 0; i < mv_class; i++ ) { |
|
mv_bit |
S() |
d |= mv_bit << i |
|
} |
|
mag = CLASS0_SIZE << ( mv_class + 2 ) |
|
if ( force_integer_mv ) |
|
mv_fr = 3 |
|
else |
|
mv_fr |
S() |
if ( allow_high_precision_mv ) |
|
mv_hp |
S() |
else |
|
mv_hp = 1 |
|
mag += ( ( d << 3 ) | ( mv_fr << 1 ) | mv_hp ) + 1 |
|
} |
|
return mv_sign ? -mag : mag |
|
} |
|
Compute prediction syntax
compute_prediction() { |
Type |
sbMask = use_128x128_superblock ? 31 : 15 |
|
subBlockMiRow = MiRow & sbMask |
|
subBlockMiCol = MiCol & sbMask |
|
for ( plane = 0; plane < 1 + HasChroma * 2; plane++ ) { |
|
planeSz = get_plane_residual_size( MiSize, plane ) |
|
num4x4W = Num_4x4_Blocks_Wide[ planeSz ] |
|
num4x4H = Num_4x4_Blocks_High[ planeSz ] |
|
log2W = MI_SIZE_LOG2 + Mi_Width_Log2[ planeSz ] |
|
log2H = MI_SIZE_LOG2 + Mi_Height_Log2[ planeSz ] |
|
subX = (plane > 0) ? subsampling_x : 0 |
|
subY = (plane > 0) ? subsampling_y : 0 |
|
baseX = (MiCol >> subX) * MI_SIZE |
|
baseY = (MiRow >> subY) * MI_SIZE |
|
candRow = (MiRow >> subY) << subY |
|
candCol = (MiCol >> subX) << subX |
|
|
|
IsInterIntra = ( is_inter && RefFrame[ 1 ] == INTRA_FRAME ) |
|
if ( IsInterIntra ) { |
|
if ( interintra_mode == II_DC_PRED ) mode = DC_PRED |
|
else if ( interintra_mode == II_V_PRED ) mode = V_PRED |
|
else if ( interintra_mode == II_H_PRED ) mode = H_PRED |
|
else mode = SMOOTH_PRED |
|
predict_intra( plane, baseX, baseY, |
|
plane == 0 ? AvailL : AvailLChroma, |
|
plane == 0 ? AvailU : AvailUChroma, |
|
BlockDecoded[ plane ] |
|
[ ( subBlockMiRow >> subY ) - 1 ] |
|
[ ( subBlockMiCol >> subX ) + num4x4W ], |
|
BlockDecoded[ plane ] |
|
[ ( subBlockMiRow >> subY ) + num4x4H ] |
|
[ ( subBlockMiCol >> subX ) - 1 ], |
|
mode, |
|
log2W, log2H ) |
|
} |
|
if ( is_inter ) { |
|
predW = Block_Width[ MiSize ] >> subX |
|
predH = Block_Height[ MiSize ] >> subY |
|
someUseIntra = 0 |
|
for ( r = 0; r < (num4x4H << subY); r++ ) |
|
for ( c = 0; c < (num4x4W << subX); c++ ) |
|
if ( RefFrames[ candRow + r ][ candCol + c ][ 0 ] == INTRA_FRAME ) |
|
someUseIntra = 1 |
|
if ( someUseIntra ) { |
|
predW = num4x4W * 4 |
|
predH = num4x4H * 4 |
|
candRow = MiRow |
|
candCol = MiCol |
|
} |
|
r = 0 |
|
for ( y = 0; y < num4x4H * 4; y += predH ) { |
|
c = 0 |
|
for ( x = 0; x < num4x4W * 4; x += predW ) { |
|
predict_inter( plane, baseX + x, baseY + y, |
|
predW, predH, |
|
candRow + r, candCol + c) |
|
c++ |
|
} |
|
r++ |
|
} |
|
} |
|
} |
|
} |
|
Residual syntax
residual( ) { |
Type |
sbMask = use_128x128_superblock ? 31 : 15 |
|
|
|
widthChunks = Max( 1, Block_Width[ MiSize ] >> 6 ) |
|
heightChunks = Max( 1, Block_Height[ MiSize ] >> 6 ) |
|
|
|
miSizeChunk = ( widthChunks > 1 || heightChunks > 1 ) ? BLOCK_64X64 : MiSize |
|
|
|
for ( chunkY = 0; chunkY < heightChunks; chunkY++ ) { |
|
for ( chunkX = 0; chunkX < widthChunks; chunkX++ ) { |
|
miRowChunk = MiRow + ( chunkY << 4 ) |
|
miColChunk = MiCol + ( chunkX << 4 ) |
|
subBlockMiRow = miRowChunk & sbMask |
|
subBlockMiCol = miColChunk & sbMask |
|
|
|
for ( plane = 0; plane < 1 + HasChroma * 2; plane++ ) { |
|
txSz = Lossless ? TX_4X4 : get_tx_size( plane, TxSize ) |
|
stepX = Tx_Width[ txSz ] >> 2 |
|
stepY = Tx_Height[ txSz ] >> 2 |
|
planeSz = get_plane_residual_size( miSizeChunk, plane ) |
|
num4x4W = Num_4x4_Blocks_Wide[ planeSz ] |
|
num4x4H = Num_4x4_Blocks_High[ planeSz ] |
|
subX = (plane > 0) ? subsampling_x : 0 |
|
subY = (plane > 0) ? subsampling_y : 0 |
|
baseX = (miColChunk >> subX) * MI_SIZE |
|
baseY = (miRowChunk >> subY) * MI_SIZE |
|
if ( is_inter && !Lossless && !plane ) { |
|
transform_tree( baseX, baseY, num4x4W * 4, num4x4H * 4 ) |
|
} else { |
|
baseXBlock = (MiCol >> subX) * MI_SIZE |
|
baseYBlock = (MiRow >> subY) * MI_SIZE |
|
for ( y = 0; y < num4x4H; y += stepY ) |
|
for ( x = 0; x < num4x4W; x += stepX ) |
|
transform_block( plane, baseXBlock, baseYBlock, txSz, |
|
x + ( ( chunkX << 4 ) >> subX ), |
|
y + ( ( chunkY << 4 ) >> subY ) ) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
transform_block(plane, baseX, baseY, txSz, x, y) { |
Type |
startX = baseX + 4 * x |
|
startY = baseY + 4 * y |
|
subX = (plane > 0) ? subsampling_x : 0 |
|
subY = (plane > 0) ? subsampling_y : 0 |
|
row = ( startY << subY ) >> MI_SIZE_LOG2 |
|
col = ( startX << subX ) >> MI_SIZE_LOG2 |
|
sbMask = use_128x128_superblock ? 31 : 15 |
|
subBlockMiRow = row & sbMask |
|
subBlockMiCol = col & sbMask |
|
stepX = Tx_Width[ txSz ] >> MI_SIZE_LOG2 |
|
stepY = Tx_Height[ txSz ] >> MI_SIZE_LOG2 |
|
maxX = (MiCols * MI_SIZE) >> subX |
|
maxY = (MiRows * MI_SIZE) >> subY |
|
if ( startX >= maxX || startY >= maxY ) { |
|
return |
|
} |
|
if ( !is_inter ) { |
|
if ( ( ( plane == 0 ) && PaletteSizeY ) || |
|
( ( plane != 0 ) && PaletteSizeUV ) ) { |
|
predict_palette( plane, startX, startY, x, y, txSz ) |
|
} else { |
|
isCfl = (plane > 0 && UVMode == UV_CFL_PRED) |
|
if ( plane == 0 ) { |
|
mode = YMode |
|
} else { |
|
mode = ( isCfl ) ? DC_PRED : UVMode |
|
} |
|
log2W = Tx_Width_Log2[ txSz ] |
|
log2H = Tx_Height_Log2[ txSz ] |
|
predict_intra( plane, startX, startY, |
|
( plane == 0 ? AvailL : AvailLChroma ) || x > 0, |
|
( plane == 0 ? AvailU : AvailUChroma ) || y > 0, |
|
BlockDecoded[ plane ] |
|
[ ( subBlockMiRow >> subY ) - 1 ] |
|
[ ( subBlockMiCol >> subX ) + stepX ], |
|
BlockDecoded[ plane ] |
|
[ ( subBlockMiRow >> subY ) + stepY ] |
|
[ ( subBlockMiCol >> subX ) - 1 ], |
|
mode, |
|
log2W, log2H ) |
|
if ( isCfl ) { |
|
predict_chroma_from_luma( plane, startX, startY, txSz ) |
|
} |
|
} |
|
|
|
if ( plane == 0 ) { |
|
MaxLumaW = startX + stepX * 4 |
|
MaxLumaH = startY + stepY * 4 |
|
} |
|
} |
|
if ( !skip ) { |
|
eob = coeffs( plane, startX, startY, txSz ) |
|
if ( eob > 0 ) |
|
reconstruct( plane, startX, startY, txSz ) |
|
} |
|
for ( i = 0; i < stepY; i++ ) { |
|
for ( j = 0; j < stepX; j++ ) { |
|
LoopfilterTxSizes[ plane ] |
|
[ (row >> subY) + i ] |
|
[ (col >> subX) + j ] = txSz |
|
BlockDecoded[ plane ] |
|
[ ( subBlockMiRow >> subY ) + i ] |
|
[ ( subBlockMiCol >> subX ) + j ] = 1 |
|
} |
|
} |
|
} |
|
transform_tree is used to read a number of transform blocks arranged in a transform tree.
transform_tree( startX, startY, w, h ) { |
Type |
maxX = MiCols * MI_SIZE |
|
maxY = MiRows * MI_SIZE |
|
if ( startX >= maxX || startY >= maxY ) { |
|
return |
|
} |
|
row = startY >> MI_SIZE_LOG2 |
|
col = startX >> MI_SIZE_LOG2 |
|
lumaTxSz = InterTxSizes[ row ][ col ] |
|
lumaW = Tx_Width[ lumaTxSz ] |
|
lumaH = Tx_Height[ lumaTxSz ] |
|
if ( w <= lumaW && h <= lumaH ) { |
|
txSz = find_tx_size( w, h ) |
|
transform_block( 0, startX, startY, txSz, 0, 0 ) |
|
} else { |
|
if ( w > h ) { |
|
transform_tree( startX, startY, w/2, h ) |
|
transform_tree( startX + w / 2, startY, w/2, h ) |
|
} else if ( w < h ) { |
|
transform_tree( startX, startY, w, h/2 ) |
|
transform_tree( startX, startY + h/2, w, h/2 ) |
|
} else { |
|
transform_tree( startX, startY, w/2, h/2 ) |
|
transform_tree( startX + w/2, startY, w/2, h/2 ) |
|
transform_tree( startX, startY + h/2, w/2, h/2 ) |
|
transform_tree( startX + w/2, startY + h/2, w/2, h/2 ) |
|
} |
|
} |
|
} |
|
where find_tx_size finds the transform size matching the given dimensions and is defined as:
find_tx_size( w, h ) {
for ( txSz = 0; txSz < TX_SIZES_ALL; txSz++ )
if ( Tx_Width[ txSz ] == w && Tx_Height[ txSz ] == h )
break
return txSz
}
Get TX size function
get_tx_size( plane, txSz ) { |
Type |
if ( plane == 0 ) |
|
return txSz |
|
uvTx = Max_Tx_Size_Rect[ get_plane_residual_size( MiSize, plane ) ] |
|
if ( Tx_Width[ uvTx ] == 64 || Tx_Height[ uvTx ] == 64 ){ |
|
if ( Tx_Width[ uvTx ] == 16 ) { |
|
return TX_16X32 |
|
} |
|
if ( Tx_Height[ uvTx ] == 16 ) { |
|
return TX_32X16 |
|
} |
|
return TX_32X32 |
|
} |
|
return uvTx |
|
} |
|
Get plane residual size function
The get_plane_residual_size returns the size of a residual block for the
specified plane. (The residual block will always have width and height at least
equal to 4.)
get_plane_residual_size( subsize, plane ) { |
Type |
subx = plane > 0 ? subsampling_x : 0 |
|
suby = plane > 0 ? subsampling_y : 0 |
|
return Subsampled_Size[ subsize ][ subx ][ suby ] |
|
} |
|
The Subsampled_Size table is defined as:
Subsampled_Size[ BLOCK_SIZES ][ 2 ][ 2 ] = {
{ { BLOCK_4X4, BLOCK_4X4}, {BLOCK_4X4, BLOCK_4X4} },
{ { BLOCK_4X8, BLOCK_4X4}, {BLOCK_INVALID, BLOCK_4X4} },
{ { BLOCK_8X4, BLOCK_INVALID}, {BLOCK_4X4, BLOCK_4X4} },
{ { BLOCK_8X8, BLOCK_8X4}, {BLOCK_4X8, BLOCK_4X4} },
{ {BLOCK_8X16, BLOCK_8X8}, {BLOCK_INVALID, BLOCK_4X8} },
{ {BLOCK_16X8, BLOCK_INVALID}, {BLOCK_8X8, BLOCK_8X4} },
{ {BLOCK_16X16, BLOCK_16X8}, {BLOCK_8X16, BLOCK_8X8} },
{ {BLOCK_16X32, BLOCK_16X16}, {BLOCK_INVALID, BLOCK_8X16} },
{ {BLOCK_32X16, BLOCK_INVALID}, {BLOCK_16X16, BLOCK_16X8} },
{ {BLOCK_32X32, BLOCK_32X16}, {BLOCK_16X32, BLOCK_16X16} },
{ {BLOCK_32X64, BLOCK_32X32}, {BLOCK_INVALID, BLOCK_16X32} },
{ {BLOCK_64X32, BLOCK_INVALID}, {BLOCK_32X32, BLOCK_32X16} },
{ {BLOCK_64X64, BLOCK_64X32}, {BLOCK_32X64, BLOCK_32X32} },
{ {BLOCK_64X128, BLOCK_64X64}, {BLOCK_INVALID, BLOCK_32X64} },
{ {BLOCK_128X64, BLOCK_INVALID}, {BLOCK_64X64, BLOCK_64X32} },
{ {BLOCK_128X128, BLOCK_128X64}, {BLOCK_64X128, BLOCK_64X64} },
{ {BLOCK_4X16, BLOCK_4X8}, {BLOCK_INVALID, BLOCK_4X8} },
{ {BLOCK_16X4, BLOCK_INVALID}, {BLOCK_8X4, BLOCK_8X4} },
{ {BLOCK_8X32, BLOCK_8X16}, {BLOCK_INVALID, BLOCK_4X16} },
{ {BLOCK_32X8, BLOCK_INVALID}, {BLOCK_16X8, BLOCK_16X4} },
{ {BLOCK_16X64, BLOCK_16X32}, {BLOCK_INVALID, BLOCK_8X32} },
{ {BLOCK_64X16, BLOCK_INVALID}, {BLOCK_32X16, BLOCK_32X8} },
}
Coefficients syntax
coeffs( plane, startX, startY, txSz ) { |
Type |
x4 = startX >> 2 |
|
y4 = startY >> 2 |
|
w4 = Tx_Width[ txSz ] >> 2 |
|
h4 = Tx_Height[ txSz ] >> 2 |
|
|
|
txSzCtx = ( Tx_Size_Sqr[txSz] + Tx_Size_Sqr_Up[txSz] + 1 ) >> 1 |
|
ptype = plane > 0 |
|
segEob = ( txSz == TX_16X64 || txSz == TX_64X16 ) ? 512 : |
|
Min( 1024, Tx_Width[ txSz ] * Tx_Height[ txSz ] ) |
|
|
|
for ( c = 0; c < segEob; c++ ) |
|
Quant[c] = 0 |
|
for ( i = 0; i < 64; i++ ) |
|
for ( j = 0; j < 64; j++ ) |
|
Dequant[ i ][ j ] = 0 |
|
|
|
eob = 0 |
|
culLevel = 0 |
|
dcCategory = 0 |
|
|
|
all_zero |
S() |
if ( all_zero ) { |
|
c = 0 |
|
if ( plane == 0 ) { |
|
for ( i = 0; i < w4; i++ ) { |
|
for ( j = 0; j < h4; j++ ) { |
|
TxTypes[ y4 + j ][ x4 + i ] = DCT_DCT |
|
} |
|
} |
|
} |
|
} else { |
|
if ( plane == 0 ) |
|
transform_type( x4, y4, txSz ) |
|
PlaneTxType = compute_tx_type( plane, txSz, x4, y4 ) |
|
scan = get_scan( txSz ) |
|
|
|
eobMultisize = Min( Tx_Width_Log2[ txSz ], 5) + Min( Tx_Height_Log2[ txSz ], 5) - 4 |
|
if ( eobMultisize == 0 ) { |
|
eob_pt_16 |
S() |
eobPt = eob_pt_16 + 1 |
|
} else if ( eobMultisize == 1 ) { |
|
eob_pt_32 |
S() |
eobPt = eob_pt_32 + 1 |
|
} else if ( eobMultisize == 2 ) { |
|
eob_pt_64 |
S() |
eobPt = eob_pt_64 + 1 |
|
} else if ( eobMultisize == 3 ) { |
|
eob_pt_128 |
S() |
eobPt = eob_pt_128 + 1 |
|
} else if ( eobMultisize == 4 ) { |
|
eob_pt_256 |
S() |
eobPt = eob_pt_256 + 1 |
|
} else if ( eobMultisize == 5 ) { |
|
eob_pt_512 |
S() |
eobPt = eob_pt_512 + 1 |
|
} else { |
|
eob_pt_1024 |
S() |
eobPt = eob_pt_1024 + 1 |
|
} |
|
|
|
eob = ( eobPt < 2 ) ? eobPt : ( ( 1 << ( eobPt - 2 ) ) + 1 ) |
|
eobShift = Max( -1, eobPt - 3 ) |
|
if ( eobShift >= 0 ) { |
|
eob_extra |
S() |
if ( eob_extra ) { |
|
eob += ( 1 << eobShift ) |
|
} |
|
|
|
for ( i = 1; i < Max( 0, eobPt - 2 ); i++ ) { |
|
eobShift = Max( 0, eobPt - 2 ) - 1 - i |
|
eob_extra_bit |
L(1) |
if ( eob_extra_bit ) { |
|
eob += ( 1 << eobShift ) |
|
} |
|
} |
|
} |
|
for ( c = eob - 1; c >= 0; c-- ) { |
|
pos = scan[ c ] |
|
if ( c == ( eob - 1 ) ) { |
|
coeff_base_eob |
S() |
level = coeff_base_eob + 1 |
|
} else { |
|
coeff_base |
S() |
level = coeff_base |
|
} |
|
|
|
if ( level > NUM_BASE_LEVELS ) { |
|
for ( idx = 0; |
|
idx < COEFF_BASE_RANGE / ( BR_CDF_SIZE - 1 ); |
|
idx++ ) { |
|
coeff_br |
S() |
level += coeff_br |
|
if ( coeff_br < ( BR_CDF_SIZE - 1 ) ) |
|
break |
|
} |
|
} |
|
Quant[ pos ] = level |
|
} |
|
|
|
for ( c = 0; c < eob; c++ ) { |
|
pos = scan[ c ] |
|
if ( Quant[ pos ] != 0 ) { |
|
if ( c == 0 ) { |
|
dc_sign |
S() |
sign = dc_sign |
|
} else { |
|
sign_bit |
L(1) |
sign = sign_bit |
|
} |
|
} else { |
|
sign = 0 |
|
} |
|
if ( Quant[ pos ] > |
|
( NUM_BASE_LEVELS + COEFF_BASE_RANGE ) ) { |
|
length = 0 |
|
do { |
|
length++ |
|
golomb_length_bit |
L(1) |
} while ( !golomb_length_bit ) |
|
x = 1 |
|
for ( i = length - 2; i >= 0; i-- ) { |
|
golomb_data_bit |
L(1) |
x = ( x << 1 ) | golomb_data_bit |
|
} |
|
Quant[ pos ] = x + COEFF_BASE_RANGE + NUM_BASE_LEVELS |
|
} |
|
if ( pos == 0 && Quant[ pos ] > 0 ) { |
|
dcCategory = sign ? 1 : 2 |
|
} |
|
Quant[ pos ] = Quant[ pos ] & 0xFFFFF |
|
culLevel += Quant[ pos ] |
|
if ( sign ) |
|
Quant[ pos ] = - Quant[ pos ] |
|
} |
|
culLevel = Min( 63, culLevel ) |
|
} |
|
|
|
for ( i = 0; i < w4; i++ ) { |
|
AboveLevelContext[ plane ][ x4 + i ] = culLevel |
|
AboveDcContext[ plane ][ x4 + i ] = dcCategory |
|
} |
|
for ( i = 0; i < h4; i++ ) { |
|
LeftLevelContext[ plane ][ y4 + i ] = culLevel |
|
LeftDcContext[ plane ][ y4 + i ] = dcCategory |
|
} |
|
|
|
return eob |
|
} |
|
compute_tx_type( plane, txSz, blockX, blockY ) { |
Type |
txSzSqrUp = Tx_Size_Sqr_Up[ txSz ] |
|
|
|
if ( Lossless || txSzSqrUp > TX_32X32 ) |
|
return DCT_DCT |
|
|
|
txSet = get_tx_set( txSz ) |
|
|
|
if ( plane == 0 ) { |
|
return TxTypes[ blockY ][ blockX ] |
|
} |
|
|
|
if ( is_inter ) { |
|
x4 = Max( MiCol, blockX << subsampling_x ) |
|
y4 = Max( MiRow, blockY << subsampling_y ) |
|
txType = TxTypes[ y4 ][ x4 ] |
|
if ( !is_tx_type_in_set( txSet, txType ) ) |
|
return DCT_DCT |
|
return txType |
|
} |
|
|
|
txType = Mode_To_Txfm[ UVMode ] |
|
if ( !is_tx_type_in_set( txSet, txType ) ) |
|
return DCT_DCT |
|
return txType |
|
} |
|
|
|
is_tx_type_in_set( txSet, txType ) { |
|
return is_inter ? Tx_Type_In_Set_Inter[ txSet ][ txType ] : |
|
Tx_Type_In_Set_Intra[ txSet ][ txType ] |
|
} |
|
where the tables Tx_Type_In_Set_Inter and Tx_Type_In_Set_Intra are specified as follows:
Tx_Type_In_Set_Intra[ TX_SET_TYPES_INTRA ][ TX_TYPES ] = {
{
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
{
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
},
{
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
}
}
Tx_Type_In_Set_Inter[ TX_SET_TYPES_INTER ][ TX_TYPES ] = {
{
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
},
{
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
}
}
Get scan function
get_mrow_scan( txSz ) { |
Type |
if ( txSz == TX_4X4 ) |
|
return Mrow_Scan_4x4 |
|
else if ( txSz == TX_4X8 ) |
|
return Mrow_Scan_4x8 |
|
else if ( txSz == TX_8X4 ) |
|
return Mrow_Scan_8x4 |
|
else if ( txSz == TX_8X8 ) |
|
return Mrow_Scan_8x8 |
|
else if ( txSz == TX_8X16 ) |
|
return Mrow_Scan_8x16 |
|
else if ( txSz == TX_16X8 ) |
|
return Mrow_Scan_16x8 |
|
else if ( txSz == TX_16X16 ) |
|
return Mrow_Scan_16x16 |
|
else if ( txSz == TX_4X16 ) |
|
return Mrow_Scan_4x16 |
|
return Mrow_Scan_16x4 |
|
} |
|
|
|
get_mcol_scan( txSz ) { |
|
if ( txSz == TX_4X4 ) |
|
return Mcol_Scan_4x4 |
|
else if ( txSz == TX_4X8 ) |
|
return Mcol_Scan_4x8 |
|
else if ( txSz == TX_8X4 ) |
|
return Mcol_Scan_8x4 |
|
else if ( txSz == TX_8X8 ) |
|
return Mcol_Scan_8x8 |
|
else if ( txSz == TX_8X16 ) |
|
return Mcol_Scan_8x16 |
|
else if ( txSz == TX_16X8 ) |
|
return Mcol_Scan_16x8 |
|
else if ( txSz == TX_16X16 ) |
|
return Mcol_Scan_16x16 |
|
else if ( txSz == TX_4X16 ) |
|
return Mcol_Scan_4x16 |
|
return Mcol_Scan_16x4 |
|
} |
|
|
|
get_default_scan( txSz ) { |
|
if ( txSz == TX_4X4 ) |
|
return Default_Scan_4x4 |
|
else if ( txSz == TX_4X8 ) |
|
return Default_Scan_4x8 |
|
else if ( txSz == TX_8X4 ) |
|
return Default_Scan_8x4 |
|
else if ( txSz == TX_8X8 ) |
|
return Default_Scan_8x8 |
|
else if ( txSz == TX_8X16 ) |
|
return Default_Scan_8x16 |
|
else if ( txSz == TX_16X8 ) |
|
return Default_Scan_16x8 |
|
else if ( txSz == TX_16X16 ) |
|
return Default_Scan_16x16 |
|
else if ( txSz == TX_16X32 ) |
|
return Default_Scan_16x32 |
|
else if ( txSz == TX_32X16 ) |
|
return Default_Scan_32x16 |
|
else if ( txSz == TX_4X16 ) |
|
return Default_Scan_4x16 |
|
else if ( txSz == TX_16X4 ) |
|
return Default_Scan_16x4 |
|
else if ( txSz == TX_8X32 ) |
|
return Default_Scan_8x32 |
|
else if ( txSz == TX_32X8 ) |
|
return Default_Scan_32x8 |
|
return Default_Scan_32x32 |
|
} |
|
|
|
get_scan( txSz ) { |
|
if ( txSz == TX_16X64 ) { |
|
return Default_Scan_16x32 |
|
} |
|
if ( txSz == TX_64X16 ) { |
|
return Default_Scan_32x16 |
|
} |
|
if ( Tx_Size_Sqr_Up[ txSz ] == TX_64X64 ) { |
|
return Default_Scan_32x32 |
|
} |
|
|
|
if ( PlaneTxType == IDTX ) { |
|
return get_default_scan( txSz ) |
|
} |
|
|
|
preferRow = ( PlaneTxType == V_DCT || |
|
PlaneTxType == V_ADST || |
|
PlaneTxType == V_FLIPADST ) |
|
|
|
preferCol = ( PlaneTxType == H_DCT || |
|
PlaneTxType == H_ADST || |
|
PlaneTxType == H_FLIPADST ) |
|
|
|
if ( preferRow ) { |
|
return get_mrow_scan( txSz ) |
|
} else if ( preferCol ) { |
|
return get_mcol_scan( txSz ) |
|
} |
|
return get_default_scan( txSz ) |
|
} |
|
Intra angle info luma syntax
intra_angle_info_y( ) { |
Type |
AngleDeltaY = 0 |
|
if ( MiSize >= BLOCK_8X8 ) { |
|
if ( is_directional_mode( YMode ) ) { |
|
angle_delta_y |
S() |
AngleDeltaY = angle_delta_y - MAX_ANGLE_DELTA |
|
} |
|
} |
|
} |
|
Intra angle info chroma syntax
intra_angle_info_uv( ) { |
Type |
AngleDeltaUV = 0 |
|
if ( MiSize >= BLOCK_8X8 ) { |
|
if ( is_directional_mode( UVMode ) ) { |
|
angle_delta_uv |
S() |
AngleDeltaUV = angle_delta_uv - MAX_ANGLE_DELTA |
|
} |
|
} |
|
} |
|
Is directional mode function
is_directional_mode( mode ) { |
Type |
if ( ( mode >= V_PRED ) && ( mode <= D67_PRED ) ) { |
|
return 1 |
|
} |
|
return 0 |
|
} |
|
Read CFL alphas syntax
read_cfl_alphas() { |
Type |
cfl_alpha_signs |
S() |
signU = (cfl_alpha_signs + 1 ) / 3 |
|
signV = (cfl_alpha_signs + 1 ) % 3 |
|
if ( signU != CFL_SIGN_ZERO ) { |
|
cfl_alpha_u |
S() |
CflAlphaU = 1 + cfl_alpha_u |
|
if ( signU == CFL_SIGN_NEG ) |
|
CflAlphaU = -CflAlphaU |
|
} else { |
|
CflAlphaU = 0 |
|
} |
|
if ( signV != CFL_SIGN_ZERO ) { |
|
cfl_alpha_v |
S() |
CflAlphaV = 1 + cfl_alpha_v |
|
if ( signV == CFL_SIGN_NEG ) |
|
CflAlphaV = -CflAlphaV |
|
} else { |
|
CflAlphaV = 0 |
|
} |
|
Palette mode info syntax
palette_mode_info( ) { |
Type |
bsizeCtx = Mi_Width_Log2[ MiSize ] + Mi_Height_Log2[ MiSize ] - 2 |
|
if ( YMode == DC_PRED ) { |
|
has_palette_y |
S() |
if ( has_palette_y ) { |
|
palette_size_y_minus_2 |
S() |
PaletteSizeY = palette_size_y_minus_2 + 2 |
|
cacheN = get_palette_cache( 0 ) |
|
idx = 0 |
|
for ( i = 0; i < cacheN && idx < PaletteSizeY; i++ ) { |
|
use_palette_color_cache_y |
L(1) |
if ( use_palette_color_cache_y ) { |
|
palette_colors_y[ idx ] = PaletteCache[ i ] |
|
idx++ |
|
} |
|
} |
|
if ( idx < PaletteSizeY ) { |
|
palette_colors_y[ idx ] |
L(BitDepth) |
idx++ |
|
} |
|
if ( idx < PaletteSizeY ) { |
|
minBits = BitDepth - 3 |
|
palette_num_extra_bits_y |
L(2) |
paletteBits = minBits + palette_num_extra_bits_y |
|
} |
|
while ( idx < PaletteSizeY ) { |
|
palette_delta_y |
L(paletteBits) |
palette_delta_y++ |
|
palette_colors_y[ idx ] = |
|
Clip1( palette_colors_y[ idx - 1 ] + |
|
palette_delta_y ) |
|
range = ( 1 << BitDepth ) - palette_colors_y[ idx ] - 1 |
|
paletteBits = Min( paletteBits, CeilLog2( range ) ) |
|
idx++ |
|
} |
|
sort( palette_colors_y, 0, PaletteSizeY - 1 ) |
|
} |
|
} |
|
if ( HasChroma && UVMode == DC_PRED ) { |
|
has_palette_uv |
S() |
if ( has_palette_uv ) { |
|
palette_size_uv_minus_2 |
S() |
PaletteSizeUV = palette_size_uv_minus_2 + 2 |
|
cacheN = get_palette_cache( 1 ) |
|
idx = 0 |
|
for ( i = 0; i < cacheN && idx < PaletteSizeUV; i++ ) { |
|
use_palette_color_cache_u |
L(1) |
if ( use_palette_color_cache_u ) { |
|
palette_colors_u[ idx ] = PaletteCache[ i ] |
|
idx++ |
|
} |
|
} |
|
if ( idx < PaletteSizeUV ) { |
|
palette_colors_u[ idx ] |
L(BitDepth) |
idx++ |
|
} |
|
if ( idx < PaletteSizeUV ) { |
|
minBits = BitDepth - 3 |
|
palette_num_extra_bits_u |
L(2) |
paletteBits = minBits + palette_num_extra_bits_u |
|
} |
|
while ( idx < PaletteSizeUV ) { |
|
palette_delta_u |
L(paletteBits) |
palette_colors_u[ idx ] = |
|
Clip1( palette_colors_u[ idx - 1 ] + |
|
palette_delta_u ) |
|
range = ( 1 << BitDepth ) - palette_colors_u[ idx ] |
|
paletteBits = Min( paletteBits, CeilLog2( range ) ) |
|
idx++ |
|
} |
|
sort( palette_colors_u, 0, PaletteSizeUV - 1 ) |
|
|
|
delta_encode_palette_colors_v |
L(1) |
if ( delta_encode_palette_colors_v ) { |
|
minBits = BitDepth - 4 |
|
maxVal = 1 << BitDepth |
|
palette_num_extra_bits_v |
L(2) |
paletteBits = minBits + palette_num_extra_bits_v |
|
palette_colors_v[ 0 ] |
L(BitDepth) |
for ( idx = 1; idx < PaletteSizeUV; idx++ ) { |
|
palette_delta_v |
L(paletteBits) |
if ( palette_delta_v ) { |
|
palette_delta_sign_bit_v |
L(1) |
if ( palette_delta_sign_bit_v ) { |
|
palette_delta_v = -palette_delta_v |
|
} |
|
} |
|
val = palette_colors_v[ idx - 1 ] + palette_delta_v |
|
if ( val < 0 ) val += maxVal |
|
if ( val >= maxVal ) val -= maxVal |
|
palette_colors_v[ idx ] = Clip1( val ) |
|
} |
|
} else { |
|
for ( idx = 0; idx < PaletteSizeUV; idx++ ) { |
|
palette_colors_v[ idx ] |
L(BitDepth) |
} |
|
} |
|
} |
|
} |
|
} |
|
The function sort( arr, i1, i2 ) sorts a subarray of the array arr in-place into
ascending order. The subarray to be sorted is between indices i1 and i2
inclusive.
Note: The palette colors are generated in ascending order. The palette cache
is also in ascending order. This means that the sort function can be replaced in
implementations by a merge of two sorted lists.
where the function get_palette_cache, which merges the above and left palettes
to form a cache, is specified as follows:
get_palette_cache( plane ) { |
Type |
aboveN = 0 |
|
if ( ( MiRow * MI_SIZE ) % 64 ) { |
|
aboveN = PaletteSizes[ plane ][ MiRow - 1 ][ MiCol ] |
|
} |
|
leftN = 0 |
|
if ( AvailL ) { |
|
leftN = PaletteSizes[ plane ][ MiRow ][ MiCol - 1 ] |
|
} |
|
aboveIdx = 0 |
|
leftIdx = 0 |
|
n = 0 |
|
while ( aboveIdx < aboveN && leftIdx < leftN ) { |
|
aboveC = PaletteColors[ plane ][ MiRow - 1 ][ MiCol ][ aboveIdx ] |
|
leftC = PaletteColors[ plane ][ MiRow ][ MiCol - 1 ][ leftIdx ] |
|
if ( leftC < aboveC ) { |
|
if ( n == 0 || leftC != PaletteCache[ n - 1 ] ) { |
|
PaletteCache[ n ] = leftC |
|
n++ |
|
} |
|
leftIdx++ |
|
} else { |
|
if ( n == 0 || aboveC != PaletteCache[ n - 1 ] ) { |
|
PaletteCache[ n ] = aboveC |
|
n++ |
|
} |
|
aboveIdx++ |
|
if ( leftC == aboveC ) { |
|
leftIdx++ |
|
} |
|
} |
|
} |
|
while ( aboveIdx < aboveN ) { |
|
val = PaletteColors[ plane ][ MiRow - 1 ][ MiCol ][ aboveIdx ] |
|
aboveIdx++ |
|
if ( n == 0 || val != PaletteCache[ n - 1 ] ) { |
|
PaletteCache[ n ] = val |
|
n++ |
|
} |
|
} |
|
while ( leftIdx < leftN ) { |
|
val = PaletteColors[ plane ][ MiRow ][ MiCol - 1 ][ leftIdx ] |
|
leftIdx++ |
|
if ( n == 0 || val != PaletteCache[ n - 1 ] ) { |
|
PaletteCache[ n ] = val |
|
n++ |
|
} |
|
} |
|
return n |
|
} |
|
Note: get_palette_cache is equivalent to sorting the available palette
colors from above and left together and removing any duplicates.
transform_type( x4, y4, txSz ) { |
Type |
set = get_tx_set( txSz ) |
|
|
|
if ( set > 0 && |
|
( segmentation_enabled ? get_qindex( 1, segment_id ) : base_q_idx ) > 0 ) { |
|
if ( is_inter ) { |
|
inter_tx_type |
S() |
if ( set == TX_SET_INTER_1 ) |
|
TxType = Tx_Type_Inter_Inv_Set1[ inter_tx_type ] |
|
else if ( set == TX_SET_INTER_2 ) |
|
TxType = Tx_Type_Inter_Inv_Set2[ inter_tx_type ] |
|
else |
|
TxType = Tx_Type_Inter_Inv_Set3[ inter_tx_type ] |
|
} else { |
|
intra_tx_type |
S() |
if ( set == TX_SET_INTRA_1 ) |
|
TxType = Tx_Type_Intra_Inv_Set1[ intra_tx_type ] |
|
else |
|
TxType = Tx_Type_Intra_Inv_Set2[ intra_tx_type ] |
|
} |
|
} else { |
|
TxType = DCT_DCT |
|
} |
|
for ( i = 0; i < ( Tx_Width[ txSz ] >> 2 ); i++ ) { |
|
for ( j = 0; j < ( Tx_Height[ txSz ] >> 2 ); j++ ) { |
|
TxTypes[ y4 + j ][ x4 + i ] = TxType |
|
} |
|
} |
|
} |
|
where the inversion tables used in the function are specified as follows:
Tx_Type_Intra_Inv_Set1[ 7 ] = { IDTX, DCT_DCT, V_DCT, H_DCT, ADST_ADST, ADST_DCT, DCT_ADST }
Tx_Type_Intra_Inv_Set2[ 5 ] = { IDTX, DCT_DCT, ADST_ADST, ADST_DCT, DCT_ADST }
Tx_Type_Inter_Inv_Set1[ 16 ] = { IDTX, V_DCT, H_DCT, V_ADST, H_ADST, V_FLIPADST, H_FLIPADST,
DCT_DCT, ADST_DCT, DCT_ADST, FLIPADST_DCT, DCT_FLIPADST, ADST_ADST,
FLIPADST_FLIPADST, ADST_FLIPADST, FLIPADST_ADST }
Tx_Type_Inter_Inv_Set2[ 12 ] = { IDTX, V_DCT, H_DCT, DCT_DCT, ADST_DCT, DCT_ADST, FLIPADST_DCT,
DCT_FLIPADST, ADST_ADST, FLIPADST_FLIPADST, ADST_FLIPADST,
FLIPADST_ADST }
Tx_Type_Inter_Inv_Set3[ 2 ] = { IDTX, DCT_DCT }
get_tx_set( txSz ) { |
Type |
txSzSqr = Tx_Size_Sqr[ txSz ] |
|
txSzSqrUp = Tx_Size_Sqr_Up[ txSz ] |
|
if ( txSzSqrUp > TX_32X32 ) |
|
return TX_SET_DCTONLY |
|
if ( is_inter ) { |
|
if ( reduced_tx_set || txSzSqrUp == TX_32X32 ) return TX_SET_INTER_3 |
|
else if ( txSzSqr == TX_16X16 ) return TX_SET_INTER_2 |
|
return TX_SET_INTER_1 |
|
} else { |
|
if ( txSzSqrUp == TX_32X32 ) return TX_SET_DCTONLY |
|
else if ( reduced_tx_set ) return TX_SET_INTRA_2 |
|
else if ( txSzSqr == TX_16X16 ) return TX_SET_INTRA_2 |
|
return TX_SET_INTRA_1 |
|
} |
|
} |
|
Palette tokens syntax
palette_tokens( ) { |
Type |
blockHeight = Block_Height[ MiSize ] |
|
blockWidth = Block_Width[ MiSize ] |
|
onscreenHeight = Min( blockHeight, (MiRows - MiRow) * MI_SIZE ) |
|
onscreenWidth = Min( blockWidth, (MiCols - MiCol) * MI_SIZE ) |
|
|
|
if ( PaletteSizeY ) { |
|
color_index_map_y |
NS(PaletteSizeY) |
ColorMapY[0][0] = color_index_map_y |
|
for ( i = 1; i < onscreenHeight + onscreenWidth - 1; i++ ) { |
|
for ( j = Min( i, onscreenWidth - 1 ); |
|
j >= Max( 0, i - onscreenHeight + 1 ); j-- ) { |
|
get_palette_color_context( |
|
ColorMapY, ( i - j ), j, PaletteSizeY ) |
|
palette_color_idx_y |
S() |
ColorMapY[ i - j ][ j ] = ColorOrder[ palette_color_idx_y ] |
|
} |
|
} |
|
for ( i = 0; i < onscreenHeight; i++ ) { |
|
for ( j = onscreenWidth; j < blockWidth; j++ ) { |
|
ColorMapY[ i ][ j ] = ColorMapY[ i ][ onscreenWidth - 1 ] |
|
} |
|
} |
|
for ( i = onscreenHeight; i < blockHeight; i++ ) { |
|
for ( j = 0; j < blockWidth; j++ ) { |
|
ColorMapY[ i ][ j ] = ColorMapY[ onscreenHeight - 1 ][ j ] |
|
} |
|
} |
|
} |
|
|
|
if ( PaletteSizeUV ) { |
|
color_index_map_uv |
NS(PaletteSizeUV) |
ColorMapUV[0][0] = color_index_map_uv |
|
blockHeight = blockHeight >> subsampling_y |
|
blockWidth = blockWidth >> subsampling_x |
|
onscreenHeight = onscreenHeight >> subsampling_y |
|
onscreenWidth = onscreenWidth >> subsampling_x |
|
if ( blockWidth < 4 ) { |
|
blockWidth += 2 |
|
onscreenWidth += 2 |
|
} |
|
if ( blockHeight < 4 ) { |
|
blockHeight += 2 |
|
onscreenHeight += 2 |
|
} |
|
|
|
for ( i = 1; i < onscreenHeight + onscreenWidth - 1; i++ ) { |
|
for ( j = Min( i, onscreenWidth - 1 ); |
|
j >= Max( 0, i - onscreenHeight + 1 ); j-- ) { |
|
get_palette_color_context( |
|
ColorMapUV, ( i - j ), j, PaletteSizeUV ) |
|
palette_color_idx_uv |
S() |
ColorMapUV[ i - j ][ j ] = ColorOrder[ palette_color_idx_uv ] |
|
} |
|
} |
|
for ( i = 0; i < onscreenHeight; i++ ) { |
|
for ( j = onscreenWidth; j < blockWidth; j++ ) { |
|
ColorMapUV[ i ][ j ] = ColorMapUV[ i ][ onscreenWidth - 1 ] |
|
} |
|
} |
|
for ( i = onscreenHeight; i < blockHeight; i++ ) { |
|
for ( j = 0; j < blockWidth; j++ ) { |
|
ColorMapUV[ i ][ j ] = ColorMapUV[ onscreenHeight - 1 ][ j ] |
|
} |
|
} |
|
} |
|
} |
|
Palette color context function
get_palette_color_context( colorMap, r, c, n ) { |
Type |
for ( i = 0; i < PALETTE_COLORS; i++ ) { |
|
scores[ i ] = 0 |
|
ColorOrder[i] = i |
|
} |
|
if ( c > 0 ) { |
|
neighbor = colorMap[ r ][ c - 1 ] |
|
scores[ neighbor ] += 2 |
|
} |
|
if ( ( r > 0 ) && ( c > 0 ) ) { |
|
neighbor = colorMap[ r - 1 ][ c - 1 ] |
|
scores[ neighbor ] += 1 |
|
} |
|
if ( r > 0 ) { |
|
neighbor = colorMap[ r - 1 ][ c ] |
|
scores[ neighbor ] += 2 |
|
} |
|
for ( i = 0; i < PALETTE_NUM_NEIGHBORS; i++ ) { |
|
maxScore = scores[ i ] |
|
maxIdx = i |
|
for ( j = i + 1; j < n; j++ ) { |
|
if ( scores[ j ] > maxScore ) { |
|
maxScore = scores[ j ] |
|
maxIdx = j |
|
} |
|
} |
|
if ( maxIdx != i ) { |
|
maxScore = scores[ maxIdx ] |
|
maxColorOrder = ColorOrder[ maxIdx ] |
|
for ( k = maxIdx; k > i; k-- ) { |
|
scores[ k ] = scores[ k - 1 ] |
|
ColorOrder[ k ] = ColorOrder[ k - 1 ] |
|
} |
|
scores[ i ] = maxScore |
|
ColorOrder[ i ] = maxColorOrder |
|
} |
|
} |
|
ColorContextHash = 0 |
|
for ( i = 0; i < PALETTE_NUM_NEIGHBORS; i++ ) { |
|
ColorContextHash += scores[ i ] * Palette_Color_Hash_Multipliers[ i ] |
|
} |
|
} |
|
Is inside function
is_inside determines whether a candidate position is inside the current tile.
is_inside( candidateR, candidateC ) { |
Type |
return ( candidateC >= MiColStart && |
|
candidateC < MiColEnd && |
|
candidateR >= MiRowStart && |
|
candidateR < MiRowEnd ) |
|
} |
|
Is inside filter region function
is_inside_filter_region determines whether a candidate position is inside the region that is being used for CDEF filtering.
is_inside_filter_region( candidateR, candidateC ) { |
Type |
colStart = 0 |
|
colEnd = MiCols |
|
rowStart = 0 |
|
rowEnd = MiRows |
|
return (candidateC >= colStart && |
|
candidateC < colEnd && |
|
candidateR >= rowStart && |
|
candidateR < rowEnd) |
|
} |
|
Clamp MV row function
clamp_mv_row( mvec, border ) { |
Type |
bh4 = Num_4x4_Blocks_High[ MiSize ] |
|
mbToTopEdge = -((MiRow * MI_SIZE) * 8) |
|
mbToBottomEdge = ((MiRows - bh4 - MiRow) * MI_SIZE) * 8 |
|
return Clip3( mbToTopEdge - border, mbToBottomEdge + border, mvec ) |
|
} |
|
Clamp MV col function
clamp_mv_col( mvec, border ) { |
Type |
bw4 = Num_4x4_Blocks_Wide[ MiSize ] |
|
mbToLeftEdge = -((MiCol * MI_SIZE) * 8) |
|
mbToRightEdge = ((MiCols - bw4 - MiCol) * MI_SIZE) * 8 |
|
return Clip3( mbToLeftEdge - border, mbToRightEdge + border, mvec ) |
|
} |
|
Clear CDEF function
clear_cdef( r, c ) { |
Type |
cdef_idx[ r ][ c ] = -1 |
|
if ( use_128x128_superblock ) { |
|
cdefSize4 = Num_4x4_Blocks_Wide[ BLOCK_64X64 ] |
|
cdef_idx[ r ][ c + cdefSize4 ] = -1 |
|
cdef_idx[ r + cdefSize4][ c ] = -1 |
|
cdef_idx[ r + cdefSize4][ c + cdefSize4 ] = -1 |
|
} |
|
} |
|
Read CDEF syntax
read_cdef( ) { |
Type |
if ( skip || CodedLossless || !enable_cdef || allow_intrabc) { |
|
return |
|
} |
|
cdefSize4 = Num_4x4_Blocks_Wide[ BLOCK_64X64 ] |
|
cdefMask4 = ~(cdefSize4 - 1) |
|
r = MiRow & cdefMask4 |
|
c = MiCol & cdefMask4 |
|
if ( cdef_idx[ r ][ c ] == -1 ) { |
|
cdef_idx[ r ][ c ] |
L(cdef_bits) |
w4 = Num_4x4_Blocks_Wide[ MiSize ] |
|
h4 = Num_4x4_Blocks_High[ MiSize ] |
|
for ( i = r; i < r + h4 ; i += cdefSize4 ) { |
|
for ( j = c; j < c + w4 ; j += cdefSize4 ) { |
|
cdef_idx[ i ][ j ] = cdef_idx[ r ][ c ] |
|
} |
|
} |
|
} |
|
} |
|
Read loop restoration syntax
read_lr( r, c, bSize ) { |
Type |
if ( allow_intrabc ) { |
|
return |
|
} |
|
w = Num_4x4_Blocks_Wide[ bSize ] |
|
h = Num_4x4_Blocks_High[ bSize ] |
|
for ( plane = 0; plane < NumPlanes; plane++ ) { |
|
if ( FrameRestorationType[ plane ] != RESTORE_NONE ) { |
|
subX = (plane == 0) ? 0 : subsampling_x |
|
subY = (plane == 0) ? 0 : subsampling_y |
|
unitSize = LoopRestorationSize[ plane ] |
|
unitRows = count_units_in_frame( unitSize, Round2( FrameHeight, subY) ) |
|
unitCols = count_units_in_frame( unitSize, Round2( UpscaledWidth, subX) ) |
|
unitRowStart = ( r * ( MI_SIZE >> subY) + |
|
unitSize - 1 ) / unitSize |
|
unitRowEnd = Min( unitRows, ( (r + h) * ( MI_SIZE >> subY) + |
|
unitSize - 1 ) / unitSize) |
|
if ( use_superres ) { |
|
numerator = (MI_SIZE >> subX) * SuperresDenom |
|
denominator = unitSize * SUPERRES_NUM |
|
} else { |
|
numerator = MI_SIZE >> subX |
|
denominator = unitSize |
|
} |
|
unitColStart = ( c * numerator + denominator - 1 ) / denominator |
|
unitColEnd = Min( unitCols, ( (c + w) * numerator + |
|
denominator - 1 ) / denominator) |
|
for ( unitRow = unitRowStart; unitRow < unitRowEnd; unitRow++ ) { |
|
for ( unitCol = unitColStart; unitCol < unitColEnd; unitCol++ ) { |
|
read_lr_unit(plane, unitRow, unitCol) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
where count_units_in_frame is a function specified as:
count_units_in_frame(unitSize, frameSize) {
return Max((frameSize + (unitSize >> 1)) / unitSize, 1)
}
Read loop restoration unit syntax
read_lr_unit(plane, unitRow, unitCol) { |
Type |
if ( FrameRestorationType[ plane ] == RESTORE_WIENER ) { |
|
use_wiener |
S() |
restoration_type = use_wiener ? RESTORE_WIENER : RESTORE_NONE |
|
} else if ( FrameRestorationType[ plane ] == RESTORE_SGRPROJ ) { |
|
use_sgrproj |
S() |
restoration_type = use_sgrproj ? RESTORE_SGRPROJ : RESTORE_NONE |
|
} else { |
|
restoration_type |
S() |
} |
|
LrType[ plane ][ unitRow ][ unitCol ] = restoration_type |
|
if ( restoration_type == RESTORE_WIENER ) { |
|
for ( pass = 0; pass < 2; pass++ ) { |
|
if ( plane ) { |
|
firstCoeff = 1 |
|
LrWiener[ plane ] |
|
[ unitRow ][ unitCol ][ pass ][0] = 0 |
|
} else { |
|
firstCoeff = 0 |
|
} |
|
for ( j = firstCoeff; j < 3; j++ ) { |
|
min = Wiener_Taps_Min[ j ] |
|
max = Wiener_Taps_Max[ j ] |
|
k = Wiener_Taps_K[ j ] |
|
v = decode_signed_subexp_with_ref_bool( |
|
min, max + 1, k, RefLrWiener[ plane ][ pass ][ j ] ) |
|
LrWiener[ plane ] |
|
[ unitRow ][ unitCol ][ pass ][ j ] = v |
|
RefLrWiener[ plane ][ pass ][ j ] = v |
|
} |
|
} |
|
} else if ( restoration_type == RESTORE_SGRPROJ ) { |
|
lr_sgr_set |
L(SGRPROJ_PARAMS_BITS) |
LrSgrSet[ plane ][ unitRow ][ unitCol ] = lr_sgr_set |
|
for ( i = 0; i < 2; i++ ) { |
|
radius = Sgr_Params[ lr_sgr_set ][ i * 2 ] |
|
min = Sgrproj_Xqd_Min[i] |
|
max = Sgrproj_Xqd_Max[i] |
|
if ( radius ) { |
|
v = decode_signed_subexp_with_ref_bool( |
|
min, max + 1, SGRPROJ_PRJ_SUBEXP_K, |
|
RefSgrXqd[ plane ][ i ]) |
|
} else { |
|
v = 0 |
|
if ( i == 1 ) { |
|
v = Clip3( min, max, (1 << SGRPROJ_PRJ_BITS) - |
|
RefSgrXqd[ plane ][ 0 ] ) |
|
} |
|
} |
|
LrSgrXqd[ plane ][ unitRow ][ unitCol ][ i ] = v |
|
RefSgrXqd[ plane ][ i ] = v |
|
} |
|
} |
|
} |
|
where Wiener_Taps_Min, Wiener_Taps_Max, ,Wiener_Taps_K, Sgrproj_Xqd_Min, and
Sgrproj_Xqd_Max are constant lookup tables:
Wiener_Taps_Min[3] = { -5, -23, -17 }
Wiener_Taps_Max[3] = { 10, 8, 46 }
Wiener_Taps_K[3] = { 1, 2, 3 }
Sgrproj_Xqd_Min[2] = { -96, -32 }
Sgrproj_Xqd_Max[2] = { 31, 95 }
Sgr_Params is a constant lookup table defined in Box filter process and
decode_signed_subexp_with_ref_bool is a function specified as follows:
decode_signed_subexp_with_ref_bool( low, high, k, r ) { |
Type |
x = decode_unsigned_subexp_with_ref_bool(high - low, k, r - low) |
|
return x + low |
|
} |
|
|
|
decode_unsigned_subexp_with_ref_bool( mx, k, r ) { |
|
v = decode_subexp_bool( mx, k ) |
|
if ( (r << 1) <= mx ) { |
|
return inverse_recenter(r, v) |
|
} else { |
|
return mx - 1 - inverse_recenter(mx - 1 - r, v) |
|
} |
|
} |
|
|
|
decode_subexp_bool( numSyms, k ) { |
|
i = 0 |
|
mk = 0 |
|
while ( 1 ) { |
|
b2 = i ? k + i - 1 : k |
|
a = 1 << b2 |
|
if ( numSyms <= mk + 3 * a ) { |
|
subexp_unif_bools |
NS(numSyms - mk) |
return subexp_unif_bools + mk |
|
} else { |
|
subexp_more_bools |
L(1) |
if ( subexp_more_bools ) { |
|
i++ |
|
mk += a |
|
} else { |
|
subexp_bools |
L(b2) |
return subexp_bools + mk |
|
} |
|
} |
|
} |
|
} |
|
Note: The decode_signed_subexp_with_ref_bool function is the same as the
decode_signed_subexp_with_ref function except that the bits used to represent
the symbol are arithmetic coded instead of being read directly from the
bitstream.
Tile list OBU syntax
General tile list OBU syntax
tile_list_obu( ) { |
Type |
output_frame_width_in_tiles_minus_1 |
f(8) |
output_frame_height_in_tiles_minus_1 |
f(8) |
tile_count_minus_1 |
f(16) |
for ( tile = 0; tile <= tile_count_minus_1; tile++ ) |
|
tile_list_entry( ) |
|
} |
|
Tile list entry syntax
tile_list_entry( ) { |
Type |
anchor_frame_idx |
f(8) |
anchor_tile_row |
f(8) |
anchor_tile_col |
f(8) |
tile_data_size_minus_1 |
f(16) |
N = 8 * (tile_data_size_minus_1 + 1) |
|
coded_tile_data |
f(N) |
} |
|