AV1语法结构分析

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_typeName of obu_typeDescription
0Reserved
1OBU_SEQUENCE_HEADER功能类似SPS
2OBU_TEMPORAL_DELIMITER时间分隔符,分割temporal unit
3OBU_FRAME_HEADER功能类似PPS
4OBU_TILE_GROUP一帧由N个tg组成,intra/inter等主要信息在此type内
5OBU_METADATA声明 profie,level,svc,HDR信息等
6OBU_FRAME一个obu_frame就是一帧,一帧有n个tile group
7OBU_REDUNDANT_FRAME_HEADER当前obu采用上一个obu hdr
8OBU_TILE_LIST用于large scale,见Annex D
9-14Reserved保留
15OBU_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 depthMonochrome supportChroma subsampling
08 or 10YesYUV 4:2:0
18 or 10NoYUV 4:4:4
28 or 10YesYUV 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_typeName of metadata_type
0Reserved for AOM use
1METADATA_TYPE_HDR_CLL
2METADATA_TYPE_HDR_MDCV
3METADATA_TYPE_SCALABILITY
4METADATA_TYPE_ITUT_T35
5METADATA_TYPE_TIMECODE
6-31Unregistered user private
32 and greaterReserved 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_typeName of frame_type
0KEY_FRAME
1INTER_FRAME
2INTRA_ONLY_FRAME
3SWITCH_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是怎么被分割的。
partitionName of partition
0PARTITION_NONE
1PARTITION_HORZ
2PARTITION_VERT
3PARTITION_SPLIT
4PARTITION_HORZ_A
5PARTITION_HORZ_B
6PARTITION_VERT_A
7PARTITION_VERT_B
8PARTITION_HORZ_4
9PARTITION_VERT_4

在这里插入图片描述

Decode block

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值