This section presents the bitstream syntax in a tabular form. The meaning of each of the syntax elements is presented in [Section 6][].
open_bitstream_unit( sz ) {
obu_header()
sz -= 1 + obu_extension_flag
if ( obu_type == OBU_SEQUENCE_HEADER )
sequence_header_obu()
else if ( obu_type == OBU_TD )
temporal_delimiter_obu()
else if ( obu_type == OBU_FRAME_HEADER )
frame_header_obu( )
else if ( obu_type == OBU_TILE_GROUP )
tile_group_obu( sz )
else if ( obu_type == OBU_METADATA )
metadata_obu( sz )
else if ( obu_type == OBU_PADDING )
padding_obu()
else
reserved_obu( sz )
trailing_bits()
}
{:.syntax }
obu_header() {
@@obu_forbidden_bit f(1)
@@obu_type f(4)
@@obu_reserved_2bits f(2)
@@obu_extension_flag f(1)
if ( obu_extension_flag == 1 )
obu_extension_header()
}
{:.syntax }
obu_extension_header() {
@@temporal_id f(3)
@@enhancement_id f(2)
@@extension_header_reserved_3bits f(3)
}
{:.syntax }
trailing_bits( ) {
while ( get_position( ) & 7 )
@@zero_bit f(1)
}
{:.syntax }
reserved_obu( sz ) {
for ( i = 0; i < sz; i++ )
@@reserved_obu_payload_byte f(8)
}
{:.syntax }
sequence_header_obu( ) {
@@profile_low_bit f(1)
@@profile_high_bit f(1)
Profile = (profile_high_bit << 1) + profile_low_bit
@@level[ 0 ] f(4)
@@enhancement_layers_cnt f(2)
for ( i = 1; i <= enhancement_layers_cnt; i++ )
@@level[ i ] f(4)
@@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)
@@frame_id_numbers_present_flag f(1)
if ( frame_id_numbers_present_flag ) {
@@delta_frame_id_length_minus2 f(4)
@@frame_id_length_minus1 f(3)
}
color_config( )
@@timing_info_present_flag f(1)
if ( timing_info_present_flag ) {
timing_info( )
}
@@film_grain_params_present f(1)
}
{:.syntax }
color_config( ) {
@@high_bitdepth f(1)
if ( Profile >= 2 && high_bitdepth ) {
@@twelve_bit f(1)
BitDepth = twelve_bit ? 12 : 10
} else {
BitDepth = high_bitdepth ? 10 : 8
}
if ( Profile == 1 ) {
monochrome = 0
} else {
@@monochrome f(1)
}
NumPlanes = monochrome ? 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 ( monochrome ) {
color_range = 1
subsampling_x = 1
subsampling_y = 1
chroma_sample_position = CSP_UNKNOWN
} else if ( color_primaries == CP_BT_709 &&
transfer_characteristics == TC_SRGB &&
matrix_coefficients == MC_IDENTITY ) {
subsampling_x = 0
subsampling_y = 0
} else {
@@color_range f(1)
if ( Profile == 0 ) {
subsampling_x = 1
subsampling_y = 1
} else if ( 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)
}
{:.syntax }
timing_info( ) {
@@num_units_in_tick f(32)
@@time_scale f(32)
@@equal_picture_interval f(1)
if (equal_picture_interval)
@@num_ticks_per_picture_minus1 uvlc()
}
{:.syntax }
temporal_delimiter_obu( ) {
SeenFrameHeader = 0
}
{:.syntax }
Note: The temporal delimiter has an empty payload. {:.alert .alert-info }
padding_obu( ) {
@@obu_padding_length f(8)
for ( i = 0; i < obu_padding_length; i++ )
@@obu_padding_byte f(8)
}
{:.syntax }
metadata_obu( sz ) {
@@metadata_type f(16)
if ( metadata_type == METADATA_TYPE_PRIVATE_DATA )
metadata_private_data( sz − 2 )
else if ( metadata_type == METADATA_TYPE_HDR_CLL )
metadata_hdr_cll( sz − 2 )
else if ( metadata_type == METADATA_TYPE_HDR_MDCV )
metadata_hdr_mdcv( sz − 2 )
else if ( metadata_type == METADATA_TYPE_SCALABILITY )
metadata_scalability( sz − 2 )
}
{:.syntax }
metadata_private_data( sz ) {
for ( i = 0; i < sz; i++ )
@@metadata_private_data_payload_byte[ i ] f(8)
}
{:.syntax }
metadata_hdr_cll( sz ) {
@@max_cll f(16)
@@max_fall f(16)
}
{:.syntax }
metadata_hdr_mdcv( sz ) {
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)
}
{:.syntax }
metadata_scalability( sz ) {
@@scalability_mode_idc f(8)
if (scalability_mode_idc == SCALABILITY_SS)
scalability_structure( sz – 1 )
}
{:.syntax }
scalability_structure( sz ) {
@@enhancement_layers_cnt f(2)
@@enhancement_layer_dimensions_present_flag f(1)
@@enhancement_layer_description_present_flag f(1)
@@temporal_group_description_present_flag f(1)
@@scalability_structure_reserved_3bits f(3)
if ( enhancement_layer_dimensions_present_flag ) {
for ( i = 0; i <= enhancement_layers_cnt ; i++ ) {
@@enhancement_layer_max_width[ i ] f(16)
@@enhancement_layer_max_height[ i ] f(16)
}
}
if ( enhancement_layer_description_present_flag ) {
for ( i = 0; i <= enhancement_layers_cnt; i++ )
@@enhancement_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_switching_up_point_flag[ i ] f(1)
@@temporal_group_ref_cnt[ i ] f(2)
@@temporal_group_reserved_2bits[ i ] f(2)
for ( j = 0; j < temporal_group_ref_cnt[ i ]; j++ ) {
@@temporal_group_ref_pic_diff[ i ][ j ] f(8)
}
}
}
}
{:.syntax }
frame_header_obu( ) {
if ( SeenFrameHeader == 1 ) {
frame_header_copy()
} else {
SeenFrameHeader = 1
uncompressed_header( )
trailing_bits( )
if ( show_existing_frame ) {
decode_frame( )
SeenFrameHeader = 0
} else {
TileNum = 0
MaxTileSize = 0
SeenFrameHeader = 1
}
}
}
{:.syntax }
uncompressed_header( ) {
idLen = frame_id_length_minus1 + delta_frame_id_length_minus2 + 3
@@show_existing_frame f(1)
if ( show_existing_frame == 1 ) {
@@frame_to_show_map_idx f(3)
refresh_frame_flags = 0
for ( i = 0; i < FRAME_LF_COUNT; i++ )
loop_filter_level[ i ] = 0
if (frame_id_numbers_present_flag) {
@@display_frame_id f(idLen)
}
CurrentVideoFrame += 1
film_grain_params( )
return
}
@@frame_type f(2)
@@show_frame f(1)
@@error_resilient_mode f(1)
if ( frame_id_numbers_present_flag ) {
@@current_frame_id f(idLen)
}
@@frame_size_override_flag f(1)
FrameIsIntra = (frame_type == INTRA_ONLY_FRAME ||
frame_type == KEY_FRAME)
allow_intrabc = 0
force_integer_mv = 1
allow_high_precision_mv = 0
can_use_previous = 0
if ( frame_type == KEY_FRAME ) {
frame_size( )
render_size( )
@@use_128x128_superblock f(1)
@@allow_screen_content_tools f(1)
if (allow_screen_content_tools) {
@@allow_intrabc f(1)
}
refresh_frame_flags = 0xFF
CurrentVideoFrame = 0
if (allow_screen_content_tools) {
@@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 = 0
}
} else {
if ( frame_type == INTRA_ONLY_FRAME ) {
@@refresh_frame_flags f(8)
frame_size( )
render_size( )
@@use_128x128_superblock f(1)
@@allow_screen_content_tools f(1)
if (allow_screen_content_tools) {
@@allow_intrabc f(1)
}
} else {
if (frame_type == SWITCH_FRAME ) {
refresh_frame_flags = 0xFF
} else {
@@refresh_frame_flags f(8)
}
for( i = 0; i < REFS_PER_FRAME; i++ ) {
@@ref_frame_idx[ i ] f(3)
if (frame_id_numbers_present_flag) {
n = delta_frame_id_length_minus2 + 2
@@delta_frame_id_minus1 f(n)
DeltaFrameId = delta_frame_id_minus1 + 1
RefFrameId = ((current_frame_id -
DeltaFrameId ) % (1 << idLen))
}
}
if ( frame_size_override_flag && !error_resilient_mode ) {
frame_size_with_refs( )
} else {
frame_size( )
render_size( )
}
if ( seq_force_integer_mv == SELECT_INTEGER_MV )
@@force_integer_mv f(1)
else
force_integer_mv = seq_force_integer_mv
if ( force_integer_mv ) {
allow_high_precision_mv = 0
} else {
@@allow_high_precision_mv f(1)
}
read_interpolation_filter( )
if ( error_resilient_mode ) {
can_use_previous = 0
} else {
@@can_use_previous f(1)
}
}
}
if (show_frame == 0) {
@@frame_offset_update f(5)
OrderHint = CurrentVideoFrame + frame_offset_update
} else {
OrderHint = CurrentVideoFrame
CurrentVideoFrame += 1
}
if ( !FrameIsIntra ) {
for( i = 0; i < REFS_PER_FRAME; i++ ) {
refFrame = LAST_FRAME + i
hint = RefOrderHint[ ref_frame_idx[ i ] ]
OrderHints[ refFrame ] = hint
if (frame_type == SWITCH_FRAME ) {
RefFrameSignBias[ refFrame ] = 0
} else {
RefFrameSignBias[ refFrame ] = hint > OrderHint
}
}
}
if ( error_resilient_mode ) {
frame_parallel_decoding_mode = 1
} else {
@@frame_parallel_decoding_mode f(1)
}
if ( FrameIsIntra || error_resilient_mode ) {
setup_past_independence ( )
} else {
load_cdfs( ref_frame_idx[ 0 ] )
load_previous( )
}
tile_info( )
loop_filter_params( )
quantization_params( )
segmentation_params( )
delta_q_params( )
delta_lf_params( )
AllLossless = 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 ] )
AllLossless = 0
if ( using_qmatrix ) {
if ( LosslessArray[ segmentId ] ) {
qmLevel = 15
} else {
qmLevel = min_qmlevel + ( base_q_idx * ( max_qmlevel - min_qmlevel + 1 ) ) / 256
}
SegQMLevel[ segmentId ] = qmLevel
}
}
cdef_params( )
lr_params( )
read_tx_mode( )
frame_reference_mode( )
skip_mode_params( )
@@reduced_tx_set f(1)
global_motion_params( )
if ( show_frame ) {
film_grain_params( )
}
}
{:.syntax }
frame_size( ) {
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
}
compute_image_size( )
superres_params( )
}
{:.syntax }
render_size( ) {
@@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 = FrameWidth
RenderHeight = FrameHeight
}
}
{:.syntax }
frame_size_with_refs( ) {
for ( i = 0; i < REFS_PER_FRAME; i++ ) {
@@found_ref f(1)
if ( found_ref == 1 ) {
FrameWidth = RefFrameWidth[ ref_frame_idx[ i ] ]
FrameHeight = RefFrameHeight[ ref_frame_idx[ i ] ]
RenderWidth = FrameWidth
RenderHeight = FrameHeight
break
}
}
if ( found_ref == 0 ) {
frame_size( )
render_size( )
} else {
compute_image_size( )
superres_params( )
}
}
{:.syntax }
superres_params() {
@@use_superres f(1)
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
}
{:.syntax }
compute_image_size( ) {
MiCols = 2 * ( ( FrameWidth + 7 ) >> 3 )
MiRows = 2 * ( ( FrameHeight + 7 ) >> 3 )
}
{:.syntax }
read_interpolation_filter( ) {
@@is_filter_switchable f(1)
if ( is_filter_switchable == 1 ) {
interpolation_filter = SWITCHABLE
} else {
@@interpolation_filter f(2)
}
}
{:.syntax }
loop_filter_params( ) {
if ( allow_intrabc ) {
loop_filter_level[ 0 ] = 0
loop_filter_level[ 1 ] = 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(6)
}
for ( i = 0; i < 2; i++ ) {
@@update_mode_delta f(1)
if ( update_mode_delta == 1 )
@@loop_filter_mode_deltas[ i ] su(6)
}
}
}
}
{:.syntax }
quantization_params( ) {
@@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
DeltaQUDc = 0
DeltaQVAc = 0
DeltaQVAc = 0
}
@@using_qmatrix f(1)
if (using_qmatrix) {
@@min_qmlevel f(4)
@@max_qmlevel f(4)
}
}
{:.syntax }
read_delta_q( ) {
@@delta_coded f(1)
if ( delta_coded ) {
@@delta_q su(6)
} else {
delta_q = 0
}
return delta_q
}
{:.syntax }
segmentation_params( ) {
@@segmentation_enabled f(1)
SegIdPreSkip = 0
if ( segmentation_enabled == 1 ) {
if ( FrameIsIntra || error_resilient_mode ) {
segmentation_update_map = 1
segmentation_temporal_update = 0
} 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
if ( feature_enabled == 1 ) {
if ( j >= SEG_LVL_REF_FRAME ) {
SegIdPreSkip = 1
}
LastActiveSegId = i
bitsToRead = Segmentation_Feature_Bits[ j ]
limit = Segmentation_Feature_Max[ j ]
if ( Segmentation_Feature_Signed[ j ] == 1 ) {
feature_value su(bitsToRead)
clippedValue = Clip3( -limit, limit, feature_value)
} else {
feature_value f(bitsToRead)
clippedValue = Clip3( 0, limit, feature_value)
}
}
FeatureData[ i ][ j ] = clippedValue
}
}
}
}
}
{:.syntax }
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 ( ) {
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
minLog2TileCols = tile_log2(MAX_TILE_WIDTH_SB, sbCols)
maxLog2TileCols = tile_log2(1, Min(sbCols, MAX_TILE_COLS))
maxLog2TileRows = tile_log2(1, Min(sbRows, MAX_TILE_ROWS))
minLog2Tiles = Max(minLog2TileCols,
tile_log2(MAX_TILE_AREA_SB, 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
}
sizeSb = (sbCols + (1 << TileColsLog2) - 1) >> TileColsLog2
i = 0
for (startSb = 0; startSb < sbCols; startSb += sizeSb) {
MiColStarts[ i ] = startSb << sbShift
i += 1
}
MiColStarts[i] = MiCols
TileCols = i
minLog2TileRows = Max( minLog2Tiles - TileColsLog2, 0)
maxTileHeightSb = sbRows >> minLog2TileRows
TileRowsLog2 = minLog2TileRows
while ( TileRowsLog2 < maxLog2TileRows ) {
@@increment_tile_rows_log2 f(1)
if ( increment_tile_rows_log2 == 1 )
TileRowsLog2++
else
break
}
sizeSb = (sbCols + (1 << TileRowsLog2) - 1) >> TileRowsLog2
i = 0
for (startSb = 0; startSb < sbRows; startSb += sizeSb) {
MiRowStarts[ i ] = startSb << sbShift
i += 1
}
MiRowStarts[i] = MiRows
TileRows = i
} else {
widestTileSb = 0
startSb = 0
for ( i = 0; startSb < sbCols && i < MAX_TILE_COLS; i++ ) {
MiColStarts[ i ] = startSb << sbShift
maxWidth = Min(sbCols - startSb, MAX_TILE_WIDTH_SB)
sizeSb = decode_uniform(maxWidth) + 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 < MAX_TILE_ROWS; i++ ) {
MiRowStarts[ i ] = startSb << sbShift
maxHeight = Min(sbRows - startSb, maxTileHeightSb)
sizeSb = decode_uniform(maxHeight) + 1
startSb += sizeSb
}
MiRowStarts[ i ] = MiRows
TileRows = i
TileRowsLog2 = tile_log2(1, TileRows)
}
startMi = 0
maxTileHeightMi = maxTileHeightSb << sbShift
for (i = 0; i < TileRows; i++) {
if (MiRowStarts[i+1] - startMi > maxTileHeightMi) {
AllowDependentTileRow[i] = 0
startMi = MiRowStarts[i+1]
} else {
AllowDependentTileRow[i] = 1
}
}
AllowDependentTileRow[ 0 ] = 0
if ( TileRowsLog2 > 0 )
@@dependent_tiles f(1)
else
dependent_tiles = 0
if ( TileColsLog2 > 0 )
@@loop_filter_across_tiles_v f(1)
else
loop_filter_across_tiles_v = 0
if ( TileRowsLog2 > 0 )
@@loop_filter_across_tiles_h f(1)
else
loop_filter_across_tiles_h = 0
@@tile_size_bytes_minus_1 f(2)
TileSizeBytes = tile_size_bytes_minus_1 + 1
}
{:.syntax }
tile_log2 returns the smallest value for k such that blkSize << k is greater than or equal to target.
tile_log2( blkSize, target ) {
for (k = 0; (blkSize << k) < target; k++) {
}
return k
}
{:.syntax }
delta_q_params( ) {
segmentQuantizerActive = 0
for ( i = 0; i < MAX_SEGMENTS; i++ ) {
if ( seg_feature_active_idx( i, SEG_LVL_ALT_Q ) ) {
segmentQuantizerActive = 1
}
}
delta_q_res = 0
delta_q_present = 0
if ( segmentQuantizerActive == 0 && base_q_idx > 0 ) {
@@delta_q_present f(1)
}
if ( delta_q_present ) {
@@delta_q_res f(2)
}
}
{:.syntax }
delta_lf_params( ) {
delta_lf_present = 0
delta_lf_res = 0
delta_lf_multi = 0
if ( delta_q_present ) {
@@delta_lf_present f(1)
if ( delta_lf_present ) {
@@delta_lf_res f(2)
@@delta_lf_multi f(1)
}
}
}
{:.syntax }
cdef_params( ) {
if ( allow_intrabc || AllLossless ) {
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
}
}
}
{:.syntax }
lr_params( ) {
if ( allow_intrabc ) {
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 ) {
@@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
}
}
{:.syntax }
where Remap_Lr_Type is a constant lookup table specified as:
Remap_Lr_Type[4] = {
RESTORE_NONE, RESTORE_SWITCHABLE, RESTORE_WIENER, RESTORE_SGRPROJ
}
read_tx_mode( ) {
if ( AllLossless == 1 ) {
TxMode = ONLY_4X4
} else {
@@tx_mode_select f(1)
if ( tx_mode_select ) {
TxMode = TX_MODE_SELECT
} else {
TxMode = TX_MODE_LARGEST
}
}
}
{:.syntax }
skip_mode_params( ) {
if ( FrameIsIntra || !reference_select ) {
skipModeAllowed = 0
} else {
forwardIdx = -1
backwardIdx = -1
for( i = 0; i < REFS_PER_FRAME; i++ ) {
refHint = RefOrderHint[ ref_frame_idx[ i ] ]
if ( refHint < OrderHint ) {
if ( forwardIdx < 0 || refHint > forwardHint ) {
forwardIdx = i
forwardHint = refHint
}
} else if ( refHint > OrderHint ) {
if ( backwardIdx < 0 || refHint < backwardHint ) {
backwardIdx = i
backwardHint = refHint
}
}
}
if ( forwardIdx < 0 ) {
skipModeAllowed = 0
} else if ( backwardIdx >= 0 ) {
skipModeAllowed = 1
ForwardFrame = LAST_FRAME + forwardIdx
BackwardFrame = LAST_FRAME + backwardIdx
} else {
for( i = 0; i < REFS_PER_FRAME; i++ ) {
refHint = RefOrderHint[ ref_frame_idx[ i ] ]
if ( refHint < forwardHint ) {
if ( backwardIdx < 0 || refHint > backwardHint ) {
backwardIdx = i
backwardHint = refHint
}
}
}
if ( backwardIdx < 0 ) {
skipModeAllowed = 0
} else {
skipModeAllowed = 1
ForwardFrame = LAST_FRAME + Min(forwardIdx, backwardIdx)
BackwardFrame = LAST_FRAME + Max(forwardIdx, backwardIdx)
}
}
}
if ( skipModeAllowed ) {
@@skip_mode_present f(1)
} else {
skip_mode_present = 0
}
}
{:.syntax }
frame_reference_mode( ) {
compoundReferenceAllowed = 0
if ( !FrameIsIntra ) {
bufIdx = ref_frame_idx[0]
refOffset0 = RefOrderHint[bufIdx]
for (ref = LAST_FRAME + 1; ref <= ALTREF_FRAME; ref++) {
bufIdx = ref_frame_idx[ref - LAST_FRAME]
refOffset = RefOrderHint[bufIdx]
if (refOffset != refOffset0) {
compoundReferenceAllowed = 1
break
}
}
}
if ( compoundReferenceAllowed ) {
@@reference_select f(1)
} else {
reference_select = 0
}
if ( FrameIsIntra ) {
allow_interintra_compound = 0
} else {
@@allow_interintra_compound f(1)
}
if ( FrameIsIntra || !reference_select) {
allow_masked_compound = 0
} else {
@@allow_masked_compound f(1)
}
}
{:.syntax }
global_motion_params( ) {
if ( FrameIsIntra || error_resilient_mode || !can_use_previous) {
for (ref = LAST_FRAME; ref <= ALTREF_FRAME; ref++) {
gm_type[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
}
gm_type[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)
}
}
}
{:.syntax }
read_global_param( type, ref, idx ) {
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 = (i % 3) == 2 ? (1 << WARPEDMODEL_PREC_BITS) : 0
sub = (i % 3) == 2 ? (1 << precDiff) : 0
mx = (1 << absBits)
r = (gm_params[ref][idx] >> precDiff) - sub
gm_params[ref][idx] = (decode_signed_subexp_with_ref( -mx, mx + 1, r ) << precDiff) + round
}
{:.syntax }
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 Zero MV process. {:.alert .alert-info }
decode_signed_subexp_with_ref( low, high, r ) {
x = decode_unsigned_subexp_with_ref(high - low, r - low)
return x + low
}
{:.syntax }
decode_unsigned_subexp_with_ref( mx, r ) {
v = decode_subexp( mx )
if ((r << 1) <= mx) {
return inverse_recenter(r, v)
} else {
return mx - 1 - inverse_recenter(mx - 1 - r, v)
}
}
{:.syntax }
decode_subexp( numSyms ) {
i = 0
mk = 0
k = 3
while (1) {
b2 = i ? k + i - 1 : k
a = 1 << b2
if (numSyms <= mk + 3 * a) {
return decode_uniform(numSyms - mk) + mk
} else {
@@subexp_more_bits f(1)
if (subexp_more_bits) {
i++
mk += a
} else {
@@subexp_bits f(b2)
return subexp_bits + mk
}
}
}
}
{:.syntax }
decode_uniform( n ) {
w = floor(log2(n)) + 1
m = (1 << w) - n
@@v f( w - 1 )
if (v < m)
return v
@@extra_bit f( 1 )
return (v << 1) - m + extra_bit
}
{:.syntax }
inverse_recenter( r, v ) {
if (v > 2 * r)
return v
else if (v & 1)
return r - ((v + 1) >> 1)
else
return r + (v >> 1)
}
{:.syntax }
inv_recenter_nonneg( v, m ) {
if ( v > 2 * m )
return v
if ( v & 1 )
return m - ((v + 1) >> 1)
return m + (v >> 1)
}
{:.syntax }
film_grain_params( ) {
if ( !film_grain_params_present ) {
return
}
@@apply_grain f(1)
if ( !apply_grain ) {
return
}
@@grain_seed f(16)
@@update_grain f(1)
if ( !update_grain ) {
return
}
@@num_y_points f(4)
for ( i = 0; i < num_y_points; i++ ) {
@@scaling_points_y[ i ][ 0 ] f(8)
@@scaling_points_y[ i ][ 1 ] f(8)
}
@@chroma_scaling_from_luma f(1)
if ( !chroma_scaling_from_luma ) {
@@num_cb_points f(4)
for ( i = 0; i < num_cb_points; i++ ) {
@@scaling_points_cb[ i ][ 0 ] f(8)
@@scaling_points_cb[ i ][ 1 ] f(8)
}
@@num_cr_points f(4)
for ( i = 0; i < num_cr_points; i++ ) {
@@scaling_points_cr[ i ][ 0 ] f(8)
@@scaling_points_cr[ i ][ 1 ] f(8)
}
} else {
num_cb_points = 0
num_cr_points = 0
}
@@grain_scaling_minus_8 f(2)
@@ar_coeff_lag f(2)
numPosLuma = 2 * ar_coeff_lag * ( ar_coeff_lag + 1 )
numPosChroma = numPosLuma + 1
if (num_y_points) {
for ( i = 0; i < numPosLuma; i++ )
@ar_coeffs_y_plus_128[ i ] f(8)
}
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)
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)
}
{:.syntax }
tile_group_obu( sz ) {
NumTiles = TileCols * TileRows
startBitPos = get_position( )
tileBits = TileColsLog2 + TileRowsLog2
@@tg_start f(tileBits)
@@tg_end f(tileBits)
trailing_bits( )
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 ) {
tile_size = sz
} else {
@@tile_size le(TileSizeBytes)
sz -= tile_size + TileSizeBytes
}
MiRowStart = MiRowStarts[ TileRow ]
MiRowEnd = MiRowStarts[ TileRow + 1 ]
MiColStart = MiColStarts[ TileCol ]
MiColEnd = MiColStarts[ TileCol + 1 ]
CurrentQIndex = base_q_idx
init_bool( tile_size )
decode_tile( )
exit_bool( )
}
if (tg_end == NumTiles - 1) {
if ( !error_resilient_mode && !frame_parallel_decoding_mode ) {
update_cdf( )
}
decode_frame( )
SeenFrameHeader = 0
}
}
{:.syntax }
decode_tile( ) {
if ( !dependent_tiles ||
(TileCol == 0 && !AllowDependentTileRow[ TileRow ]) ) {
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( c < ( MiColEnd - 1 ) )
decode_lr( r, c, sbSize )
decode_partition( r, c, sbSize )
}
}
}
{:.syntax }
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( notLastColumn ) {
sbSize = use_128x128_superblock ? 128 : 64
for ( plane = 0; plane < NumPlanes; plane++ ) {
subX = (plane > 0) ? subsampling_x : 0
subY = (plane > 0) ? subsampling_y : 0
for ( y = -1; y <= ( sbSize >> ( MI_SIZE_LOG2 + subY ) ); y++ )
for ( x = -1; x <= ( sbSize >> ( MI_SIZE_LOG2 + subX ) ); x++ ) {
BlockDecoded[ plane ][ y ][ x ] = ( y < 0 || x < 0 )
}
BlockDecoded[ plane ][ -1 ][ sbSize >> ( MI_SIZE_LOG2 + subX ) ] = notLastColumn
BlockDecoded[ plane ][ sbSize >> ( MI_SIZE_LOG2 + subY ) ][ -1 ] = 0
}
}
{:.syntax }
decode_partition( r, c, bSize ) {
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 )
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 )
decode_block( r, c + quarterBlock4x4 * 3, subSize )
}
}
{:.syntax }
decode_block( r, c, subSize ) {
MiRow = r
MiCol = c
MiSize = subSize
AvailU = is_inside( r - 1, c )
AvailL = is_inside( r, c - 1 )
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
mode_info( )
if ( skip )
reset_block_context( bw4, bh4 )
for ( y = 0; y < bh4; y++ ) {
for ( x = 0; x < bw4; x++ ) {
YModes [ r + y ][ c + x ] = YMode
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 < 2; refList++ ) {
Mvs[ r + y ][ c + x ][ refList ] = Mv[ refList ]
PredMvs[ r + y ][ c + x ][ refList ] = PredMv[ refList ]
}
}
}
}
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
TileNums[ r + y ][ c + x ] = TileNum
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 ]
}
}
}
{:.syntax }
where reset_block_context( ) is specified as:
reset_block_context( bw4, bh4 ) {
mask = use_128x128_superblock ? 255 : 127
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 & mask ] = 0
LeftDcContext[ plane ][ i & mask ] = 0
}
}
}
mode_info( ) {
if ( FrameIsIntra )
intra_frame_mode_info( )
else
inter_frame_mode_info( )
}
{:.syntax }
intra_frame_mode_info( ) {
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
read_inter_tx_size( )
YMode = DC_PRED
UVMode = DC_PRED
PaletteSizeY = 0
PaletteSizeUV = 0
interp_filter[ 0 ] = BILINEAR
interp_filter[ 1 ] = BILINEAR
find_mv_stack( 0 )
assign_mv( 0 )
} else {
is_inter = 0
read_tx_size( 1 )
@@intra_frame_y_mode S
YMode = intra_frame_y_mode
if (HasChroma) {
@@uv_mode S
UVMode = uv_mode
if (UVMode == UV_CFL_PRED) {
read_cfl_alphas( )
}
}
intra_angle_info( )
PaletteSizeY = 0
PaletteSizeUV = 0
if ( Block_Width[ MiSize ] <= 64 &&
Block_Height[ MiSize ] <= 64 &&
allow_screen_content_tools ) {
palette_mode_info( )
}
use_filter_intra = 0
filter_intra_mode_info( )
}
}
{:.syntax }
intra_segment_id( ) {
if ( segmentation_enabled && segmentation_update_map )
read_segment_id( )
else
segment_id = 0
Lossless = LosslessArray[ segment_id ]
}
{:.syntax }
read_segment_id( ) {
if ( AvailU && AvailL )
prevUL = PrevSegmentIds[ MiRow - 1 ][ MiCol - 1 ]
else
prevUL = -1
if ( AvailU )
prevU = PrevSegmentIds[ MiRow - 1 ][ MiCol ]
else
prevU = -1
if ( AvailL )
prevL = PrevSegmentIds[ 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 )
}
}
{:.syntax }
where neg_deinterleave is a function defined as:
neg_deinterleave(int diff, int ref, int 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)
}
}
read_skip_mode() {
if ( seg_feature_active( SEG_LVL_SKIP ) ||
!skip_mode_present ||
Block_Width[ MiSize ] < 8 ||
Block_Height[ MiSize ] < 8 ) {
skip_mode = 0
} else {
@@skip_mode S
}
}
{:.syntax }
read_skip() {
if ( seg_feature_active( SEG_LVL_SKIP ) ) {
skip = 1
} else {
@@skip S
}
}
{:.syntax }
read_delta_qindex( ) {
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))
}
}
}
{:.syntax }
read_delta_lf( ) {
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64
if ( MiSize == sbSize && skip )
return
if ( ReadDeltas && delta_lf_present ) {
for ( i = 0; i < ( delta_lf_multi ? FRAME_LF_COUNT : 1 ); 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( 0, MAX_LOOP_FILTER, DeltaLF[ i ] +
(reducedDeltaLfLevel << delta_lf_res) )
}
}
}
}
{:.syntax }
seg_feature_active_idx( idx, feature ) {
return segmentation_enabled && FeatureEnabled[ idx ][ feature ]
}
seg_feature_active( feature ) {
return seg_feature_active_idx( segment_id, feature )
}
{:.syntax }
read_tx_size( allowSelect ) {
largestTxSize = Tx_Mode_To_Biggest_Tx_Size[ TxMode ]
maxTxSize = Max_Tx_Size[ MiSize ]
maxRectTxSize = Max_Tx_Size_Rect[ MiSize ]
maxTxDepth = Max_Tx_Depth[ MiSize ]
if ( MiSize > BLOCK_4X4 ) {
if ( allowSelect && TxMode == TX_MODE_SELECT ) {
@@tx_depth S
TxSize = maxRectTxSize
for ( i = 0; i < tx_depth; i++ )
TxSize = Split_Tx_Size[ TxSize ]
} else {
if ( MiSize == BLOCK_4X4 )
TxSize = Min( maxTxSize, largestTxSize )
else if ( Tx_Size_Sqr[ maxRectTxSize ] <= largestTxSize )
TxSize = maxRectTxSize
else
TxSize = largestTxSize
}
} else {
TxSize = maxRectTxSize
}
}
{:.syntax }
The Max_Tx_Depth table specifies the maximum transform depth which can be encoded 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,
}
The Tx_Mode_To_Biggest_Tx_Size table is defined as:
Tx_Mode_To_Biggest_Tx_Size[ TX_MODES ] = {
TX_4X4,
TX_64X64,
TX_64X64
}
read_inter_tx_size is used in inter frames to read the transform sizes.
Either a single transform size is used for the whole block, or a tree of transform sizes is generated.
As the maximum transform size is 32 samples, a block may require several transform trees to be coded.
read_inter_tx_size( ) {
bw4 = Num_4x4_Blocks_Wide[ MiSize ]
bh4 = Num_4x4_Blocks_High[ MiSize ]
if (TxMode == TX_MODE_SELECT &&
MiSize > BLOCK_4X4 && is_inter &&
!skip && !Lossless) {
MinTxSize = TX_32X32
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
MinTxSize = TxSize
}
}
{:.syntax }
read_var_tx_size is used to read a transform size tree.
The original transform size may be square or rectangular, but only square transform sizes are produced if split.
read_var_tx_size( row, col, txSz, depth) {
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 ]
step4 = Tx_Width[ subTxSz ] / MI_SIZE
for (i = 0; i < h4; i += step4)
for (j = 0; j < w4; j += step4)
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
MinTxSize = ( Tx_Width[ MinTxSize ] * Tx_Height[ MinTxSize ] <=
Tx_Width[ txSz ] * Tx_Height[ txSz ] ) ? MinTxSize : txSz
TxSize = txSz
}
}
{:.syntax }
inter_frame_mode_info( ) {
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( )
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( )
read_inter_tx_size( )
if ( is_inter )
inter_block_mode_info( )
else
intra_block_mode_info( )
}
{:.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 ) {
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
}
}
{:.syntax }
read_is_inter( ) {
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 {
@@is_inter S
}
}
{:.syntax }
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( ) {
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
}
{:.syntax }
intra_block_mode_info( ) {
RefFrame[ 0 ] = INTRA_FRAME
RefFrame[ 1 ] = NONE
@@y_mode S
YMode = y_mode
if (HasChroma) {
@@uv_mode S
UVMode = uv_mode
if (UVMode == UV_CFL_PRED) {
read_cfl_alphas( )
}
}
intra_angle_info( )
PaletteSizeY = 0
PaletteSizeUV = 0
if ( Block_Width[ MiSize ] <= 64 &&
Block_Height[ MiSize ] <= 64 &&
allow_screen_content_tools )
palette_mode_info( )
use_filter_intra = 0
filter_intra_mode_info( )
}
{:.syntax }
inter_block_mode_info( ) {
PaletteSizeY = 0
PaletteSizeUV = 0
use_filter_intra = 0
read_ref_frames( )
for ( j = 0; j < 2; j++ ) {
if ( RefFrame[ j ] > INTRA_FRAME ) {
find_mv_stack( j )
find_mv_list( j )
}
}
isCompound = RefFrame[ 1 ] > INTRA_FRAME
if ( isCompound ) {
compound_context( )
find_mv_stack( -1 )
}
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 < 2; dir++ ) {
if ( needs_interp_filter( ) ) {
@@interp_filter[ dir ] S
} else {
interp_filter[ dir ] = EIGHTTAP
}
}
} else {
for ( dir = 0; dir < 2; dir++ )
interp_filter[ dir ] = interpolation_filter
}
}
{:.syntax }
The function has_nearmv is defined as:
has_nearmv( ) {
return (YMode == NEARMV || YMode == NEAR_NEARMV
|| YMode == NEAR_NEWMV || YMode == NEW_NEARMV)
}
{:.syntax }
The function needs_interp_filter is defined as:
needs_interp_filter( ) {
if (YMode == GLOBALMV) {
return gm_type[ RefFrame[ 0 ] ] <= TRANSLATION
} else if (YMode == GLOBAL_GLOBALMV ) {
return gm_type[ RefFrame[ 0 ] ] <= TRANSLATION || gm_type[ RefFrame[ 1 ] ] <= TRANSLATION
} else {
return 1
}
}
{:.syntax }
filter_intra_mode_info( ) {
if ( YMode == DC_PRED && PaletteSizeY == 0 &&
Max( Tx_Width[ TxSize ], Tx_Height[ TxSize ] ) <= 32 ) {
@@use_filter_intra S
if ( use_filter_intra ) {
@@filter_intra_mode S
}
}
}
{:.syntax }
read_ref_frames( ) {
if ( skip_mode ) {
RefFrame[ 0 ] = ForwardFrame
RefFrame[ 1 ] = BackwardFrame
} 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 {
if ( reference_select )
@@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 ?
LAST_FRAME : LAST2_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
}
}
}
{:.syntax }
assign_mv( isCompound ) {
bw = Block_Width[ MiSize ]
bh = Block_Height[ MiSize ]
Mv[ 1 ] = ZeroMvs[ 1 ]
PredMv[ 1 ] = ZeroMvs[ 1 ]
for ( i = 0; i < 1 + isCompound; i++ ) {
if ( use_intrabc ) {
compMode = NEWMV
} else {
compMode = get_mode( i )
}
if ( use_intrabc ) {
PredMv[ 0 ] = RefListMv[ i ][ 0 ]
if ( PredMv[ 0 ][ 0 ] == 0 && PredMv[ 0 ][ 1 ] == 0 ) {
PredMv[ 0 ] = RefListMv[ i ][ 1 ]
}
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 ] = (-sbSize - INTRABC_DELAY_PIXELS) * 8
} else {
PredMv[ 0 ][ 0 ] = -sbSize * 8
PredMv[ 0 ][ 1 ] = 0
}
}
}
else if ( compMode == GLOBALMV ) {
PredMv[ i ] = ZeroMvs[ i ]
} else {
pos = ( compMode == NEARESTMV ) ? 0 : RefMvIdx
useStack = pos < NumMvFound
if ( compMode == NEWMV && NumMvFound <= 1)
useStack = 0
if ( useStack ) {
PredMv[ i ] = RefStackMv[ pos ][ i ]
if ( YMode == NEARMV && pos > 1 ) {
// No clamping
} else {
PredMv[ i ][ 0 ] = clamp_mv_row( PredMv[ i ][ 0 ], MV_BORDER + bh * 8)
PredMv[ i ][ 1 ] = clamp_mv_col( PredMv[ i ][ 1 ], MV_BORDER + bw * 8)
}
} else {
PredMv[ i ] = RefListMv[ i ][ pos ]
}
}
if ( compMode == NEWMV ) {
read_mv( i )
}
}
}
{:.syntax }
read_motion_mode( isCompound ) {
if ( skip_mode ) {
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 (gm_type[ RefFrame[ 0 ] ] > TRANSLATION) {
motion_mode = SIMPLE
return
}
}
if ( isCompound || !has_overlappable_candidates( ) ) {
motion_mode = SIMPLE
return
}
find_warp_samples()
if ( force_integer_mv || NumSamples == 0) {
@@use_obmc S
motion_mode = use_obmc ? OBMC : SIMPLE
} else {
@@motion_mode S
}
}
{:.syntax }
read_interintra_mode( isCompound ) {
if ( !skip_mode && allow_interintra_compound && !isCompound &&
MiSize >= BLOCK_8X8 && MiSize <= BLOCK_32X32) {
@@interintra S
if (interintra) {
@@interintra_mode S
RefFrame[1] = INTRA_FRAME
AngleDeltaY = 0
AngleDeltaUV = 0
n = Wedge_Bits[ MiSize ]
if ( n > 0 ) {
@@wedge_interintra S
if (wedge_interintra) {
@@wedge_index L(n)
wedge_sign = 0
}
} else {
wedge_interintra = 0
}
}
} else {
interintra = 0
}
}
{:.syntax }
read_compound_type( isCompound ) {
comp_group_idx = 0
compound_idx = 1
if ( skip_mode ) {
compound_type = COMPOUND_DISTANCE
return
}
if ( isCompound ) {
if ( allow_masked_compound && Wedge_Bits[ MiSize ] > 0 ) {
@@comp_group_idx S
} else {
comp_group_idx = 0
}
if ( comp_group_idx == 0 ) {
@@compound_idx S
compound_type = compound_idx ? COMPOUND_DISTANCE :
COMPOUND_AVERAGE
return
}
}
if ( allow_masked_compound && isCompound &&
motion_mode == SIMPLE && MiSize >= BLOCK_8X8) {
n = Wedge_Bits[ MiSize ]
if ( n == 0 ) {
compound_type = COMPOUND_SEG
} else {
@@compound_type S
}
if ( compound_type == COMPOUND_WEDGE ) {
@@wedge_index L(n)
@@wedge_sign L(1)
} else if ( compound_type == COMPOUND_SEG ) {
@@mask_type L(1)
}
} else {
if ( interintra ) {
compound_type = wedge_interintra ? COMPOUND_WEDGE : COMPOUND_INTRA
} else {
compound_type = COMPOUND_AVERAGE
}
}
}
{:.syntax }
get_mode( refList ) {
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
}
{:.syntax }
read_mv( ref ) {
diffMv[ 0 ] = 0
diffMv[ 1 ] = 0
if ( use_intrabc ) {
MvCtx = MV_INTRABC_CONTEXT
} else {
if ( RefMvIdx < NumMvFound &&
WeightStack[ RefMvIdx ] >= REF_CAT_LEVEL ) {
MvCtx = MvCtxStack[ RefMvIdx ][ ref ]
} 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 ]
}
{:.syntax }
read_mv_component( comp ) {
@@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
}
{:.syntax }
residual( ) {
palette_tokens( )
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 ]
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 = (miColChunk >> subX) * MI_SIZE
baseY = (miRowChunk >> subY) * MI_SIZE
candRow = (MiRow >> subY) << subY
candCol = (MiCol >> subX) << subX
IsInterIntra = ( is_inter && RefFrame[ 1 ] == INTRA_FRAME )
IsCFL = (plane > 0 && !is_inter && UVMode == UV_CFL_PRED)
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
} else {
mode = DC_PRED
}
if ( IsInterIntra || IsCFL ) {
predict_intra( plane, baseX, baseY,
AvailL,
AvailU,
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[ miSizeChunk ] >> subX
predH = Block_Height[ miSizeChunk ] >> subY
someUseIntra = 0
for( r = 0; r < num4x4H; r++ )
for( c = 0; c < num4x4W; 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++
}
}
if ( is_inter ) {
transform_tree( plane, 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 ),
y + ( chunkY << 4 ) )
}
}
}
}
}
{:.syntax }
transform_block(plane, baseX, baseY, txSz, x, y) {
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 if ( IsCFL ) {
predict_chroma_from_luma( plane, startX, startY, txSz )
} else {
mode = ( plane == 0 ) ? YMode : UVMode
log2W = Tx_Width_Log2[ txSz ]
log2H = Tx_Height_Log2[ txSz ]
predict_intra( plane, startX, startY,
AvailL || x > 0,
AvailU || y > 0,
BlockDecoded[ plane ]
[ ( subBlockMiRow >> subY ) + y - 1 ]
[ ( subBlockMiCol >> subX ) + x + stepX ],
BlockDecoded[ plane ]
[ ( subBlockMiRow >> subY ) + y + stepY ]
[ ( subBlockMiCol >> subX ) + x - 1 ],
mode,
log2W, log2H )
}
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 ) + y + i ]
[ ( subBlockMiCol >> subX ) + x + j ] = 1
}
}
}
{:.syntax }
transform_tree is used to read a number of transform blocks arranged in a transform tree.
transform_tree( plane, startX, startY, w, h ) {
subX = (plane > 0) ? subsampling_x : 0
subY = (plane > 0) ? subsampling_y : 0
maxX = (MiCols * MI_SIZE) >> subX
maxY = (MiRows * MI_SIZE) >> subY
if ( startX >= maxX || startY >= maxY ) {
return
}
row = ( startY << subY ) >> MI_SIZE_LOG2
col = ( startX << subX ) >> MI_SIZE_LOG2
lumaTxSz = InterTxSizes[ row ][ col ]
lumaW = Tx_Width[ lumaTxSz ]
lumaH = Tx_Height[ lumaTxSz ]
uses64 = w >= 64 || h >= 64
isSubsampled = subX || subY
if ( (isSubsampled && !uses64) ||
(!isSubsampled && w <= lumaW && h <= lumaH) ) {
txSz = find_tx_size( w, h )
transform_block( plane, startX, startY, txSz, 0, 0 )
} else {
if ( w > h ) {
transform_tree( plane, startX, startY, w/2, h )
transform_tree( plane, startX + w / 2, startY, w/2, h )
} else if ( w < h ) {
transform_tree( plane, startX, startY, w, h/2 )
transform_tree( plane, startX, startY + h/2, w, h/2 )
} else {
transform_tree( plane, startX, startY, w/2, h/2 )
transform_tree( plane, startX + w/2, startY, w/2, h/2 )
transform_tree( plane, startX, startY + h/2, w/2, h/2 )
transform_tree( plane, startX + w/2, startY + h/2, w/2, h/2 )
}
}
}
{:.syntax }
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( plane, txSz ) {
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 )
return TX_32X32
return uvTx
}
{:.syntax }
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 ) {
subx = plane > 0 ? subsampling_x : 0
suby = plane > 0 ? subsampling_y : 0
return Subsampled_Size[ subsize ][ subx ][ suby ]
}
{:.syntax }
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} },
{ {BLOCK_32X128, BLOCK_32X64}, {BLOCK_INVALID, BLOCK_16X64} },
{ {BLOCK_128X32, BLOCK_INVALID}, {BLOCK_64X32, BLOCK_64X16} },
}
coeffs( plane, startX, startY, txSz ) {
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( plane, txSz )
eobMultisize = Tx_Width_Log2[ txSz ] + Tx_Height_Log2[ txSz ] - 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-- ) {
if ( c == ( eob - 1 ) ) {
@@coeff_base_eob S
level = coeff_base_eob + 1
} else {
@@coeff_base S
level = coeff_base
}
Quant[ scan[ c ] ] = level
}
for ( c = 0; c < eob; c++ ) {
if ( Quant[ scan[ c ] ] != 0 ) {
if ( c == 0 ) {
@@dc_sign S
signs[ c ] = dc_sign
} else {
@@sign_bit L(1)
signs[ c ] = sign_bit
}
} else {
signs[ c ] = 0
}
}
for ( c = eob - 1; c >= 0; c-- ) {
pos = scan[ c ]
if ( Quant[ pos ] > NUM_BASE_LEVELS ) {
for ( idx = 0;
idx < COEFF_BASE_RANGE / ( BR_CDF_SIZE - 1 );
idx++ ) {
@@coeff_br S
Quant[ pos ] += coeff_br
if ( coeff_br < ( BR_CDF_SIZE - 1 ) )
break
}
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
}
}
}
for ( c = 0; c < eob; c++ ) {
culLevel += Quant[ scan[ c ] ]
}
coeffMin = - ( 1 << ( 7 + BitDepth ) )
coeffMax = ( 1 << ( 7 + BitDepth ) ) - 1
for ( c = 0; c < eob; c++ ) {
if ( signs[ c ] )
Quant[ scan[ c ] ] = - Quant[ scan[ c ] ]
Quant[ scan[ c ] = Clip3( coeffMin, coeffMax, Quant[ scan[ c ] ] )
}
culLevel = Min( 63, culLevel )
if ( Quant[ 0 ] < 0 ) {
dcCategory = 1
} else if ( Quant[ 0 ] > 0 ) {
dcCategory = 2
}
}
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
}
{:.syntax }
compute_tx_type( plane, txSz, blockX, blockY ) {
txSzSqrUp = Tx_Size_Sqr_Up[ txSz ]
if ( Lossless || txSzSqrUp > TX_32X32 )
return DCT_DCT
set = get_tx_set( txSz )
if ( plane == 0 ) {
txType = TxTypes[ blockY ][ blockX ]
if ( !Tx_Type_In_Set[ set ][ txType ] )
return DCT_DCT
return txType
}
if ( RefFrame[ 0 ] != INTRA_FRAME ) {
txType = TxTypes[ blockY << subsampling_y ][ blockX << subsampling_x ]
if ( !Tx_Type_In_Set[ set ][ txType ] )
return DCT_DCT
return txType
}
txType = Mode_To_Txfm[ UVMode ]
if ( !Tx_Type_In_Set[ set ][ txType ] )
return DCT_DCT
return txType
}
{:.syntax }
get_mrow_scan( txSz ) {
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_16X32 )
return Mrow_Scan_16x32
else if ( txSz == TX_32X16 )
return Mrow_Scan_32x16
else if ( txSz == TX_4X16 )
return Mrow_Scan_4x16
else if ( txSz == TX_16X4 )
return Mrow_Scan_16x4
else if ( txSz == TX_8X32 )
return Mrow_Scan_8x32
else if ( txSz == TX_32X8 )
return Mrow_Scan_32x8
return Mrow_Scan_32x32
}
get_row_scan( txSz ) {
if ( txSz == TX_4X4 )
return Row_Scan_4x4
else if ( txSz == TX_8X8 )
return Row_Scan_8x8
return Row_Scan_16x16
}
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_16X32 )
return Mcol_Scan_16x32
else if ( txSz == TX_32X16 )
return Mcol_Scan_32x16
else if ( txSz == TX_4X16 )
return Mcol_Scan_4x16
else if ( txSz == TX_16X4 )
return Mcol_Scan_16x4
else if ( txSz == TX_8X32 )
return Mcol_Scan_8x32
else if ( txSz == TX_32X8 )
return Mcol_Scan_32x8
return Mcol_Scan_32x32
}
get_col_scan( txSz ) {
if ( txSz == TX_4X4 )
return Col_Scan_4x4
else if ( txSz == TX_8X8 )
return Col_Scan_8x8
return Col_Scan_16x16
}
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( plane, 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_mrow_scan( txSz )
}
preferRow = ( PlaneTxType == ADST_DCT ||
PlaneTxType == V_DCT ||
PlaneTxType == V_ADST ||
PlaneTxType == V_FLIPADST )
preferCol = ( PlaneTxType == DCT_ADST ||
PlaneTxType == H_DCT ||
PlaneTxType == H_ADST ||
PlaneTxType == H_FLIPADST )
usesIdTx = ( PlaneTxType == V_DCT ||
PlaneTxType == V_ADST ||
PlaneTxType == V_FLIPADST ||
PlaneTxType == H_DCT ||
PlaneTxType == H_ADST ||
PlaneTxType == H_FLIPADST )
preferRaster = !( ( txSz == TX_4X4 ||
txSz == TX_8X8 ||
txSz == TX_16X16 ) && !is_inter )
if ( !usesIdTx ) {
if ( txSz == TX_32X32 ) {
return Default_Scan_32x32
} else if ( is_inter && Abs( Tx_Width_Log2[ txSz ] - Tx_Height_Log2[ txSz ] ) < 2 ) {
preferRow = 0
preferCol = 0
}
}
if (preferRow) {
return preferRaster ? get_mrow_scan( txSz ) : get_row_scan( txSz )
} else if (preferCol) {
return preferRaster ? get_mcol_scan( txSz ) : get_col_scan( txSz )
}
return get_default_scan( txSz )
}
{:.syntax }
intra_angle_info( ) {
if ( MiSize >= BLOCK_8X8 ) {
if ( is_directional_mode( YMode ) ) {
@@angle_delta_y S
AngleDeltaY = angle_delta_y - MAX_ANGLE_DELTA
}
if ( is_directional_mode( UVMode ) ) {
@@angle_delta_uv S
AngleDeltaUV = angle_delta_uv - MAX_ANGLE_DELTA
}
}
}
{:.syntax }
is_directional_mode( mode ) {
if ( ( mode >= V_PRED ) && ( mode <= D63_PRED ) ) {
return 1
}
return 0
}
{:.syntax }
read_cfl_alphas() {
@@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
}
}
{:.syntax }
palette_mode_info( ) {
bsizeCtx = Mi_Width_Log2[ MiSize ] + Mi_Height_Log2[ MiSize ]
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, ceil( log2( range ) ) )
idx++
}
sort( palette_colors_y, 0, PaletteSizeY - 1 )
}
}
if ( UVMode == DC_PRED && HasChroma ) {
@@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, ceil( log2( 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)
}
}
}
}
}
{:.syntax }
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. {:.alert .alert-info }
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 ) {
aboveN = 0
if ( ( ( MiRow * MI_SIZE ) % 64 ) && AvailU ) {
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
}
{:.syntax }
Note: get_palette_cache is equivalent to sorting the available palette colors from above and left together and removing any duplicates. {:.alert .alert-info }
transform_type( x4, y4, txSz ) {
set = get_tx_set( txSz )
if ( set > 0 &&
( segmentation_enabled ? get_qindex( 1, segment_id ) : base_q_idx ) > 0 &&
!skip &&
!seg_feature_active( SEG_LVL_SKIP ) ) {
if ( is_inter ) {
@@inter_tx_type S
if ( set == 1 )
TxType = Tx_Type_Inter_Inv_Set1[ inter_tx_type ]
else if ( set == 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 == 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
}
}
}
{:.syntax }
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 ) {
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
}
}
{:.syntax }
palette_tokens( ) {
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 U(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 U(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 ]
}
}
}
}
{:.syntax }
get_palette_color_context( colorMap, r, c, n ) {
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 ]
}
}
{:.syntax }
is_inside determines whether a candidate position is accessible. Moving across the top tile edge is allowed when dependent_tiles is equal to 1 and allowed by the AllowDependentTileRow array, but moving across the other tile edges is always prohibited.
is_inside( candidateR, candidateC ) {
if (candidateC >= MiColStart &&
candidateC < MiColEnd &&
candidateR < MiRowEnd) {
if (candidateR >= MiRowStart)
return 1
if (dependent_tiles && AllowDependentTileRow[ TileRow ])
return 1
}
return 0
}
{:.syntax }
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 ) {
colStart = loop_filter_across_tiles_v ? 0 : MiColStart
colEnd = loop_filter_across_tiles_v ? MiCols : MiColEnd
rowStart = loop_filter_across_tiles_h ? 0 : MiRowStart
rowEnd = loop_filter_across_tiles_h ? MiRows : MiRowEnd
return (candidateC >= colStart &&
candidateC < colEnd &&
candidateR >= rowStart &&
candidateR < rowEnd)
}
{:.syntax }
This section defines some simple helper functions used in other parts of the specification:
check_backward(refFrame) {
return ( (refFrame >= BWDREF_FRAME) && (refFrame <= ALTREF_FRAME) )
}
check_last_or_last2(refFrame) {
return ( (refFrame == LAST_FRAME) || (refFrame == LAST2_FRAME) )
}
check_golden_or_last3(refFrame) {
return ( (refFrame == GOLDEN_FRAME) || (refFrame == LAST3_FRAME) )
}
check_last(refFrame) {
return (refFrame == LAST_FRAME)
}
check_last2(refFrame) {
return (refFrame == LAST2_FRAME)
}
check_last3(refFrame) {
return (refFrame == LAST3_FRAME)
}
check_golden(refFrame) {
return (refFrame == GOLDEN_FRAME)
}
{:.syntax }
clamp_mv_row( mvec, border ) {
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 )
}
{:.syntax }
clamp_mv_col( mvec, border ) {
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 )
}
{:.syntax }
clear_cdef( r, c ) {
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
}
}
{:.syntax }
read_cdef( ) {
if ( allow_intrabc || AllLossless) {
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 ]
}
}
}
}
{:.syntax }
decode_lr( r, c, bSize ) {
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)
continue
subX = (plane == 0) ? 0 : subsampling_x
subY = (plane == 0) ? 0 : subsampling_y
unitSize = LoopRestorationSize[ plane ]
tileLeft = upscale_mi_to_pos(MiColStart, plane)
tileRight = upscale_mi_to_pos(MiColEnd, plane)
unitRows = count_units_in_tile( unitSize, (MiRowEnd - MiRowStart) * ( MI_SIZE >> subY ) )
unitCols = count_units_in_tile( unitSize, tileRight - tileLeft )
relMiRow = r - MiRowStart
relMiCol = c - MiColStart
unitRowStart = ( relMiRow * ( MI_SIZE >> subY) + unitSize - 1 ) / unitSize
unitRowEnd = Min( unitRows, ( (relMiRow + 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 = ( relMiCol * numerator + denominator - 1 ) / denominator
unitColEnd = Min( unitCols, ( (relMiCol + w) * numerator + denominator - 1 ) / denominator)
for (unitRow = unitRowStart; unitRow < unitRowEnd; unitRow++) {
for (unitCol = unitColStart; unitCol < unitColEnd; unitCol++) {
decode_lr_unit(plane, unitRow, unitCol)
}
}
}
}
{:.syntax }
where count_units_in_tile is a function specified as:
count_units_in_tile(unitSize, tileSize) {
return Max((tileSize + (unitSize >> 1)) / unitSize, 1)
}
and upscale_mi_to_pos is a function that converts a x position (in units of 4x4 luma blocks) to an upsampled sample position in the specified plane specified as:
upscale_mi_to_pos( miX, plane ) {
if (plane > 0) {
subX = subsampling_x
} else {
subX = 0
}
if ( miX == MiCols ) {
return Round2( UpscaledWidth, subX )
}
downscaleX = ( miX * MI_SIZE ) >> subX
if ( use_superres ) {
upscaleX = ( downscaleX * SuperresDenom ) / SUPERRES_NUM
} else {
upscaleX = downscaleX
}
return upscaleX
}
decode_lr_unit(plane, unitRow, unitCol) {
if (FrameRestorationType[ plane ] == RESTORE_NONE) {
restoration_type = RESTORE_NONE
} else 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[ TileNum ][ plane ][ unitRow ][ unitCol ] = restoration_type
if (restoration_type == RESTORE_WIENER) {
for ( pass = 0; pass < 2; pass++ ) {
if (plane) {
firstCoeff = 1
LrWiener[ TileNum ][ 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[ TileNum ][ plane ]
[ unitRow ][ unitCol ][ pass ][ j ] = v
RefLrWiener[ plane ][ pass ][ j ] = v
}
}
} else if (restoration_type == RESTORE_SGRPROJ) {
@@lr_sgr_set U(SGRPROJ_PARAMS_BITS)
LrSgrSet[ TileNum ][ plane ][ unitRow ][ unitCol ] = lr_sgr_set
for (i = 0; i < 2; i++) {
min = Sgrproj_Xqd_Min[i]
max = Sgrproj_Xqd_Max[i]
v = decode_signed_subexp_with_ref_bool(
min, max + 1, SGRPROJ_PRJ_SUBEXP_K, RefSgrXqd[ plane ][ i ])
LrSgrXqd[ TileNum ][ plane ][ unitRow ][ unitCol ][ i ] = v
RefSgrXqd[ plane ][ i ] = v
}
}
}
{:.syntax }
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 }
and decode_signed_subexp_with_ref_bool is a function specified as follows:
decode_signed_subexp_with_ref_bool( low, high, k, r ) {
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 U(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
}
}
}
}
{:.syntax }
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. {:.alert .alert-info }