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