AV1语法结构分析
bitstream
av1把原始的yuv文件编码成码流文件,生成的码流文件格式有以下两种。
-
low-overhead bitstream format:标准的5.2节规定了由一系列的OBU单元打包形成bitstream的方式,是一种低开销的码流格式。
-
length-delimited format:标准的Annex B规定了temporal_unit组成bitstram的方式,下图描述了如何将一个temporal_unit打包起来,而多个temporal_unit进行组合则形成了bitstream。该格式优点是很方便跳过某些帧或者temporal_unit。
对于上图的说明如下: -
Bitstream由多个temporal_unit打包构成。
-
一个temporal_unit是由N个OBU组成,这些OBU在时间上有相关性。
-
每个temporal_unit内,第一个frame_unit包含的必须是temporal delimiter OBU,这是temporal delimiter OBU唯一可以出现的地方,功能类似时间分隔符。
-
一个frame_unit包含一帧的内容,它不能包含多个帧的frame hdr OBU。
-
sequence_hdr_OBU类似SPS,一个视频序列可以有多个sequence_hdr_OBU。
-
metedata_OBU声明了一些编码格式,如profile,level,hdr,svc等。
-
frame hdr OBU类似PPS,每个frame_unit都应该有一个frame_hdr_OBU或reduant_frame_hdr_OBU。
-
一个frame_unit含有N个tile_group_OBU,一个tile group有多个tile,是码流的主要构成成分。
-
一个tile由N个superblock构成,superblock有两种尺寸,128x128和64x64。superblock有多种分割方式,称作partition。
-
每种partition划分的单元,称作block,decode_block()函数内,就包括了编码具体过程的语法元素,如mode_info,residual。
TU始终遵循递增的显示顺序。如果未使用可伸缩性,则TU仅包含一个显示帧,即show_existing_frame等于1或show_frame等于1的帧。如果使用了可伸缩性,则TU中来自不同可伸缩层的所有显示帧都对应于相同的呈现时间。一个TU也可以包含show_frame标志等于0的帧。此类帧会被解码但不会立即显示。它们用于支持如上所述的帧重排序。类似地,也可以发送覆盖帧,该覆盖帧会对先前解码的帧(称为替代参考帧(ARF))与源帧之间的差异进行编码。AV1比特流的这一方面类似于VP9编解码器中的超帧。AV1解码器模型介绍
AV1解码器模型介绍原作者blog
下图显示出了将比特流划分为时间单元的示例。在该图中,帧编号按照显示顺序编号。比特流使用具有三个时间层的4帧的双向层级预测结构。show_frame等于0的帧显示为青色框,show_frame等于1的帧显示为深绿色框。FrameHdr 2是show_existing_frame标志等于1的帧头,该帧指向先前解码的Frame 2。
bitstream( ) { Type
while ( more_data_in_bitstream() ) {
temporal_unit_size leb128()
temporal_unit( temporal_unit_size )
}
}
语法元素
- more_data_in_bitstream() 1表示还有data需要读取,0表示data已经全部读完。
- temporal_unit_size 表示temporal_unit的字节长度。
- leb128() 表示过程中读取的字节数。
temporal_unit
temporal_unit( sz ) { Type
while ( sz > 0 ) {
frame_unit_size leb128()
sz -= Leb128Bytes
frame_unit( frame_unit_size )
sz -= frame_unit_size
}
}
语法元素
- sz 表示temporal_unit读取的字节数。
- frame_unit_size 表示下一个frame_unit的字节长度。
frame_unit
frame_unit( sz ) { Type
while ( sz > 0 ) {
obu_length leb128()
sz -= Leb128Bytes
open_bitstream_unit( obu_length )
sz -= obu_length
}
}
语法元素
- obu_length 表示下个OBU的字节长度。
可以看到这两种打包方式的基本单元都是OBU。
open_bitstream_unit
open_bitstream_unit( sz ) { Type
obu_header()
if ( obu_has_size_field ) {
obu_size leb128()
} else {
obu_size = sz - 1 - obu_extension_flag
}
startPosition = get_position( )
if ( obu_type != OBU_SEQUENCE_HEADER &&
obu_type != OBU_TEMPORAL_DELIMITER &&
OperatingPointIdc != 0 &&
obu_extension_flag == 1 )
{
inTemporalLayer = (OperatingPointIdc >> temporal_id ) & 1
inSpatialLayer = (OperatingPointIdc >> ( spatial_id + 8 ) ) & 1
if ( !inTemporalLayer || ! inSpatialLayer ) {
drop_obu( )
return
}
}
if ( obu_type == OBU_SEQUENCE_HEADER )
sequence_header_obu( )
else if ( obu_type == OBU_TEMPORAL_DELIMITER )
temporal_delimiter_obu( )
else if ( obu_type == OBU_FRAME_HEADER )
frame_header_obu( )
else if ( obu_type == OBU_REDUNDANT_FRAME_HEADER )
frame_header_obu( )
else if ( obu_type == OBU_TILE_GROUP )
tile_group_obu( obu_size )
else if ( obu_type == OBU_METADATA )
metadata_obu( )
else if ( obu_type == OBU_FRAME )
frame_obu( obu_size )
else if ( obu_type == OBU_TILE_LIST )
tile_list_obu( )
else if ( obu_type == OBU_PADDING )
padding_obu( )
else
reserved_obu( )
currentPosition = get_position( )
payloadBits = currentPosition - startPosition
if ( obu_size > 0 && obu_type != OBU_TILE_GROUP &&
obu_type != OBU_TILE_LIST &&
obu_type != OBU_FRAME ) {
trailing_bits( obu_size * 8 - payloadBits )
}
}
obu_header() { Type
obu_forbidden_bit f(1)
obu_type f(4)
obu_extension_flag f(1)
obu_has_size_field f(1)
obu_reserved_1bit f(1)
if ( obu_extension_flag == 1 )
obu_extension_header()
}
obu_extension_header() { Type
temporal_id f(3)
spatial_id f(2)
extension_header_reserved_3bits f(3)
}
trailing_bits( nbBits ) { Type
trailing_one_bit f(1)
nbBits--
while ( nbBits > 0 ) {
trailing_zero_bit f(1)
nbBits--
}
语法元素
- obu_has_size_field =1表示会有obu_size语法元素,=0表示不提供obu_size。
- obu_extension_flag 表示可选择的obu_extension_header语法元素是否存在。
- startPosition 表示码流比特的位置(the value of the bitstream position indicator)。
- obu_type 表示OBU内含有的数据结构的类型,下一节我们将讨论它的语法。
- OperatingPointIdc 表示operating_point_idc的值。
- inTemporalLayer 表示时域层,分层解码。
- inSpatialLayer 表示空域层,控制分辨率。
obu_type
obu_type | Name of obu_type | Description |
---|---|---|
0 | Reserved | |
1 | OBU_SEQUENCE_HEADER | 功能类似SPS |
2 | OBU_TEMPORAL_DELIMITER | 时间分隔符,分割temporal unit |
3 | OBU_FRAME_HEADER | 功能类似PPS |
4 | OBU_TILE_GROUP | 一帧由N个tg组成,intra/inter等主要信息在此type内 |
5 | OBU_METADATA | 声明 profie,level,svc,HDR信息等 |
6 | OBU_FRAME | 一个obu_frame就是一帧,一帧有n个tile group |
7 | OBU_REDUNDANT_FRAME_HEADER | 当前obu采用上一个obu hdr |
8 | OBU_TILE_LIST | 用于large scale,见Annex D |
9-14 | Reserved | 保留 |
15 | OBU_PADDING | 填充OBU,解码器可以忽略整个padding OBU单元 |
Sequence header OBU
sequence_header_obu( ) { Type
seq_profile f(3)
still_picture f(1)
reduced_still_picture_header f(1)
if ( reduced_still_picture_header ) {
timing_info_present_flag = 0
decoder_model_info_present_flag = 0
initial_display_delay_present_flag = 0
operating_points_cnt_minus_1 = 0
operating_point_idc[ 0 ] = 0
seq_level_idx[ 0 ] f(5)
seq_tier[ 0 ] = 0
decoder_model_present_for_this_op[ 0 ] = 0
initial_display_delay_present_for_this_op[ 0 ] = 0
} else {
timing_info_present_flag f(1)
if ( timing_info_present_flag ) {
timing_info( )
decoder_model_info_present_flag f(1)
if ( decoder_model_info_present_flag ) {
decoder_model_info( )
}
} else {
decoder_model_info_present_flag = 0
}
initial_display_delay_present_flag f(1)
operating_points_cnt_minus_1 f(5)
for ( i = 0; i <= operating_points_cnt_minus_1; i++ ) {
operating_point_idc[ i ] f(12)
seq_level_idx[ i ] f(5)
if ( seq_level_idx[ i ] > 7 ) {
seq_tier[ i ] f(1)
} else {
seq_tier[ i ] = 0
}
if ( decoder_model_info_present_flag ) {
decoder_model_present_for_this_op[ i ] f(1)
if ( decoder_model_present_for_this_op[ i ] ) {
operating_parameters_info( i )
}
} else {
decoder_model_present_for_this_op[ i ] = 0
}
if ( initial_display_delay_present_flag ) {
initial_display_delay_present_for_this_op[ i ] f(1)
if ( initial_display_delay_present_for_this_op[ i ] ) {
initial_display_delay_minus_1[ i ] f(4)
}
}
}
}
operatingPoint = choose_operating_point( )
OperatingPointIdc = operating_point_idc[ operatingPoint ]
frame_width_bits_minus_1 f(4)
frame_height_bits_minus_1 f(4)
n = frame_width_bits_minus_1 + 1
max_frame_width_minus_1 f(n)
n = frame_height_bits_minus_1 + 1
max_frame_height_minus_1 f(n)
if ( reduced_still_picture_header )
frame_id_numbers_present_flag = 0
else
frame_id_numbers_present_flag f(1)
if ( frame_id_numbers_present_flag ) {
delta_frame_id_length_minus_2 f(4)
additional_frame_id_length_minus_1 f(3)
}
use_128x128_superblock f(1)
enable_filter_intra f(1)
enable_intra_edge_filter f(1)
if ( reduced_still_picture_header ) {
enable_interintra_compound = 0
enable_masked_compound = 0
enable_warped_motion = 0
enable_dual_filter = 0
enable_order_hint = 0
enable_jnt_comp = 0
enable_ref_frame_mvs = 0
seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS
seq_force_integer_mv = SELECT_INTEGER_MV
OrderHintBits = 0
} else {
enable_interintra_compound f(1)
enable_masked_compound f(1)
enable_warped_motion f(1)
enable_dual_filter f(1)
enable_order_hint f(1)
if ( enable_order_hint ) {
enable_jnt_comp f(1)
enable_ref_frame_mvs f(1)
} else {
enable_jnt_comp = 0
enable_ref_frame_mvs = 0
}
seq_choose_screen_content_tools f(1)
if ( seq_choose_screen_content_tools ) {
seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS
} else {
seq_force_screen_content_tools f(1)
}
if ( seq_force_screen_content_tools > 0 ) {
seq_choose_integer_mv f(1)
if ( seq_choose_integer_mv ) {
seq_force_integer_mv = SELECT_INTEGER_MV
} else {
seq_force_integer_mv f(1)
}
} else {
seq_force_integer_mv = SELECT_INTEGER_MV
}
if ( enable_order_hint ) {
order_hint_bits_minus_1 f(3)
OrderHintBits = order_hint_bits_minus_1 + 1
} else {
OrderHintBits = 0
}
}
enable_superres f(1)
enable_cdef
enable_restoration f(1)
color_config( )
film_grain_params_present f(1)
}
语法元素
- seq_profile 指明了待编码序列的格式,见下表。
Bit depth | Monochrome support | Chroma subsampling | |
---|---|---|---|
0 | 8 or 10 | Yes | YUV 4:2:0 |
1 | 8 or 10 | No | YUV 4:4:4 |
2 | 8 or 10 | Yes | YUV 4:2:2 |
- still_picture =1表示编码序列只包含一个帧;=0表示编码序列包含一或多个帧。
- reduced_still_picture_header 表示still_picture的不需要语法元素将被省略。
- timing_info_present_flag 指明编码序列中是否存在时间信息。
- decoder_model_info_present_flag 指明编码序列中是否存在解码器模型信息。
- initial_display_delay_present_flag 指定编码序列中是否存在初始显示延迟信息。
- operating_points_cnt_minus_1 表示operating points-1。
- operating_points 表示哪个空域和时域层需要被解码。
- operating_point_idc[ i ] 包括一个位掩码用来指明哪个空域和时域层需要被解码。如果时域层k需要被解码,那么bit k=1( k∈[0,7] );如果空域层j需要被解码,要么bit j+8=1( j∈[0,3] )。
- seq_level_idx表示符合operating point i的编码序列的level。
- seq_tier表示符合operating point i的编码序列的等级。
- decoder_model_present_for_this_op 表示是否有一个解码模型提供给当前的operating point i。
- initial_display_delay_present_for_this_op表示是否有一个初始显示延迟信息提供给当前的operating point i。
- initial_display_delay_minus_1[ i ] 信号+1表示在第一个可显示的帧之前,需要被存到解码buffer中的解码帧数量。这将确保序列中所有的解码帧能够在显示前成功解码。如果没有传递此信号,那么initial_display_delay_minus_1[ i ] = BUFFER_POOL_MAX_SIZE - 1。
- frame_id_numbers_present_flag 表示编码序列中是否有帧id号。
- delta_frame_id_length_minus_2 表示编码delta_frame_id语法元素所需比特数-2。
- additional_frame_id_length_minus_1 表示编码frame_id语法元素所需比特数-1。
- use_128x128_superblock =1表示一个超级块包括亮度128x128采样信息;=0表示包括亮度64x64采样信息(色度采样信息方式由subsampling_x 和 subsampling_y决定)。superblock概念含义见Superblock解释。
- enable_filter_intra =1表示码流中有use_filter_intra语法元素;=0表示没有use_filter_intra语法元素。
- enable_intra_edge_filter 表示是否开启了帧内边界滤波过程。
- enable_interintra_compound 表示帧间块模式信息是否包括interintra语法元素。
- enable_masked_compound 表示帧间块模式信息是否包括compound_type语法元素。compound_type描述了两种预测方式是怎样混合在一起进行预测的。
- enable_warped_motion 表示码流是否包括allow_warped_motion语法元素。
- enable_dual_filter =1表示可以在水平方向和垂直方向分别指定帧间预测滤波器类型;=0,则只能指定一种过滤器类型,然后在两个方向上使用。
- enable_order_hint 表示码流是否使用enable_jnt_comp和enable_ref_frame_mvs语法元素。
- enable_jnt_comp 表示帧间预测的distance weights process是否使用。
- enable_ref_frame_mvs 表示码流是否包括use_ref_frame_mvs语法元素。
- seq_force_screen_content_tools =SELECT_SCREEN_CONTENT_TOOLS表示帧头中含有allow_screen_content_tools语法元素;否则表示allow_screen_content_tools的值。
- seq_force_integer_mv =SELECT_INTEGER_MV表示帧头中含有force_integer_mv语法元素(在allow_screen_content_tools=1的前提下);否则表示force_integer_mv的值。
- OrderHintBits 表示order_hint语法元素的比特数。
- seq_choose_screen_content_tools =0表示帧头含有seq_force_screen_content_tools语法元素;=1表示seq_force_screen_content_tools=SELECT_SCREEN_CONTENT_TOOLS。
- seq_choose_integer_mv =0表示含有seq_force_integer_mv语法元素;=1表示seq_force_integer_mv=SELECT_INTEGER_MV。
- enable_superres =1表示在未压缩的头中含有use_superres语法元素;=0表示不含有use_superres语法元素(在未压缩的头中use_superres=0从而不被读取)。
- enable_cdef 表示是否开启CDEF,CDEF原理详见AV1的CDEF过程介绍。
- enable_restoration 表示是否开始loop restoration。
- film_grain_params_present 表示在编码序列中是否含有film grain参数。
Metadata OBU syntax
metadata_obu( ) { Type
metadata_type leb128()
if ( metadata_type == METADATA_TYPE_ITUT_T35 )
metadata_itut_t35( )
else if ( metadata_type == METADATA_TYPE_HDR_CLL )
metadata_hdr_cll( )
else if ( metadata_type == METADATA_TYPE_HDR_MDCV )
metadata_hdr_mdcv( )
else if ( metadata_type == METADATA_TYPE_SCALABILITY )
metadata_scalability( )
else if ( metadata_type == METADATA_TYPE_TIMECODE )
metadata_timecode( )
}
语法元素
metadata_type | Name of metadata_type |
---|---|
0 | Reserved for AOM use |
1 | METADATA_TYPE_HDR_CLL |
2 | METADATA_TYPE_HDR_MDCV |
3 | METADATA_TYPE_SCALABILITY |
4 | METADATA_TYPE_ITUT_T35 |
5 | METADATA_TYPE_TIMECODE |
6-31 | Unregistered user private |
32 and greater | Reserved for AOM use |
Frame header OBU
frame_header_obu( ) {
if ( SeenFrameHeader == 1 ) {
frame_header_copy()
} else {
SeenFrameHeader = 1
uncompressed_header( )
if ( show_existing_frame ) {
decode_frame_wrapup( )
SeenFrameHeader = 0
} else {
TileNum = 0
SeenFrameHeader = 1
}
}
}
语法元素
- frame_header_copy 这是一个函数表示此处应插入之前的frame_header_obu。Note:码流中可以包含几份frame_header_obu的副本,其分布在tile_group_obu中,以保证更好的错误恢复能力。副本的内容须与原始frame_header_obu相同。
- show_existing_frame =1表示frame_to_show_map_idx的帧索引即将被输出;=0表示要进行更多的进程。
- TileNum 表示当前tile的索引值。
- decode_frame_wrapup 是一个函数调用,意味着调用解码wrapup流程,见标准7.4节。
Uncompressed header
uncompressed_header( ) {
if ( frame_id_numbers_present_flag ) {
idLen = ( additional_frame_id_length_minus_1 +
delta_frame_id_length_minus_2 + 3 )
}
allFrames = (1 << NUM_REF_FRAMES) - 1
if ( reduced_still_picture_header ) {
show_existing_frame = 0
frame_type = KEY_FRAME
FrameIsIntra = 1
show_frame = 1
showable_frame = 0
} else {
show_existing_frame
if ( show_existing_frame == 1 ) {
frame_to_show_map_idx
if ( decoder_model_info_present_flag && !equal_picture_interval ) {
temporal_point_info( )
}
refresh_frame_flags = 0
if ( frame_id_numbers_present_flag ) {
display_frame_id f(idLen)
}
frame_type = RefFrameType[ frame_to_show_map_idx ]
if ( frame_type == KEY_FRAME ) {
refresh_frame_flags = allFrames
}
if ( film_grain_params_present ) {
load_grain_params( frame_to_show_map_idx )
}
return
}
frame_type f(2)
FrameIsIntra = (frame_type == INTRA_ONLY_FRAME ||
frame_type == KEY_FRAME)
show_frame f(1)
if ( show_frame && decoder_model_info_present_flag && !equal_picture_interval ) {
temporal_point_info( )
}
if ( show_frame ) {
showable_frame = frame_type != KEY_FRAME
} else {
showable_frame f(1)
}
if ( frame_type == SWITCH_FRAME ||
( frame_type == KEY_FRAME && show_frame ) )
error_resilient_mode = 1
else
error_resilient_mode f(1)
}
if ( frame_type == KEY_FRAME && show_frame ) {
for ( i = 0; i < NUM_REF_FRAMES; i++ ) {
RefValid[ i ] = 0
RefOrderHint[ i ] = 0
}
for ( i = 0; i < REFS_PER_FRAME; i++ ) {
OrderHints[ LAST_FRAME + i ] = 0
}
}
disable_cdf_update f(1)
if ( seq_force_screen_content_tools == SELECT_SCREEN_CONTENT_TOOLS ) {
allow_screen_content_tools f(1)
} else {
allow_screen_content_tools = seq_force_screen_content_tools
}
if ( allow_screen_content_tools ) {
if ( seq_force_integer_mv == SELECT_INTEGER_MV ) {
force_integer_mv f(1)
} else {
force_integer_mv = seq_force_integer_mv
}
} else {
force_integer_mv = 0
}
if ( FrameIsIntra ) {
force_integer_mv = 1
}
if ( frame_id_numbers_present_flag ) {
PrevFrameID = current_frame_id
current_frame_id f(idLen)
mark_ref_frames( idLen )
} else {
current_frame_id = 0
}
if ( frame_type == SWITCH_FRAME )
frame_size_override_flag = 1
else if ( reduced_still_picture_header )
frame_size_override_flag = 0
else
frame_size_override_flag
order_hint
OrderHint = order_hint
if ( FrameIsIntra || error_resilient_mode ) {
primary_ref_frame = PRIMARY_REF_NONE
} else {
primary_ref_frame
}
if ( decoder_model_info_present_flag ) {
buffer_removal_time_present_flag f(1)
if ( buffer_removal_time_present_flag ) {
for ( opNum = 0; opNum <= operating_points_cnt_minus_1; opNum++ ) {
if ( decoder_model_present_for_this_op[ opNum ] ) {
opPtIdc = operating_point_idc[ opNum ]
inTemporalLayer = ( opPtIdc >> temporal_id ) & 1
inSpatialLayer = ( opPtIdc >> ( spatial_id + 8 ) ) & 1
if ( opPtIdc == 0 || ( inTemporalLayer && inSpatialLayer ) ) {
n = buffer_removal_time_length_minus_1 + 1
buffer_removal_time[ opNum ] f(n)
}
}
}
}
}
allow_high_precision_mv = 0
use_ref_frame_mvs = 0
allow_intrabc = 0
if ( frame_type == SWITCH_FRAME ||
( frame_type == KEY_FRAME && show_frame ) ) {
refresh_frame_flags = allFrames
} else {
refresh_frame_flags f(8)
}
if ( !FrameIsIntra || refresh_frame_flags != allFrames ) {
if ( error_resilient_mode && enable_order_hint ) {
for ( i = 0; i < NUM_REF_FRAMES; i++) {
ref_order_hint[ i ] f(OrderHintBits)
if ( ref_order_hint[ i ] != RefOrderHint[ i ] ) {
RefValid[ i ] = 0
}
}
}
}
if ( FrameIsIntra ) {
frame_size( )
render_size( )
if ( allow_screen_content_tools && UpscaledWidth == FrameWidth ) {
allow_intrabc f(1)
}
} else {
if ( !enable_order_hint ) {
frame_refs_short_signaling = 0
} else {
frame_refs_short_signaling f(1)
if ( frame_refs_short_signaling ) {
last_frame_idx f(3)
gold_frame_idx f(3)
set_frame_refs()
}
}
for ( i = 0; i < REFS_PER_FRAME; i++ ) {
if ( !frame_refs_short_signaling )
ref_frame_idx[ i ]
if ( frame_id_numbers_present_flag ) {
n = delta_frame_id_length_minus_2 + 2
delta_frame_id_minus_1 f(n)
DeltaFrameId = delta_frame_id_minus_1 + 1
expectedFrameId[ i ] = ((current_frame_id + (1 << idLen) -
DeltaFrameId ) % (1 << idLen))
}
}
if ( frame_size_override_flag && !error_resilient_mode ) {
frame_size_with_refs( )
} else {
frame_size( )
render_size( )
}
if ( force_integer_mv ) {
allow_high_precision_mv = 0
} else {
allow_high_precision_mv f(1)
}
read_interpolation_filter( )
is_motion_mode_switchable f(1)
if ( error_resilient_mode || !enable_ref_frame_mvs ) {
use_ref_frame_mvs = 0
} else {
use_ref_frame_mvs f(1)
}
for ( i = 0; i < REFS_PER_FRAME; i++ ) {
refFrame = LAST_FRAME + i
hint = RefOrderHint[ ref_frame_idx[ i ] ]
OrderHints[ refFrame ] = hint
if ( !enable_order_hint ) {
RefFrameSignBias[ refFrame ] = 0
} else {
RefFrameSignBias[ refFrame ] = get_relative_dist( hint, OrderHint) > 0
}
}
}
if ( reduced_still_picture_header || disable_cdf_update )
disable_frame_end_update_cdf = 1
else
disable_frame_end_update_cdf f(1)
if ( primary_ref_frame == PRIMARY_REF_NONE ) {
init_non_coeff_cdfs( )
setup_past_independence( )
} else {
load_cdfs( ref_frame_idx[ primary_ref_frame ] )
load_previous( )
}
if ( use_ref_frame_mvs == 1 )
motion_field_estimation( )
tile_info( )
quantization_params( )
segmentation_params( )
delta_q_params( )
delta_lf_params( )
if ( primary_ref_frame == PRIMARY_REF_NONE ) {
init_coeff_cdfs( )
} else {
load_previous_segment_ids( )
}
CodedLossless = 1
for ( segmentId = 0; segmentId < MAX_SEGMENTS; segmentId++ ) {
qindex = get_qindex( 1, segmentId )
LosslessArray[ segmentId ] = qindex == 0 && DeltaQYDc == 0 &&
DeltaQUAc == 0 && DeltaQUDc == 0 &&
DeltaQVAc == 0 && DeltaQVDc == 0
if ( !LosslessArray[ segmentId ] )
CodedLossless = 0
if ( using_qmatrix ) {
if ( LosslessArray[ segmentId ] ) {
SegQMLevel[ 0 ][ segmentId ] = 15
SegQMLevel[ 1 ][ segmentId ] = 15
SegQMLevel[ 2 ][ segmentId ] = 15
} else {
SegQMLevel[ 0 ][ segmentId ] = qm_y
SegQMLevel[ 1 ][ segmentId ] = qm_u
SegQMLevel[ 2 ][ segmentId ] = qm_v
}
}
}
AllLossless = CodedLossless && ( FrameWidth == UpscaledWidth )
loop_filter_params( )
cdef_params( )
lr_params( )
read_tx_mode( )
frame_reference_mode( )
skip_mode_params( )
if ( FrameIsIntra ||
error_resilient_mode ||
!enable_warped_motion )
allow_warped_motion = 0
else
allow_warped_motion
reduced_tx_set
global_motion_params( )
film_grain_params( )
}
语法元素
- frame type
frame_type | Name of frame_type |
---|---|
0 | KEY_FRAME |
1 | INTER_FRAME |
2 | INTRA_ONLY_FRAME |
3 | SWITCH_FRAME |
- NUM_REF_FRAMES 参考帧的数量。
- frame_to_show_map_idx 表示要被输出帧的索引。
- display_frame_id 表示要输出帧的id号。
- RefFrameType[ ] 表示可被用来作为输出帧类型的索引表。
- show_frame =1表示该帧在解码完要立即输出。
- showable_frame =1表示该帧采用show_existing_frame机制后输出;=0表示采用show_existing_frame机制后不输出。
- error_resilient_mode =1表示错差恢复机制使能;=0表示错差恢复机制关闭。
- RefValid[ i ] =1表示选出了那些在bit depth, profile, chroma subsampling, color space与当前帧都一致的参考帧的标志位。
- RefOrderHint[ i ] 表示每个参考帧的预期输出顺序,大多数情况下=OrderHints。
- REFS_PER_FRAME 表示可用于帧间预测的参考帧数量。
- OrderHints 表示每个参考帧的预期输出顺序。
- disable_cdf_update 表示符号解码过程的CDF update过程应该被关掉。
- allow_screen_content_tools =1表示帧内块可以使用palette编码;=0表示禁用palette编码。
- force_integer_mv =1表示运动矢量为整数;=0表示运动矢量可以为小数。
- frame_size_override_flag =0表示帧大小=sequence header中的size;=1表示帧大小要么等于一个参考帧中的size,要么由frame_width_minus_1 和 frame_height_minus_1来进行计算。
- primary_ref_frame 表示在帧开始时,哪个含有CDF值和其他规定说明的参考帧需要被load进来。
- buffer_removal_time_present_flag 表示是否buffer_removal_time语法元素。
- buffer_removal_time[ opNum ] 指明了在解码buffer中帧的移除时间。
- allow_high_precision_mv =0表示运动矢量被指定为四分之一像素精度;=1表示运动矢量被指定为八分之一像素精度。
- use_ref_frame_mvs =1表示之前帧的MV信息可以用来解码当前帧。
- allow_intrabc =1表示本帧可以intra block copy。
- ref_order_hint 表示每个参考帧被期望的输出顺序。
- frame_refs_short_signaling =1表示只有2个参考帧是显示传输的;=0表示全部的参考帧都显示传输。
- is_motion_mode_switchable =0表示只有SIMPLE运动模式可以被使用。
- RefFrameSignBias[ refFrame ] =0表示参考帧是向前参考帧;=1表示是一个向后参考帧。
- reduced_tx_set =1表示当前帧被限制用变换类型的全部集合的一个缩减的子集。
Frame OBU
frame_obu( sz ) {
startBitPos = get_position( )
frame_header_obu( )
byte_alignment( )
endBitPos = get_position( )
headerBytes = (endBitPos - startBitPos) / 8
sz -= headerBytes
tile_group_obu( sz )
}
Tile group OBU
tile_group_obu( sz ) { Type
NumTiles = TileCols * TileRows
startBitPos = get_position( )
tile_start_and_end_present_flag = 0
if ( NumTiles > 1 )
tile_start_and_end_present_flag f(1)
if ( NumTiles == 1 || !tile_start_and_end_present_flag ) {
tg_start = 0
tg_end = NumTiles - 1
} else {
tileBits = TileColsLog2 + TileRowsLog2
tg_start f(tileBits)
tg_end f(tileBits)
}
byte_alignment( )
endBitPos = get_position( )
headerBytes = (endBitPos - startBitPos) / 8
sz -= headerBytes
for ( TileNum = tg_start; TileNum <= tg_end; TileNum++ ) {
tileRow = TileNum / TileCols
tileCol = TileNum % TileCols
lastTile = TileNum == tg_end
if ( lastTile ) {
tileSize = sz
} else {
tile_size_minus_1 le(TileSizeBytes)
tileSize = tile_size_minus_1 + 1
sz -= tileSize + TileSizeBytes
}
MiRowStart = MiRowStarts[ tileRow ]
MiRowEnd = MiRowStarts[ tileRow + 1 ]
MiColStart = MiColStarts[ tileCol ]
MiColEnd = MiColStarts[ tileCol + 1 ]
CurrentQIndex = base_q_idx
init_symbol( tileSize )
decode_tile( )
exit_symbol( )
}
if ( tg_end == NumTiles - 1 ) {
if ( !disable_frame_end_update_cdf ) {
frame_end_update_cdf( )
}
decode_frame_wrapup( )
SeenFrameHeader = 0
}
}
语法元素
- NumTiles 表示一帧中tile的数量。
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 )
}
}
}
语法元素
- clear_above_context 是一个函数调用,调用此函数将会使某些用于确定概率的数组=0。
- DeltaLF 表示loop filter delta的值。
Decode partition
decode_partition( r, c, bSize ) { Type
if ( r >= MiRows || c >= MiCols )
return 0
AvailU = is_inside( r - 1, c )
AvailL = is_inside( r, c - 1 )
num4x4 = Num_4x4_Blocks_Wide[ bSize ]
halfBlock4x4 = num4x4 >> 1
quarterBlock4x4 = halfBlock4x4 >> 1
hasRows = ( r + halfBlock4x4 ) < MiRows
hasCols = ( c + halfBlock4x4 ) < MiCols
if ( bSize < BLOCK_8X8 ) {
partition = PARTITION_NONE
} else if ( hasRows && hasCols ) {
partition S()
} else if ( hasCols ) {
split_or_horz S()
partition = split_or_horz ? PARTITION_SPLIT : PARTITION_HORZ
} else if ( hasRows ) {
split_or_vert S()
partition = split_or_vert ? PARTITION_SPLIT : PARTITION_VERT
} else {
partition = PARTITION_SPLIT
}
subSize = Partition_Subsize[ partition ][ bSize ]
splitSize = Partition_Subsize[ PARTITION_SPLIT ][ bSize ]
if ( partition == PARTITION_NONE ) {
decode_block( r, c, subSize )
} else if ( partition == PARTITION_HORZ ) {
decode_block( r, c, subSize )
if ( hasRows )
decode_block( r + halfBlock4x4, c, subSize )
} else if ( partition == PARTITION_VERT ) {
decode_block( r, c, subSize )
if ( hasCols )
decode_block( r, c + halfBlock4x4, subSize )
} else if ( partition == PARTITION_SPLIT ) {
decode_partition( r, c, subSize )
decode_partition( r, c + halfBlock4x4, subSize )
decode_partition( r + halfBlock4x4, c, subSize )
decode_partition( r + halfBlock4x4, c + halfBlock4x4, subSize )
} else if ( partition == PARTITION_HORZ_A ) {
decode_block( r, c, splitSize )
decode_block( r, c + halfBlock4x4, splitSize )
decode_block( r + halfBlock4x4, c, subSize )
} else if ( partition == PARTITION_HORZ_B ) {
decode_block( r, c, subSize )
decode_block( r + halfBlock4x4, c, splitSize )
decode_block( r + halfBlock4x4, c + halfBlock4x4, splitSize )
} else if ( partition == PARTITION_VERT_A ) {
decode_block( r, c, splitSize )
decode_block( r + halfBlock4x4, c, splitSize )
decode_block( r, c + halfBlock4x4, subSize )
} else if ( partition == PARTITION_VERT_B ) {
decode_block( r, c, subSize )
decode_block( r, c + halfBlock4x4, splitSize )
decode_block( r + halfBlock4x4, c + halfBlock4x4, splitSize )
} else if ( partition == PARTITION_HORZ_4 ) {
decode_block( r + quarterBlock4x4 * 0, c, subSize )
decode_block( r + quarterBlock4x4 * 1, c, subSize )
decode_block( r + quarterBlock4x4 * 2, c, subSize )
if ( r + quarterBlock4x4 * 3 < MiRows )
decode_block( r + quarterBlock4x4 * 3, c, subSize )
} else {
decode_block( r, c + quarterBlock4x4 * 0, subSize )
decode_block( r, c + quarterBlock4x4 * 1, subSize )
decode_block( r, c + quarterBlock4x4 * 2, subSize )
if ( c + quarterBlock4x4 * 3 < MiCols )
decode_block( r, c + quarterBlock4x4 * 3, subSize )
}
}
语法元素
- partition 表示一个block是怎么被分割的。
partition | Name of partition |
---|---|
0 | PARTITION_NONE |
1 | PARTITION_HORZ |
2 | PARTITION_VERT |
3 | PARTITION_SPLIT |
4 | PARTITION_HORZ_A |
5 | PARTITION_HORZ_B |
6 | PARTITION_VERT_A |
7 | PARTITION_VERT_B |
8 | PARTITION_HORZ_4 |
9 | PARTITION_VERT_4 |