Table of Contents
5.11.3 clear_block_decoded_flags函数
5.11.7 intra_frame_mode_info语法
5.11.14 seg_feature_active_idx函数
5.11.18 inter_frame_mode_info语法
5.11.22 intra_block_mode_info语法
5.11.23 inter_block_mode_info语法
5.11.24 filter_intra_mode_info语法
5.11.28 read_interintra_mode语法
5.11.38 get_plane_residual_size函数
5.11.50 get_palette_color_context函数
5.11.52 is_inside_filter_region函数
5.11 Tile组OBU语法
5.11.1 tile_group_obu语法
tile_group_obu( sz )
{
NumTiles = TileCols * TileRows
startBitPos = get_position( )
tile_start_and_end_present_flag = 0
if ( NumTiles > 1 )
tile_start_and_end_present_flag // Type f(1)
if ( NumTiles == 1 || !tile_start_and_end_present_flag )
{
tg_start = 0
tg_end = NumTiles - 1
}
else
{
tileBits = TileColsLog2 + TileRowsLog2
tg_start // Type f(tileBits)
tg_end // Type 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 // Type 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
}
}
5.11.2 decode_tile语法
decode_tile( )
{
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 )
}
}
}
其中的常量查找表Sgrproj_Xqd_Mid和Wiener_Taps_Mid定义如下,
Wiener_Taps_Mid[3] = { 3, -7, 15 }
Sgrproj_Xqd_Mid[2] = { -32, 31 }
5.11.3 clear_block_decoded_flags函数
clear_block_decoded_flags( r, c, sbSize4 )
{
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
}
}
5.11.4 decode_partition语法
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 // Type S()
}
else if ( hasCols )
{
split_or_horz // Type S()
partition = split_or_horz ? PARTITION_SPLIT : PARTITION_HORZ
}
else if ( hasRows )
{
split_or_vert // Type 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 )
}
}
5.11.5 decode_block语法
decode_block( r, c, subSize )
{
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 ]
}
}
}
其中的reset_block_context()定义如下,
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
}
}
}
5.11.6 mode_info语法
mode_info( )
{
if ( FrameIsIntra )
intra_frame_mode_info( )
else
inter_frame_mode_info( )
}
5.11.7 intra_frame_mode_info语法
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 // Type 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 // Type S()
YMode = intra_frame_y_mode
intra_angle_info_y( )
if ( HasChroma )
{
uv_mode // Type 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( )
}
}
5.11.8 intra_segment_id语法
intra_segment_id( )
{
if ( segmentation_enabled )
read_segment_id( )
else
segment_id = 0
Lossless = LosslessArray[ segment_id ]
}
5.11.9 read_segment_id语法
read_segment_id( )
{
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 // Type S()
segment_id = neg_deinterleave( segment_id, pred, LastActiveSegId + 1 )
}
}
其中的neg_deinterleave()定义如下,
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)
}
}
5.11.10 read_skip_mode语法
read_skip_mode()
{
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 // Type S()
}
}
5.11.11 read_skip语法
read_skip()
{
if ( SegIdPreSkip && seg_feature_active( SEG_LVL_SKIP ) )
{
skip = 1
}
else
{
skip // Type S()
}
}
5.11.12 read_delta_qindex语法
read_delta_qindex( )
{
sbSize = use_128x128_superblock ? BLOCK_128X128 : BLOCK_64X64
if ( MiSize == sbSize && skip )
return
if ( ReadDeltas )
{
delta_q_abs // Type S()
if ( delta_q_abs == DELTA_Q_SMALL )
{
delta_q_rem_bits // Type L(3)
delta_q_rem_bits++
delta_q_abs_bits // Type 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 // Type L(1)
reducedDeltaQIndex = delta_q_sign_bit ? -delta_q_abs : delta_q_abs
CurrentQIndex = Clip3(1, 255, CurrentQIndex + (reducedDeltaQIndex << delta_q_res))
}
}
}
5.11.13 read_delta_lf语法
read_delta_lf( )
{
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 // Type S()
if ( delta_lf_abs == DELTA_LF_SMALL )
{
delta_lf_rem_bits // Type L(3)
n = delta_lf_rem_bits + 1
delta_lf_abs_bits // Type L(n)
deltaLfAbs = delta_lf_abs_bits + ( 1 << n ) + 1
}
else
{
deltaLfAbs = delta_lf_abs
}
if ( deltaLfAbs )
{
delta_lf_sign_bit // Type L(1)
reducedDeltaLfLevel = delta_lf_sign_bit ? -deltaLfAbs : deltaLfAbs
DeltaLF[ i ] = Clip3( -MAX_LOOP_FILTER, MAX_LOOP_FILTER, DeltaLF[ i ] + (reducedDeltaLfLevel << delta_lf_res) )
}
}
}
}
5.11.14 seg_feature_active_idx函数
seg_feature_active_idx( idx, feature )
{
return segmentation_enabled && FeatureEnabled[ idx ][ feature ]
}
seg_feature_active( feature )
{
return seg_feature_active_idx( segment_id, feature )
}
5.11.15 read_tx_size语法
read_tx_size( allowSelect )
{
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 // Type S()
for ( i = 0; i < tx_depth; i++ )
TxSize = Split_Tx_Size[ TxSize ]
}
}
其中Max_Tx_Depth定义了每个块尺寸的最大变换深度,
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
}
注意:Max_Tx_Depth包含必须拆分变换以达到4x4变换大小的次数。它可能大于MAX_TX_DEPTH。但是,因为tx_depth只能编码0到2范围内的值,所以无法进行变换深度大于MAX_TX_DEPTH的编码。
5.11.16 read_block_tx_size语法
read_block_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 )
{
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
}
}
5.11.17 read_var_tx_size语法
用于读取变换尺寸树。
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 // Type 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
}
}
5.11.18 inter_frame_mode_info语法
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( )
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( )
}
5.11.19 inter_segment_id语法
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 // Type 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
}
}
5.11.20 read_is_inter语法
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 if ( seg_feature_active ( SEG_LVL_GLOBALMV ) )
{
is_inter = 1
}
else
{
is_inter // Type S()
}
}
5.11.21 get_segment_id函数
segment_id是在当前块覆盖的分割图的屏幕中找到的最小值。
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
}
5.11.22 intra_block_mode_info语法
intra_block_mode_info( )
{
RefFrame[ 0 ] = INTRA_FRAME
RefFrame[ 1 ] = NONE
y_mode // Type S()
YMode = y_mode
intra_angle_info_y( )
if ( HasChroma )
{
uv_mode // Type 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( )
}
5.11.23 inter_block_mode_info语法
inter_block_mode_info( )
{
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 // Type S()
YMode = NEAREST_NEARESTMV + compound_mode
}
else
{
new_mv // Type S()
if ( new_mv == 0 )
{
YMode = NEWMV
}
else
{
zero_mv // Type S()
if ( zero_mv == 0 )
{
YMode = GLOBALMV
}
else
{
ref_mv // Type 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 // Type 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 // Type 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 ] // Type 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
}
}
其中的has_nearmv函数和needs_interp_filter函数定义为,
has_nearmv( )
{
return (YMode == NEARMV || YMode == NEAR_NEARMV || YMode == NEAR_NEWMV || YMode == NEW_NEARMV)
}
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
}
}
5.11.24 filter_intra_mode_info语法
filter_intra_mode_info( )
{
use_filter_intra = 0
if ( enable_filter_intra
&& YMode == DC_PRED
&& PaletteSizeY == 0
&& Max( Block_Width[ MiSize ], Block_Height[ MiSize ] ) <= 32 )
{
use_filter_intra // Type S()
if ( use_filter_intra )
{
filter_intra_mode // Type S()
}
}
}
5.11.25 read_ref_frames语法
read_ref_frames( )
{
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 // Type S()
else
comp_mode = SINGLE_REFERENCE
if ( comp_mode == COMPOUND_REFERENCE )
{
comp_ref_type // Type S()
if ( comp_ref_type == UNIDIR_COMP_REFERENCE )
{
uni_comp_ref // Type S()
if ( uni_comp_ref )
{
RefFrame[0] = BWDREF_FRAME
RefFrame[1] = ALTREF_FRAME
}
else
{
uni_comp_ref_p1 // Type S()
if ( uni_comp_ref_p1 )
{
uni_comp_ref_p2 // Type 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 // Type S()
if ( comp_ref == 0 )
{
comp_ref_p1 // Type S()
RefFrame[ 0 ] = comp_ref_p1 ? LAST2_FRAME : LAST_FRAME
}
else
{
comp_ref_p2 // Type S()
RefFrame[ 0 ] = comp_ref_p2 ? GOLDEN_FRAME : LAST3_FRAME
}
comp_bwdref // Type S()
if ( comp_bwdref == 0 )
{
comp_bwdref_p1 // Type S()
RefFrame[ 1 ] = comp_bwdref_p1 ? ALTREF2_FRAME : BWDREF_FRAME
}
else
{
RefFrame[ 1 ] = ALTREF_FRAME
}
}
}
else
{
single_ref_p1 // Type S()
if ( single_ref_p1 )
{
single_ref_p2 // Type S()
if ( single_ref_p2 == 0 )
{
single_ref_p6 // Type S()
RefFrame[ 0 ] = single_ref_p6 ? ALTREF2_FRAME : BWDREF_FRAME
}
else
{
RefFrame[ 0 ] = ALTREF_FRAME
}
}
else
{
single_ref_p3 // Type S()
if ( single_ref_p3 )
{
single_ref_p5 // Type S()
RefFrame[ 0 ] = single_ref_p5 ? GOLDEN_FRAME : LAST3_FRAME
}
else
{
single_ref_p4 // Type S()
RefFrame[ 0 ] = single_ref_p4 ? LAST2_FRAME : LAST_FRAME
}
}
RefFrame[ 1 ] = NONE
}
}
}
5.11.26 assign_mv语法
assign_mv( isCompound )
{
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 ]
}
}
}
5.11.27 read_motion_mode语法
read_motion_mode( isCompound )
{
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 // Type S()
motion_mode = use_obmc ? OBMC : SIMPLE
}
else
{
motion_mode
}
}
其中的is_scaled函数定义为,
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
}
5.11.28 read_interintra_mode语法
read_interintra_mode( isCompound )
{
if ( !skip_mode
&& enable_interintra_compound
&& !isCompound
&& MiSize >= BLOCK_8X8
&& MiSize <= BLOCK_32X32)
{
interintra // Type S()
if ( interintra )
{
interintra_mode // Type S()
RefFrame[1] = INTRA_FRAME
AngleDeltaY = 0
AngleDeltaUV = 0
use_filter_intra = 0
wedge_interintra // Type S()
if ( wedge_interintra )
{
wedge_index // Type S()
wedge_sign = 0
}
}
}
else
{
interintra = 0
}
}
5.11.29 read_compound_type语法
read_compound_type( isCompound )
{
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 // Type S()
}
if ( comp_group_idx == 0 )
{
if ( enable_jnt_comp )
{
compound_idx // Type 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 // Type S()
}
}
if ( compound_type == COMPOUND_WEDGE )
{
wedge_index // Type S()
wedge_sign // Type L(1)
}
else if ( compound_type == COMPOUND_DIFFWTD )
{
mask_type // Type L(1)
}
}
else
{
if ( interintra )
{
compound_type = wedge_interintra ? COMPOUND_WEDGE : COMPOUND_INTRA
}
else
{
compound_type = COMPOUND_AVERAGE
}
}
}
5.11.30 get_mode函数
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
}
5.11.31 read_mv语法
read_mv( ref )
{
diffMv[ 0 ] = 0
diffMv[ 1 ] = 0
if ( use_intrabc )
{
MvCtx = MV_INTRABC_CONTEXT
}
else
{
MvCtx = 0
}
mv_joint // Type 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 ]
}
5.11.32 read_mv_component语法
read_mv_component( comp )
{
mv_sign // Type S()
mv_class // Type S()
if ( mv_class == MV_CLASS_0 )
{
mv_class0_bit // Type S()
if ( force_integer_mv )
mv_class0_fr = 3
else
mv_class0_fr // Type S()
if ( allow_high_precision_mv )
mv_class0_hp // Type 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 // Type S()
d |= mv_bit << i
}
mag = CLASS0_SIZE << ( mv_class + 2 )
if ( force_integer_mv )
mv_fr = 3
else
mv_fr // Type S()
if ( allow_high_precision_mv )
mv_hp // Type S()
else
mv_hp = 1
mag += ( ( d << 3 ) | ( mv_fr << 1 ) | mv_hp ) + 1
}
return mv_sign ? -mag : mag
}
5.11.33 compute_prediction语法
compute_prediction()
{
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++
}
}
}
}
5.11.34 residual语法
residual( )
{
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 ) )
}
}
}
}
}
5.11.35 transform_block语法
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
{
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
}
}
}
5.11.36 transform_tree语法
用于读取一系列的转换块。
transform_tree( startX, startY, w, h )
{
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 )
}
}
}
其中的find_tx_size函数定义为,
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
}
5.11.37 get_tx_size函数
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 )
{
if ( Tx_Width[ uvTx ] == 16 )
{
return TX_16X32
}
if ( Tx_Height[ uvTx ] == 16 )
{
return TX_32X16
}
return TX_32X32
}
return uvTx
}
5.11.38 get_plane_residual_size函数
get_plane_residual_size返回指定平面的残留块的大小。(残留块的宽度和高度始终至少等于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 ]
}
其中的Subsampled_Size定义如下,
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} },
}
5.11.39 coeffs语法
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 // Type 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 // Type S()
eobPt = eob_pt_16 + 1
}
else if ( eobMultisize == 1 )
{
eob_pt_32 // Type S()
eobPt = eob_pt_32 + 1
}
else if ( eobMultisize == 2 )
{
eob_pt_64 // Type S()
eobPt = eob_pt_64 + 1
}
else if ( eobMultisize == 3 )
{
eob_pt_128 // Type S()
eobPt = eob_pt_128 + 1
}
else if ( eobMultisize == 4 )
{
eob_pt_256 // Type S()
eobPt = eob_pt_256 + 1
}
else if ( eobMultisize == 5 )
{
eob_pt_512 // Type S()
eobPt = eob_pt_512 + 1
}
else
{
eob_pt_1024 // Type S()
eobPt = eob_pt_1024 + 1
}
eob = ( eobPt < 2 ) ? eobPt : ( ( 1 << ( eobPt - 2 ) ) + 1 )
eobShift = Max( -1, eobPt - 3 )
if ( eobShift >= 0 )
{
eob_extra // Type S()
if ( eob_extra )
{
eob += ( 1 << eobShift )
}
for ( i = 1; i < Max( 0, eobPt - 2 ); i++ )
{
eobShift = Max( 0, eobPt - 2 ) - 1 – i
if ( eob_extra_bit )
{
eob += ( 1 << eobShift )
}
}
}
for ( c = eob - 1; c >= 0; c-- )
{
pos = scan[ c ]
if ( c == ( eob - 1 ) )
{
coeff_base_eob // Type S()
level = coeff_base_eob + 1
}
else
{
coeff_base // Type S()
level = coeff_base
}
if ( level > NUM_BASE_LEVELS )
{
for ( idx = 0; idx < COEFF_BASE_RANGE / ( BR_CDF_SIZE - 1 ); idx++ )
{
coeff_br // Type 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 // Type S()
sign = dc_sign
}
else
{
sign_bit // Type L(1)
sign = sign_bit
}
}
else
{
sign = 0
}
if ( Quant[ pos ] > ( NUM_BASE_LEVELS + COEFF_BASE_RANGE ) )
{
length = 0
do
{
length++
golomb_length_bit // Type L(1)
} while ( !golomb_length_bit )
x = 1
for ( i = length - 2; i >= 0; i-- )
{
golomb_data_bit // Type 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
}
5.11.40 compute_tx_type函数
compute_tx_type( plane, txSz, blockX, blockY )
{
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 ]
}
其中的常量查找表定义为,
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,}
}
5.11.41 get_mrow_scan函数
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_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 )
}
5.11.42 intra_angle_info_y语法
intra_angle_info_y( )
{
AngleDeltaY = 0
if ( MiSize >= BLOCK_8X8 )
{
if ( is_directional_mode( YMode ) )
{
angle_delta_y // Type S()
AngleDeltaY = angle_delta_y - MAX_ANGLE_DELTA
}
}
}
5.11.43 intra_angle_info_uv语法
intra_angle_info_uv( )
{
AngleDeltaUV = 0
if ( MiSize >= BLOCK_8X8 )
{
if ( is_directional_mode( UVMode ) )
{
angle_delta_uv // Type S()
AngleDeltaUV = angle_delta_uv - MAX_ANGLE_DELTA
}
}
}
5.11.44 is_directional_mode语法
is_directional_mode( mode )
{
if ( ( mode >= V_PRED ) && ( mode <= D67_PRED ) )
{
return 1
}
return 0
}
5.11.45 read_cfl_alphas语法
read_cfl_alphas()
{
cfl_alpha_signs // Type S()
signU = (cfl_alpha_signs + 1 ) / 3
signV = (cfl_alpha_signs + 1 ) % 3
if ( signU != CFL_SIGN_ZERO )
{
cfl_alpha_u // Type S()
CflAlphaU = 1 + cfl_alpha_u
if ( signU == CFL_SIGN_NEG )
CflAlphaU = -CflAlphaU
}
else
{
CflAlphaU = 0
}
if ( signV != CFL_SIGN_ZERO )
{
cfl_alpha_v // Type S()
CflAlphaV = 1 + cfl_alpha_v
if ( signV == CFL_SIGN_NEG )
CflAlphaV = -CflAlphaV
}
else
{
CflAlphaV = 0
}
}
5.11.46 palette_mode_info语法
palette_mode_info( )
{
bsizeCtx = Mi_Width_Log2[ MiSize ] + Mi_Height_Log2[ MiSize ] - 2
if ( YMode == DC_PRED )
{
has_palette_y // Type S()
if ( has_palette_y )
{
palette_size_y_minus_2 // Type 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 // Type L(1)
if ( use_palette_color_cache_y )
{
palette_colors_y[ idx ] = PaletteCache[ i ]
idx++
}
}
if ( idx < PaletteSizeY )
{
palette_colors_y[ idx ] // Type L(BitDepth)
idx++
}
if ( idx < PaletteSizeY )
{
minBits = BitDepth - 3
palette_num_extra_bits_y // Type L(2)
paletteBits = minBits + palette_num_extra_bits_y
}
while ( idx < PaletteSizeY )
{
palette_delta_y // Type 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 // Type S()
if ( has_palette_uv )
{
palette_size_uv_minus_2 // Type 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 // Type L(1)
if ( use_palette_color_cache_u )
{
palette_colors_u[ idx ] = PaletteCache[ i ]
idx++
}
}
if ( idx < PaletteSizeUV )
{
palette_colors_u[ idx ] // Type L(BitDepth)
idx++
}
if ( idx < PaletteSizeUV )
{
minBits = BitDepth - 3
palette_num_extra_bits_u // Type L(2)
paletteBits = minBits + palette_num_extra_bits_u
}
while ( idx < PaletteSizeUV )
{
palette_delta_u // Type 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 // Type L(1)
if ( delta_encode_palette_colors_v )
{
minBits = BitDepth - 4
maxVal = 1 << BitDepth
palette_num_extra_bits_v // Type L(2)
paletteBits = minBits + palette_num_extra_bits_v
palette_colors_v[ 0 ] // Type L(BitDepth)
for ( idx = 1; idx < PaletteSizeUV; idx++ )
{
palette_delta_v // Type L(paletteBits)
if ( palette_delta_v )
{
palette_delta_sign_bit_v // Type 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 ] // Type L(BitDepth)
}
}
}
}
}
函数sort(arr,i1,i2)按顺序对数组arr的子数组进行就地排序,要排序的子阵列在索引i1和i2之间。
注意:调色板颜色按升序生成,调色板缓存也按升序排列。这意味着可以在实现中通过合并两个排序列表替换sort函数。
其中的get_palette_cache函数定义如下,
get_palette_cache( plane )
{
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
}
注意:get_palette_cache相当于从上方和左侧排列可用的调色板颜色并删除重复项。
5.11.47 transform_type语法
transform_type( x4, y4, txSz )
{
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 // 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 // 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
}
}
}
其中使用转换表定义如下,
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, LIPADST_ADST }
Tx_Type_Inter_Inv_Set3[ 2 ] = { IDTX, DCT_DCT }
5.11.48 get_tx_set语法
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
}
}
5.11.49 palette_tokens语法
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 // Type 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 // Type 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 // Type 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 // Type 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 ]
}
}
}
}
5.11.50 get_palette_color_context函数
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 ]
}
}
5.11.51 is_inside函数
is_inside( candidateR, candidateC )
{
return ( candidateC >= MiColStart && candidateC < MiColEnd && candidateR >= MiRowStart && candidateR < MiRowEnd )
}
5.11.52 is_inside_filter_region函数
is_inside_filter_region( candidateR, candidateC )
{
colStart = 0
colEnd = MiCols
rowStart = 0
rowEnd = MiRows
return (candidateC >= colStart && candidateC < colEnd && candidateR >= rowStart && candidateR < rowEnd)
}
5.11.53 clamp_mv_row函数
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 )
}
5.11.54 clamp_mv_col函数
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 )
}
5.11.55 clear_cdef函数
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
}
}
5.11.56 read_cdef语法
read_cdef( )
{
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 ] // Type 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 ]
}
}
}
}
5.11.57 read_Ir语法
read_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 )
{
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)
}
}
}
}
}
其中的count_units_in_frame函数定义如下,
count_units_in_frame(unitSize, frameSize)
{
return Max((frameSize + (unitSize >> 1)) / unitSize, 1)
}
5.11.58 read_lr_unit语法
read_lr_unit(plane, unitRow, unitCol)
{
if ( FrameRestorationType[ plane ] == RESTORE_WIENER )
{
use_wiener // Type S()
restoration_type = use_wiener ? RESTORE_WIENER : RESTORE_NONE
}
else if ( FrameRestorationType[ plane ] == RESTORE_SGRPROJ )
{
use_sgrproj // Type S()
restoration_type = use_sgrproj ? RESTORE_SGRPROJ : RESTORE_NONE
}
else
{
restoration_type // 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 // Type 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
}
}
}
其中的常量查找表和函数定义如下,
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 }
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 // Type NS(numSyms - mk)
return subexp_unif_bools + mk
}
else
{
subexp_more_bools // Type L(1)
if ( subexp_more_bools )
{
i++
mk += a
}
else
{
subexp_bools // Type L(b2)
return subexp_bools + mk
}
}
}
}
注意:decode_signed_subexp_with_ref_bool函数与decode_signed_subexp_with_ref函数相同,除了用于表示符号的比特是算术编码而不是直接从比特流读取。
5.12 Tile列表OBU语法
5.12.1 tile_list_obu语法
tile_list_obu( )
{
output_frame_width_in_tiles_minus_1 // Type f(8)
output_frame_height_in_tiles_minus_1 // Type f(8)
tile_count_minus_1 // Type f(16)
for ( tile = 0; tile <= tile_count_minus_1; tile++ )
tile_list_entry( )
}
5.12.2 tile_list_entry语法
tile_list_entry( )
{
anchor_frame_idx // Type f(8)
anchor_tile_row // Type f(8)
anchor_tile_col // Type f(8)
tile_data_size_minus_1 // Type f(16)
N = 8 * (tile_data_size_minus_1 + 1)
coded_tile_data // Type f(N)
}