/************************************************************************** * * Copyright 2020 Advanced Micro Devices, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "pipe/p_video_codec.h" #include "util/u_memory.h" #include "util/u_video.h" #include "vl/vl_video_buffer.h" #include "vl/vl_codec.h" #include "entrypoint.h" #include "vid_dec.h" #include "vid_dec_av1.h" static unsigned av1_f(struct vl_vlc *vlc, unsigned n) { unsigned valid = vl_vlc_valid_bits(vlc); if (n == 0) return 0; if (valid < 32) vl_vlc_fillbits(vlc); return vl_vlc_get_uimsbf(vlc, n); } static unsigned av1_uvlc(struct vl_vlc *vlc) { unsigned value; unsigned leadingZeros = 0; while (1) { bool done = av1_f(vlc, 1); if (done) break; leadingZeros++; } if (leadingZeros >= 32) return 0xffffffff; value = av1_f(vlc, leadingZeros); return value + (1 << leadingZeros) - 1; } static int av1_le(struct vl_vlc *vlc, const unsigned n) { unsigned byte, t = 0; unsigned i; for (i = 0; i < n; ++i) { byte = av1_f(vlc, 8); t += (byte << (i * 8)); } return t; } static unsigned av1_uleb128(struct vl_vlc *vlc) { unsigned value = 0; unsigned leb128Bytes = 0; unsigned i; for (i = 0; i < 8; ++i) { leb128Bytes = av1_f(vlc, 8); value |= ((leb128Bytes & 0x7f) << (i * 7)); if (!(leb128Bytes & 0x80)) break; } return value; } static int av1_su(struct vl_vlc *vlc, const unsigned n) { unsigned value = av1_f(vlc, n); unsigned signMask = 1 << (n - 1); if (value && signMask) value = value - 2 * signMask; return value; } static unsigned FloorLog2(unsigned x) { unsigned s = 0; unsigned x1 = x; while (x1 != 0) { x1 = x1 >> 1; s++; } return s - 1; } static unsigned av1_ns(struct vl_vlc *vlc, unsigned n) { unsigned w = FloorLog2(n) + 1; unsigned m = (1 << w) - n; unsigned v = av1_f(vlc, w - 1); if (v < m) return v; bool extra_bit = av1_f(vlc, 1); return (v << 1) - m + extra_bit; } static void av1_byte_alignment(struct vl_vlc *vlc) { vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8); } static void sequence_header_obu(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); bool timing_info_present_flag; bool initial_display_delay_present_flag; uint8_t seq_level_idx; bool initial_display_delay_present_for_this_op; bool high_bitdepth; bool twelve_bit; bool color_description_present_flag; uint8_t color_primaries; uint8_t transfer_characteristics; uint8_t matrix_coefficients; int i; seq->seq_profile = av1_f(vlc, 3); assert(seq->seq_profile < 3); av1_f(vlc, 1); /* still_picture */ seq->reduced_still_picture_header = av1_f(vlc, 1); if (seq->reduced_still_picture_header) { timing_info_present_flag = 0; seq->decoder_model_info_present_flag = 0; initial_display_delay_present_flag = 0; seq->operating_points_cnt_minus_1 = 0; seq->operating_point_idc[0] = 0; seq_level_idx = av1_f(vlc, 5); seq->decoder_model_present_for_this_op[0] = 0; initial_display_delay_present_for_this_op = 0; } else { uint8_t buffer_delay_length_minus_1 = 0; timing_info_present_flag = av1_f(vlc, 1); if (timing_info_present_flag) { av1_f(vlc, 32); /* num_units_in_display_tick */ av1_f(vlc, 32); /* time_scale */ seq->timing_info.equal_picture_interval = av1_f(vlc, 1); if (seq->timing_info.equal_picture_interval) av1_uvlc(vlc); /* num_ticks_per_picture_minus_1 */ seq->decoder_model_info_present_flag = av1_f(vlc, 1); if (seq->decoder_model_info_present_flag) { /* decoder_model_info */ buffer_delay_length_minus_1 = av1_f(vlc, 5); seq->decoder_model_info.num_units_in_decoding_tick = av1_f(vlc, 32); seq->decoder_model_info.buffer_removal_time_length_minus_1 = av1_f(vlc, 5); seq->decoder_model_info.frame_presentation_time_length_minus_1 = av1_f(vlc, 5); } } else { seq->decoder_model_info_present_flag = 0; } initial_display_delay_present_flag = av1_f(vlc, 1); seq->operating_points_cnt_minus_1 = av1_f(vlc, 5); for (i = 0; i < seq->operating_points_cnt_minus_1 + 1; ++i) { seq->operating_point_idc[i] = av1_f(vlc, 12); seq_level_idx = av1_f(vlc, 5); if (seq_level_idx > 7) av1_f(vlc, 1); /* seq_tier */ if (seq->decoder_model_info_present_flag) { seq->decoder_model_present_for_this_op[i] = av1_f(vlc, 1); if (seq->decoder_model_present_for_this_op[i]) { uint8_t n = buffer_delay_length_minus_1 + 1; av1_f(vlc, n); /* decoder_buffer_delay */ av1_f(vlc, n); /* encoder_buffer_delay */ av1_f(vlc, 1); /* low_delay_mode_flag */ } } else { seq->decoder_model_present_for_this_op[i] = 0; } if (initial_display_delay_present_flag) { initial_display_delay_present_for_this_op = av1_f(vlc, 1); if (initial_display_delay_present_for_this_op) av1_f(vlc, 4); /* initial_display_delay_minus_1 */ } } } seq->frame_width_bits_minus_1 = av1_f(vlc, 4); seq->frame_height_bits_minus_1 = av1_f(vlc, 4); seq->max_frame_width_minus_1 = av1_f(vlc, seq->frame_width_bits_minus_1 + 1); seq->max_frame_height_minus_1 = av1_f(vlc, seq->frame_height_bits_minus_1 + 1); if (seq->reduced_still_picture_header) seq->frame_id_numbers_present_flag = 0; else seq->frame_id_numbers_present_flag = av1_f(vlc, 1); if (seq->frame_id_numbers_present_flag) { seq->delta_frame_id_length_minus_2 = av1_f(vlc, 4); seq->additional_frame_id_length_minus_1 = av1_f(vlc, 3); } seq->use_128x128_superblock = av1_f(vlc, 1); seq->enable_filter_intra = av1_f(vlc, 1); seq->enable_intra_edge_filter = av1_f(vlc, 1); if (seq->reduced_still_picture_header) { seq->enable_interintra_compound = 0; seq->enable_masked_compound = 0; seq->enable_warped_motion = 0; seq->enable_dual_filter = 0; seq->enable_order_hint = 0; seq->enable_jnt_comp = 0; seq->enable_ref_frame_mvs = 0; seq->seq_force_screen_content_tools = AV1_SELECT_SCREEN_CONTENT_TOOLS; seq->seq_force_integer_mv = AV1_SELECT_INTEGER_MV; seq->OrderHintBits = 0; } else { bool seq_choose_screen_content_tools; seq->enable_interintra_compound = av1_f(vlc, 1); seq->enable_masked_compound = av1_f(vlc, 1); seq->enable_warped_motion = av1_f(vlc, 1); seq->enable_dual_filter = av1_f(vlc, 1); seq->enable_order_hint = av1_f(vlc, 1); if (seq->enable_order_hint) { seq->enable_jnt_comp = av1_f(vlc, 1); seq->enable_ref_frame_mvs = av1_f(vlc, 1); } else { seq->enable_jnt_comp = 0; seq->enable_ref_frame_mvs = 0; } seq_choose_screen_content_tools = av1_f(vlc, 1); seq->seq_force_screen_content_tools = seq_choose_screen_content_tools ? AV1_SELECT_SCREEN_CONTENT_TOOLS : av1_f(vlc, 1); if (seq->seq_force_screen_content_tools > 0) { bool seq_choose_integer_mv = av1_f(vlc, 1); seq->seq_force_integer_mv = seq_choose_integer_mv ? AV1_SELECT_INTEGER_MV : av1_f(vlc, 1); } else { seq->seq_force_integer_mv = AV1_SELECT_INTEGER_MV; } if (seq->enable_order_hint) { seq->order_hint_bits_minus_1 = av1_f(vlc, 3); seq->OrderHintBits = seq->order_hint_bits_minus_1 + 1; } else { seq->OrderHintBits = 0; } } seq->enable_superres = av1_f(vlc, 1); seq->enable_cdef = av1_f(vlc, 1); seq->enable_restoration = av1_f(vlc, 1); high_bitdepth = av1_f(vlc, 1); if (seq->seq_profile == 2 && high_bitdepth) { twelve_bit = av1_f(vlc, 1); seq->color_config.BitDepth = twelve_bit ? 12 : 10; } else if (seq->seq_profile <= 2) { seq->color_config.BitDepth = high_bitdepth ? 10 : 8; } seq->color_config.mono_chrome = (seq->seq_profile == 1) ? 0 : av1_f(vlc, 1); seq->color_config.NumPlanes = seq->color_config.mono_chrome ? 1 : 3; color_description_present_flag = av1_f(vlc, 1); if (color_description_present_flag) { color_primaries = av1_f(vlc, 8); transfer_characteristics = av1_f(vlc, 8); matrix_coefficients = av1_f(vlc, 8); } else { color_primaries = AV1_CP_UNSPECIFIED; transfer_characteristics = AV1_TC_UNSPECIFIED; matrix_coefficients = AV1_MC_UNSPECIFIED; } if (seq->color_config.mono_chrome) { av1_f(vlc, 1); /* color_range */ seq->color_config.subsampling_x = 1; seq->color_config.subsampling_y = 1; seq->color_config.separate_uv_delta_q = 0; } else if (color_primaries == AV1_CP_BT_709 && transfer_characteristics == AV1_TC_SRGB && matrix_coefficients == AV1_MC_IDENTITY) { seq->color_config.subsampling_x = 0; seq->color_config.subsampling_y = 0; } else { av1_f(vlc, 1); /* color_range */ if (seq->seq_profile == 0) { seq->color_config.subsampling_x = 1; seq->color_config.subsampling_y = 1; } else if (seq->seq_profile == 1 ) { seq->color_config.subsampling_x = 0; seq->color_config.subsampling_y = 0; } else { if (seq->color_config.BitDepth == 12) { seq->color_config.subsampling_x = av1_f(vlc, 1); if (seq->color_config.subsampling_x) seq->color_config.subsampling_y = av1_f(vlc, 1); else seq->color_config.subsampling_y = 0; } else { seq->color_config.subsampling_x = 1; seq->color_config.subsampling_y = 0; } } if (seq->color_config.subsampling_x && seq->color_config.subsampling_y) av1_f(vlc, 2); /* chroma_sample_position */ } if (!seq->color_config.mono_chrome) seq->color_config.separate_uv_delta_q = av1_f(vlc, 1); seq->film_grain_params_present = av1_f(vlc, 1); priv->picture.av1.picture_parameter.profile = seq->seq_profile; priv->picture.av1.picture_parameter.seq_info_fields.use_128x128_superblock = seq->use_128x128_superblock; priv->picture.av1.picture_parameter.seq_info_fields.enable_filter_intra = seq->enable_filter_intra; priv->picture.av1.picture_parameter.seq_info_fields.enable_intra_edge_filter = seq->enable_intra_edge_filter; priv->picture.av1.picture_parameter.order_hint_bits_minus_1 = seq->order_hint_bits_minus_1; priv->picture.av1.picture_parameter.max_width = seq->max_frame_width_minus_1 + 1; priv->picture.av1.picture_parameter.max_height = seq->max_frame_height_minus_1 + 1; priv->picture.av1.picture_parameter.seq_info_fields.enable_interintra_compound = seq->enable_interintra_compound; priv->picture.av1.picture_parameter.seq_info_fields.enable_masked_compound = seq->enable_masked_compound; priv->picture.av1.picture_parameter.seq_info_fields.enable_dual_filter = seq->enable_dual_filter; priv->picture.av1.picture_parameter.seq_info_fields.enable_order_hint = seq->enable_order_hint; priv->picture.av1.picture_parameter.seq_info_fields.enable_jnt_comp = seq->enable_jnt_comp; priv->picture.av1.picture_parameter.seq_info_fields.ref_frame_mvs = seq->enable_ref_frame_mvs; priv->picture.av1.picture_parameter.bit_depth_idx = (seq->color_config.BitDepth - 8) >> 1; priv->picture.av1.picture_parameter.seq_info_fields.mono_chrome = seq->color_config.mono_chrome; } static void superres_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); unsigned coded_denom; if (seq->enable_superres) hdr->use_superres = av1_f(vlc, 1); else hdr->use_superres = 0; if (hdr->use_superres) { coded_denom = av1_f(vlc, 3 /* SUPERRES_DENOM_BITS */); hdr->SuperresDenom = coded_denom + 9 /* SUPERRES_DENOM_MIN */; } else { hdr->SuperresDenom = 8 /* SUPERRES_NUM */; } hdr->UpscaledWidth = hdr->FrameWidth; hdr->FrameWidth = (hdr->UpscaledWidth * 8 + (hdr->SuperresDenom / 2)) / hdr->SuperresDenom; } static void compute_image_size(vid_dec_PrivateType *priv) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); hdr->MiCols = 2 * ((hdr->FrameWidth + 7) >> 3); hdr->MiRows = 2 * ((hdr->FrameHeight + 7) >> 3); } static void frame_size(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); unsigned frame_width_minus_1; unsigned frame_height_minus_1; if (hdr->frame_size_override_flag) { frame_width_minus_1 = av1_f(vlc, seq->frame_width_bits_minus_1 + 1); frame_height_minus_1 = av1_f(vlc, seq->frame_height_bits_minus_1 + 1); hdr->FrameWidth = frame_width_minus_1 + 1; hdr->FrameHeight = frame_height_minus_1 + 1; } else { hdr->FrameWidth = seq->max_frame_width_minus_1 + 1; hdr->FrameHeight = seq->max_frame_height_minus_1 + 1; } superres_params(priv, vlc); compute_image_size(priv); } static void render_size(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); bool render_and_frame_size_different; unsigned render_width_minus_1; unsigned render_height_minus_1; render_and_frame_size_different = av1_f(vlc, 1); if (render_and_frame_size_different) { render_width_minus_1 = av1_f(vlc, 16); render_height_minus_1 = av1_f(vlc, 16); hdr->RenderWidth = render_width_minus_1 + 1; hdr->RenderHeight = render_height_minus_1 + 1; } else { hdr->RenderWidth = hdr->UpscaledWidth; hdr->RenderHeight = hdr->FrameHeight; } } static int get_relative_dist(vid_dec_PrivateType *priv, int a, int b) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); int diff; unsigned m; if (!seq->enable_order_hint) return 0; diff = a - b; m = 1 << (seq->OrderHintBits - 1); diff = (diff & (m - 1)) - (diff & m); return diff; } static uint8_t find_latest_backward(vid_dec_PrivateType *priv) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); uint8_t ref = 0xff; unsigned latestOrderHint = 0; int i; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { unsigned hint = hdr->shiftedOrderHints[i]; if (!hdr->usedFrame[i] && hint >= hdr->curFrameHint && (ref == 0xff || hint >= latestOrderHint)) { ref = i; latestOrderHint = hint; } } return ref; } static uint8_t find_earliest_backward(vid_dec_PrivateType *priv) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); uint8_t ref = 0xff; unsigned earliestOrderHint = 0; int i; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { unsigned hint = hdr->shiftedOrderHints[i]; if (!hdr->usedFrame[i] && hint >= hdr->curFrameHint && (ref == 0xff || hint < earliestOrderHint)) { ref = i; earliestOrderHint = hint; } } return ref; } static uint8_t find_latest_forward(vid_dec_PrivateType *priv) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); uint8_t ref = 0xff; unsigned latestOrderHint = 0; int i; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { unsigned hint = hdr->shiftedOrderHints[i]; if (!hdr->usedFrame[i] && hint < hdr->curFrameHint && (ref == 0xff || hint >= latestOrderHint)) { ref = i; latestOrderHint = hint; } } return ref; } static void set_frame_refs(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); uint8_t Ref_Frame_List[5] = { AV1_LAST2_FRAME , AV1_LAST3_FRAME, AV1_BWDREF_FRAME, AV1_ALTREF2_FRAME, AV1_ALTREF_FRAME }; unsigned earliestOrderHint = 0; uint8_t ref; int i; for (i = 0; i < AV1_REFS_PER_FRAME; ++i) hdr->ref_frame_idx[i] = 0xff; hdr->ref_frame_idx[0] = hdr->last_frame_idx; hdr->ref_frame_idx[AV1_GOLDEN_FRAME - AV1_LAST_FRAME] = hdr->gold_frame_idx; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) hdr->usedFrame[i] = 0; hdr->usedFrame[hdr->last_frame_idx] = 1; hdr->usedFrame[hdr->gold_frame_idx] = 1; hdr->curFrameHint = 1 << (seq->OrderHintBits - 1); for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) hdr->shiftedOrderHints[i] = hdr->curFrameHint + get_relative_dist(priv, hdr->RefOrderHint[i], hdr->OrderHint); ref = find_latest_backward(priv); if (ref != 0xff) { hdr->ref_frame_idx[AV1_ALTREF_FRAME - AV1_LAST_FRAME] = ref; hdr->usedFrame[ref] = 1; } ref = find_earliest_backward(priv); if (ref != 0xff) { hdr->ref_frame_idx[AV1_BWDREF_FRAME - AV1_LAST_FRAME] = ref; hdr->usedFrame[ref] = 1; } ref = find_earliest_backward(priv); if (ref != 0xff) { hdr->ref_frame_idx[AV1_ALTREF2_FRAME - AV1_LAST_FRAME] = ref; hdr->usedFrame[ref] = 1; } for (i = 0; i < AV1_REFS_PER_FRAME - 2; ++i) { uint8_t refFrame = Ref_Frame_List[i]; if (hdr->ref_frame_idx[refFrame - AV1_LAST_FRAME] == 0xff) { ref = find_latest_forward(priv); if (ref != 0xff) { hdr->ref_frame_idx[refFrame - AV1_LAST_FRAME] = ref; hdr->usedFrame[ref] = 1; } } } ref = 0xff; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { unsigned hint = hdr->shiftedOrderHints[i]; if (ref == 0xff || hint < earliestOrderHint) { ref = i; earliestOrderHint = hint; } } for (i = 0; i < AV1_REFS_PER_FRAME; ++i) { if (hdr->ref_frame_idx[i] == 0xff) hdr->ref_frame_idx[i] = ref; } } static void frame_size_with_refs(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); bool found_ref; int i; for (i = 0; i < AV1_REFS_PER_FRAME; ++i) { found_ref = av1_f(vlc, 1); if (found_ref) { hdr->UpscaledWidth = priv->codec_data.av1.RefFrames[hdr->ref_frame_idx[i]].RefUpscaledWidth; hdr->FrameWidth = hdr->UpscaledWidth; hdr->FrameHeight = priv->codec_data.av1.RefFrames[hdr->ref_frame_idx[i]].RefFrameHeight; hdr->RenderWidth = priv->codec_data.av1.RefFrames[hdr->ref_frame_idx[i]].RefRenderWidth; hdr->RenderHeight = priv->codec_data.av1.RefFrames[hdr->ref_frame_idx[i]].RefRenderHeight; break; } } if (!found_ref) { frame_size(priv, vlc); render_size(priv, vlc); } else { superres_params(priv, vlc); compute_image_size(priv); } } static unsigned tile_log2(unsigned blkSize, unsigned target) { unsigned k = 0; for (k = 0; (blkSize << k) < target; k++); return k; } static void tile_info(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct tile_info *ti = &(priv->codec_data.av1.uncompressed_header.ti); unsigned sbCols; unsigned sbRows; int width_sb; int height_sb; unsigned sbSize; unsigned maxTileWidthSb; unsigned minLog2TileCols; unsigned maxLog2TileCols; unsigned maxLog2TileRows; unsigned minLog2Tiles; bool uniform_tile_spacing_flag; unsigned maxTileAreaSb; unsigned startSb, i; sbCols = (seq->use_128x128_superblock) ? ((hdr->MiCols + 31) >> 5) : ((hdr->MiCols + 15) >> 4); sbRows = (seq->use_128x128_superblock) ? ((hdr->MiRows + 31) >> 5) : ((hdr->MiRows + 15) >> 4); width_sb = sbCols; height_sb = sbRows; sbSize = (seq->use_128x128_superblock ? 5 : 4) + 2; maxTileWidthSb = AV1_MAX_TILE_WIDTH >> sbSize; maxTileAreaSb = AV1_MAX_TILE_AREA >> (2 * sbSize); minLog2TileCols = tile_log2(maxTileWidthSb, sbCols); maxLog2TileCols = tile_log2(1, MIN2(sbCols, AV1_MAX_TILE_COLS)); maxLog2TileRows = tile_log2(1, MIN2(sbRows, AV1_MAX_TILE_ROWS)); minLog2Tiles = MAX2(minLog2TileCols, tile_log2(maxTileAreaSb, sbRows * sbCols)); uniform_tile_spacing_flag = av1_f(vlc, 1); if (uniform_tile_spacing_flag) { unsigned tileWidthSb, tileHeightSb; unsigned minLog2TileRows; ti->TileColsLog2 = minLog2TileCols; while (ti->TileColsLog2 < maxLog2TileCols) { bool increment_tile_cols_log2 = av1_f(vlc, 1); if (increment_tile_cols_log2) ti->TileColsLog2++; else break; } tileWidthSb = (sbCols + (1 << ti->TileColsLog2) - 1) >> ti->TileColsLog2; i = 0; for (startSb = 0; startSb < sbCols; startSb += tileWidthSb) { ti->tile_col_start_sb[i] = startSb; i++; } ti->tile_col_start_sb[i] = sbCols; ti->TileCols = i; minLog2TileRows = (minLog2Tiles > ti->TileColsLog2)? (minLog2Tiles - ti->TileColsLog2) : 0; ti->TileRowsLog2 = minLog2TileRows; while (ti->TileRowsLog2 < maxLog2TileRows) { bool increment_tile_rows_log2 = av1_f(vlc, 1); if (increment_tile_rows_log2) ti->TileRowsLog2++; else break; } tileHeightSb = (sbRows + (1 << ti->TileRowsLog2) - 1) >> ti->TileRowsLog2; i = 0; for (startSb = 0; startSb < sbRows; startSb += tileHeightSb) { ti->tile_row_start_sb[i] = startSb; i++; } ti->tile_row_start_sb[i] = sbRows; ti->TileRows = i; } else { unsigned widestTileSb = 0; unsigned maxTileHeightSb; startSb = 0; for (i = 0; startSb < sbCols; ++i) { uint8_t maxWidth; unsigned sizeSb; unsigned width_in_sbs_minus_1; ti->tile_col_start_sb[i] = startSb; maxWidth = MIN2(sbCols - startSb, maxTileWidthSb); width_in_sbs_minus_1 = av1_ns(vlc, maxWidth); sizeSb = width_in_sbs_minus_1 + 1; widestTileSb = MAX2(sizeSb, widestTileSb); startSb += sizeSb; width_sb -= sizeSb; } ti->TileCols = i; ti->tile_col_start_sb[i] = startSb + width_sb; ti->TileColsLog2 = tile_log2(1, ti->TileCols); if (minLog2Tiles > 0) maxTileAreaSb = (sbRows * sbCols) >> (minLog2Tiles + 1); else maxTileAreaSb = (sbRows * sbCols); maxTileHeightSb = MAX2(maxTileAreaSb / widestTileSb, 1); startSb = 0; for (i = 0; startSb < sbRows; ++i) { uint8_t maxHeight; unsigned height_in_sbs_minus_1; maxHeight = MIN2(sbRows - startSb, maxTileHeightSb); height_in_sbs_minus_1 = av1_ns(vlc, maxHeight); ti->tile_row_start_sb[i] = startSb; startSb += height_in_sbs_minus_1 + 1; height_sb -= height_in_sbs_minus_1 + 1; } ti->TileRows = i; ti->tile_row_start_sb[i] = startSb + height_sb; ti->TileRowsLog2 = tile_log2(1, ti->TileRows); } if (ti->TileColsLog2 > 0 || ti->TileRowsLog2 > 0) { ti->context_update_tile_id = av1_f(vlc, ti->TileRowsLog2 + ti->TileColsLog2); uint8_t tile_size_bytes_minus_1 = av1_f(vlc, 2); ti->TileSizeBytes = tile_size_bytes_minus_1 + 1; } else { ti->context_update_tile_id = 0; } } static int read_delta_q(struct vl_vlc *vlc) { bool delta_coded = av1_f(vlc, 1); int delta_q = 0; if (delta_coded) delta_q = av1_su(vlc, 7); return delta_q; } static void quantization_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct quantization_params* qp = &(priv->codec_data.av1.uncompressed_header.qp); bool using_qmatrix; qp->base_q_idx = av1_f(vlc, 8); qp->DeltaQYDc = read_delta_q(vlc); if (seq->color_config.NumPlanes > 1) { bool diff_uv_delta = (seq->color_config.separate_uv_delta_q) ? av1_f(vlc, 1) : 0; qp->DeltaQUDc = read_delta_q(vlc); qp->DeltaQUAc = read_delta_q(vlc); if (diff_uv_delta) { qp->DeltaQVDc = read_delta_q(vlc); qp->DeltaQVAc = read_delta_q(vlc); } else { qp->DeltaQVDc = qp->DeltaQUDc; qp->DeltaQVAc = qp->DeltaQUAc; } } else { qp->DeltaQVDc = 0; qp->DeltaQVAc = 0; qp->DeltaQUDc = 0; qp->DeltaQUAc = 0; } using_qmatrix = av1_f(vlc, 1); if (using_qmatrix) { qp->qm_y = av1_f(vlc, 4); qp->qm_u = av1_f(vlc, 4); if (!seq->color_config.separate_uv_delta_q) qp->qm_v = qp->qm_u; else qp->qm_v = av1_f(vlc, 4); } else { qp->qm_y = 0xf; qp->qm_u = 0xf; qp->qm_v = 0xf; } } static void segmentation_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct segmentation_params* sp = &(priv->codec_data.av1.uncompressed_header.sp); int i, j; sp->segmentation_enabled = av1_f(vlc, 1); if (sp->segmentation_enabled) { bool segmentation_update_data; if (hdr->primary_ref_frame == AV1_PRIMARY_REF_NONE) { sp->segmentation_update_map = 1; sp->segmentation_temporal_update = 0; segmentation_update_data = 1; } else { sp->segmentation_update_map = av1_f(vlc, 1); if (sp->segmentation_update_map) sp->segmentation_temporal_update = av1_f(vlc, 1); else sp->segmentation_temporal_update = 0; segmentation_update_data = av1_f(vlc, 1); } if (segmentation_update_data) { uint8_t Segmentation_Feature_Bits[AV1_SEG_LVL_MAX] = { 8, 6, 6, 6, 6, 3, 0, 0 }; bool Segmentation_Feature_Signed[AV1_SEG_LVL_MAX] = { 1, 1, 1, 1, 1, 0, 0, 0 }; unsigned Segmentation_Feature_Max[AV1_SEG_LVL_MAX] = { 255, 63, 63, 63, 63, 7, 0, 0 }; memset(sp->FeatureData, 0, sizeof(sp->FeatureData)); memset(sp->FeatureMask, 0, sizeof(sp->FeatureMask)); for (i = 0; i < AV1_MAX_SEGMENTS; ++i) { for (j = 0; j < AV1_SEG_LVL_MAX; ++j) { int feature_value = 0; bool feature_enabled = av1_f(vlc, 1); sp->FeatureEnabled[i][j] = feature_enabled; int clippedValue = 0; if (feature_enabled) { uint8_t bitsToRead = Segmentation_Feature_Bits[j]; int limit = Segmentation_Feature_Max[j]; if (Segmentation_Feature_Signed[j]) { feature_value = av1_su(vlc, 1 + bitsToRead); clippedValue = CLAMP(feature_value, -limit, limit); sp->FeatureMask[i] |= 1 << j; } else { feature_value = av1_f(vlc, bitsToRead); clippedValue = CLAMP(feature_value, 0, limit); sp->FeatureMask[i] |= 1 << j; } } sp->FeatureData[i][j] = clippedValue; } } } else { int r = hdr->ref_frame_idx[hdr->primary_ref_frame]; memcpy(sp, &(priv->codec_data.av1.refs[r].sp), sizeof(*sp)); } } else { memset(sp, 0, sizeof(*sp)); } } static void delta_q_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct quantization_params* qp = &(priv->codec_data.av1.uncompressed_header.qp); struct delta_q_params * dqp = &(priv->codec_data.av1.uncompressed_header.dqp); dqp->delta_q_present = 0; dqp->delta_q_res = 0; if (qp->base_q_idx > 0) dqp->delta_q_present = av1_f(vlc, 1); if (dqp->delta_q_present) dqp->delta_q_res = av1_f(vlc, 2); } static void delta_lf_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct delta_q_params * dqp = &(priv->codec_data.av1.uncompressed_header.dqp); struct delta_lf_params* dlfp = &(priv->codec_data.av1.uncompressed_header.dlfp); dlfp->delta_lf_present = 0; dlfp->delta_lf_res = 0; dlfp->delta_lf_multi = 0; if (dqp->delta_q_present) { if (!hdr->allow_intrabc) dlfp->delta_lf_present = av1_f(vlc, 1); if (dlfp->delta_lf_present) { dlfp->delta_lf_res = av1_f(vlc, 2); dlfp->delta_lf_multi = av1_f(vlc, 1); } } } static unsigned get_qindex(vid_dec_PrivateType * priv, bool ignoreDeltaQ, unsigned segmentId) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct segmentation_params* sp = &(priv->codec_data.av1.uncompressed_header.sp); struct quantization_params* qp = &(priv->codec_data.av1.uncompressed_header.qp); unsigned qindex = 0; if (sp->segmentation_enabled && sp->FeatureEnabled[segmentId][AV1_SEG_LVL_ALT_Q]) { unsigned data = sp->FeatureData[segmentId][AV1_SEG_LVL_ALT_Q]; qindex = qp->base_q_idx + data; if (!ignoreDeltaQ && hdr->dqp.delta_q_present) qindex = data; return CLAMP(qindex, 0, 255); } if (!ignoreDeltaQ && hdr->dqp.delta_q_present) return 0; return qp->base_q_idx; } static void loop_filter_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct loop_filter_params *lfp = &(priv->codec_data.av1.uncompressed_header.lfp); int i; if (hdr->CodedLossless || hdr->allow_intrabc) { lfp->loop_filter_level[0] = 0; lfp->loop_filter_level[1] = 0; lfp->loop_filter_ref_deltas[AV1_INTRA_FRAME] = 1; lfp->loop_filter_ref_deltas[AV1_LAST_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_LAST2_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_LAST3_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_BWDREF_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_GOLDEN_FRAME] = -1; lfp->loop_filter_ref_deltas[AV1_ALTREF2_FRAME] = -1; lfp->loop_filter_ref_deltas[AV1_ALTREF_FRAME] = -1; lfp->loop_filter_mode_deltas[0] = 0; lfp->loop_filter_mode_deltas[1] = 0; return; } if (hdr->primary_ref_frame == AV1_PRIMARY_REF_NONE) { lfp->loop_filter_ref_deltas[AV1_INTRA_FRAME] = 1; lfp->loop_filter_ref_deltas[AV1_LAST_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_LAST2_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_LAST3_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_BWDREF_FRAME] = 0; lfp->loop_filter_ref_deltas[AV1_GOLDEN_FRAME] = -1; lfp->loop_filter_ref_deltas[AV1_ALTREF2_FRAME] = -1; lfp->loop_filter_ref_deltas[AV1_ALTREF_FRAME] = -1; lfp->loop_filter_mode_deltas[0] = 0; lfp->loop_filter_mode_deltas[1] = 0; } else { int r = hdr->ref_frame_idx[hdr->primary_ref_frame]; memcpy(lfp->loop_filter_ref_deltas, priv->codec_data.av1.refs[r].lfp.loop_filter_ref_deltas, 8); memcpy(lfp->loop_filter_mode_deltas, priv->codec_data.av1.refs[r].lfp.loop_filter_mode_deltas, 2); } lfp->loop_filter_level[0] = av1_f(vlc, 6); lfp->loop_filter_level[1] = av1_f(vlc, 6); if (seq->color_config.NumPlanes > 1) { if (lfp->loop_filter_level[0] || lfp->loop_filter_level[1]) { lfp->loop_filter_level[2] = av1_f(vlc, 6); lfp->loop_filter_level[3] = av1_f(vlc, 6); } } lfp->loop_filter_sharpness = av1_f(vlc, 3); lfp->loop_filter_delta_enabled = av1_f(vlc, 1); if (lfp->loop_filter_delta_enabled) { lfp->loop_filter_delta_update = av1_f(vlc, 1); if (lfp->loop_filter_delta_update) { for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { int8_t update_ref_delta = av1_f(vlc, 1); if (update_ref_delta) lfp->loop_filter_ref_deltas[i] = av1_su(vlc, 7); } for (i = 0; i < 2; ++i) { int8_t update_mode_delta = av1_f(vlc, 1); if (update_mode_delta) lfp->loop_filter_mode_deltas[i] = av1_su(vlc, 7); } } } } static void cdef_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct cdef_params *cdefp = &(priv->codec_data.av1.uncompressed_header.cdefp);; int i; if (hdr->CodedLossless || hdr->allow_intrabc || !seq->enable_cdef) { cdefp->cdef_bits = 0; cdefp->cdef_y_strengths[0] = 0; cdefp->cdef_uv_strengths[0] = 0; return; } cdefp->cdef_damping_minus_3 = av1_f(vlc, 2); cdefp->cdef_bits = av1_f(vlc, 2); for (i = 0; i < (1 << cdefp->cdef_bits); ++i) { cdefp->cdef_y_strengths[i] = av1_f(vlc, 6); if (seq->color_config.NumPlanes > 1) cdefp->cdef_uv_strengths[i] = av1_f(vlc, 6); } } static void lr_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct loop_restoration_params *lrp = &(priv->codec_data.av1.uncompressed_header.lrp); uint8_t Remap_Lr_Type[4] = { AV1_RESTORE_NONE, AV1_RESTORE_SWITCHABLE, AV1_RESTORE_WIENER, AV1_RESTORE_SGRPROJ }; bool UsesLr = false; bool UsesChromaLr = false; uint8_t lr_unit_shift, lr_uv_shift; int i; if (hdr->AllLossless || hdr->allow_intrabc || !seq->enable_restoration) { lrp->FrameRestorationType[0] = AV1_RESTORE_NONE; lrp->FrameRestorationType[1] = AV1_RESTORE_NONE; lrp->FrameRestorationType[2] = AV1_RESTORE_NONE; return; } for (i = 0; i < seq->color_config.NumPlanes; ++i) { uint8_t lr_type = av1_f(vlc, 2); lrp->FrameRestorationType[i] = Remap_Lr_Type[lr_type]; if (lrp->FrameRestorationType[i] != AV1_RESTORE_NONE) { UsesLr = true; if (i > 0) UsesChromaLr = true; } } if (UsesLr) { if (seq->use_128x128_superblock) { lr_unit_shift = av1_f(vlc, 1) + 1; } else { lr_unit_shift = av1_f(vlc, 1); if (lr_unit_shift) { uint8_t lr_unit_extra_shift = av1_f(vlc, 1); lr_unit_shift += lr_unit_extra_shift; } } lrp->LoopRestorationSize[0] = AV1_RESTORATION_TILESIZE >> (2 - lr_unit_shift); lr_uv_shift = (seq->color_config.subsampling_x && seq->color_config.subsampling_y && UsesChromaLr) ? av1_f(vlc, 1) : 0; lrp->LoopRestorationSize[1] = lrp->LoopRestorationSize[0] >> lr_uv_shift; lrp->LoopRestorationSize[2] = lrp->LoopRestorationSize[0] >> lr_uv_shift; } else { lrp->LoopRestorationSize[0] = lrp->LoopRestorationSize[1] = lrp->LoopRestorationSize[2] = (1 << 8); } } static void tx_mode(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct tx_mode_params *tm = &(priv->codec_data.av1.uncompressed_header.tm); if (hdr->CodedLossless) { tm->TxMode = AV1_ONLY_4X4; } else { bool tx_mode_select = av1_f(vlc, 1); tm->TxMode = (tx_mode_select) ? AV1_TX_MODE_SELECT : AV1_TX_MODE_LARGEST; } } static void frame_reference_mode(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); if (hdr->FrameIsIntra) hdr->reference_select = SINGLE_REFERENCE; else hdr->reference_select = av1_f(vlc, 1) ? REFERENCE_MODE_SELECT : SINGLE_REFERENCE; } static void skip_mode_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct skip_mode_params *smp = &(priv->codec_data.av1.uncompressed_header.smp);; bool skipModeAllowed; int i; if (hdr->FrameIsIntra || hdr->reference_select == SINGLE_REFERENCE || !seq->enable_order_hint) { skipModeAllowed = 0; } else { int ref_frame_offset[2] = { -1, INT_MAX }; int ref_idx[2] = { -1, -1 }; skipModeAllowed = 0; for (i = 0; i < AV1_REFS_PER_FRAME; ++i) { unsigned ref_offset = priv->codec_data.av1.refs[hdr->ref_frame_idx[i]].OrderHint; if (get_relative_dist(priv, ref_offset, hdr->OrderHint) < 0) { if (ref_frame_offset[0] == -1 || get_relative_dist(priv, ref_offset, ref_frame_offset[0]) > 0) { ref_frame_offset[0] = ref_offset; ref_idx[0] = i; } } else if (get_relative_dist(priv, ref_offset, hdr->OrderHint) > 0) { if (ref_frame_offset[1] == INT_MAX || get_relative_dist(priv, ref_offset, ref_frame_offset[1]) < 0) { ref_frame_offset[1] = ref_offset; ref_idx[1] = i; } } } if (ref_idx[0] != -1 && ref_idx[1] != -1) { skipModeAllowed = 1; } else if (ref_idx[0] != -1 && ref_idx[1] == -1) { ref_frame_offset[1] = -1; for (i = 0; i < AV1_ALTREF_FRAME - AV1_LAST_FRAME + 1; ++i) { unsigned ref_offset = priv->codec_data.av1.refs[hdr->ref_frame_idx[i]].OrderHint; if ((ref_frame_offset[0] != -1 && get_relative_dist(priv, ref_offset, ref_frame_offset[0]) < 0) && (ref_frame_offset[1] == -1 || get_relative_dist(priv, ref_offset, ref_frame_offset[1]) > 0)) { ref_frame_offset[1] = ref_offset; ref_idx[1] = i; } } if (ref_frame_offset[1] != -1) skipModeAllowed = 1; } } smp->skip_mode_present = skipModeAllowed ? av1_f(vlc, 1) : 0; } static unsigned inverse_recenter(unsigned r, unsigned v) { if (v > (2 * r)) return v; else if (v & 1) return (r - ((v + 1) >> 1)); else return (r + (v >> 1)); } static unsigned decode_subexp(struct vl_vlc *vlc, unsigned numSyms) { unsigned i = 0; unsigned mk = 0; unsigned k = 3; while (1) { unsigned b2 = (i) ? (k + i - 1) : k; unsigned a = 1 << b2; if (numSyms <= (mk + 3 * a)) { unsigned subexp_final_bits = av1_ns(vlc, (numSyms - mk)); return (subexp_final_bits + mk); } else { bool subexp_more_bits = av1_f(vlc, 1); if (subexp_more_bits) { i++; mk += a; } else { unsigned subexp_bits = av1_f(vlc, b2); return (subexp_bits + mk); } } } } static unsigned decode_unsigned_subexp_with_ref(struct vl_vlc *vlc, unsigned mx, unsigned r) { unsigned smart; unsigned v = decode_subexp(vlc, mx); if ((r << 1) <= mx) { smart = inverse_recenter(r, v); return smart; } else { smart = inverse_recenter(mx - 1 - r, v); return (mx - 1 - smart); } } static int decode_signed_subexp_with_ref(struct vl_vlc *vlc, int low, int high, int r) { int x = decode_unsigned_subexp_with_ref(vlc, high - low, r - low); return (x + low); } static void read_global_param(struct global_motion_params* global_params, struct global_motion_params* ref_params, vid_dec_PrivateType *priv, struct vl_vlc *vlc, uint8_t type, uint8_t ref, uint8_t idx) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); uint8_t absBits = 12; /* GM_ABS_ALPHA_BITS */ uint8_t precBits = 15; /* GM_ALPHA_PREC_BITS */ int precDiff, round, sub, mx, r = 0; if (idx < 2) { if (type == AV1_TRANSLATION) { absBits = 9 /* GM_ABS_TRANS_ONLY_BITS */ - !hdr->allow_high_precision_mv; precBits = 3 /* GM_TRANS_ONLY_PREC_BITS */ - !hdr->allow_high_precision_mv; } else { absBits = 12; /* GM_ABS_TRANS_BITS */ precBits = 6; /* GM_TRANS_PREC_BITS */; } } precDiff = AV1_WARPEDMODEL_PREC_BITS - precBits; round = ((idx % 3) == 2) ? (1 << AV1_WARPEDMODEL_PREC_BITS) : 0; sub = ((idx % 3) == 2) ? (1 << precBits) : 0; mx = (int)(1 << absBits); if (ref_params) r = (ref_params->gm_params[ref][idx] >> precDiff) - sub; global_params->gm_params[ref][idx] = (decode_signed_subexp_with_ref(vlc, -mx, mx + 1, r) << precDiff) + round; } static void global_motion_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct global_motion_params *gmp = &(priv->codec_data.av1.uncompressed_header.gmp); struct global_motion_params *ref_gmp = NULL; unsigned ref, i; if (hdr->primary_ref_frame == AV1_PRIMARY_REF_NONE) { for (ref = 0; ref < AV1_NUM_REF_FRAMES; ++ref) { gmp->GmType[ref] = AV1_IDENTITY; for (i = 0; i < 6; ++i) gmp->gm_params[ref][i] = (((i % 3) == 2) ? (1 << AV1_WARPEDMODEL_PREC_BITS) : 0); } } else { const int r = hdr->ref_frame_idx[hdr->primary_ref_frame]; ref_gmp = &(priv->codec_data.av1.refs[r].gmp); } for (ref = AV1_LAST_FRAME; ref <= AV1_ALTREF_FRAME; ++ref) { gmp->GmType[ref] = AV1_IDENTITY; for (i = 0; i < 6; ++i) gmp->gm_params[ref][i] = (((i % 3) == 2) ? (1 << AV1_WARPEDMODEL_PREC_BITS) : 0); } if (hdr->FrameIsIntra) return; for (ref = AV1_LAST_FRAME; ref <= AV1_ALTREF_FRAME; ++ref) { uint8_t type = AV1_IDENTITY; bool is_global; gmp->GmType[ref] = AV1_IDENTITY; for (i = 0; i < 6; ++i) gmp->gm_params[ref][i] = (((i % 3) == 2) ? (1 << AV1_WARPEDMODEL_PREC_BITS) : 0); is_global = av1_f(vlc, 1); if (is_global) { bool is_rot_zoom = av1_f(vlc, 1); if (is_rot_zoom) { type = AV1_ROTZOOM; } else { bool is_translation = av1_f(vlc, 1); type = is_translation ? AV1_TRANSLATION : AV1_AFFINE; } } gmp->GmType[ref] = type; if (type >= AV1_ROTZOOM) { read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 2); read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 3); if (type == AV1_AFFINE) { read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 4); read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 5); } else { gmp->gm_params[ref][4] = -gmp->gm_params[ref][3]; gmp->gm_params[ref][5] = gmp->gm_params[ref][2]; } } if (type >= AV1_TRANSLATION) { read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 0); read_global_param(gmp, ref_gmp, priv, vlc, type, ref, 1); } } } static void film_grain_params(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); struct film_grain_params *fgp = &(priv->codec_data.av1.uncompressed_header.fgp); bool update_grain; uint8_t numPosLuma; uint8_t numPosChroma; unsigned i; if (!seq->film_grain_params_present || (!hdr->show_frame && !hdr->showable_frame)) { memset(fgp, 0, sizeof(*fgp)); return; } fgp->apply_grain = av1_f(vlc, 1); if (!fgp->apply_grain) { memset(fgp, 0, sizeof(*fgp)); return; } fgp->grain_seed = av1_f(vlc, 16); update_grain = (hdr->frame_type == AV1_INTER_FRAME) ? av1_f(vlc, 1) : 1; if (!update_grain) { uint8_t film_grain_params_ref_idx = av1_f(vlc, 3); uint16_t tempGrainSeed = fgp->grain_seed; memcpy(fgp, &(priv->codec_data.av1.refs[film_grain_params_ref_idx].fgp), sizeof(*fgp)); fgp->grain_seed = tempGrainSeed; return; } fgp->num_y_points = av1_f(vlc, 4); for (i = 0; i < fgp->num_y_points; ++i) { fgp->point_y_value[i] = av1_f(vlc, 8); fgp->point_y_scaling[i] = av1_f(vlc, 8); } fgp->chroma_scaling_from_luma = (seq->color_config.mono_chrome) ? 0 : av1_f(vlc, 1); if (seq->color_config.mono_chrome || fgp->chroma_scaling_from_luma || (seq->color_config.subsampling_x && seq->color_config.subsampling_y && (fgp->num_y_points == 0))) { fgp->num_cb_points = 0; fgp->num_cr_points = 0; } else { fgp->num_cb_points = av1_f(vlc, 4); for (i = 0; i < fgp->num_cb_points; ++i) { fgp->point_cb_value[i] = av1_f(vlc, 8); fgp->point_cb_scaling[i] = av1_f(vlc, 8); } fgp->num_cr_points = av1_f(vlc, 4); for (i = 0; i < fgp->num_cr_points; ++i) { fgp->point_cr_value[i] = av1_f(vlc, 8); fgp->point_cr_scaling[i] = av1_f(vlc, 8); } } fgp->grain_scaling_minus_8 = av1_f(vlc, 2); fgp->ar_coeff_lag = av1_f(vlc, 2); numPosLuma = 2 * fgp->ar_coeff_lag * (fgp->ar_coeff_lag + 1); if (fgp->num_y_points) { numPosChroma = numPosLuma + 1; for (i = 0; i < numPosLuma; ++i) { uint8_t ar_coeffs_y_plus_128 = av1_f(vlc, 8); fgp->ar_coeffs_y[i] = ar_coeffs_y_plus_128 - 128; } } else { numPosChroma = numPosLuma; } if (fgp->chroma_scaling_from_luma || fgp->num_cb_points) { for (i = 0; i < numPosChroma; ++i) { uint8_t ar_coeffs_cb_plus_128 = av1_f(vlc, 8); fgp->ar_coeffs_cb[i] = ar_coeffs_cb_plus_128 - 128; } } if (fgp->chroma_scaling_from_luma || fgp->num_cr_points) { for (i = 0; i < numPosChroma; ++i) { uint8_t ar_coeffs_cr_plus_128 = av1_f(vlc, 8); fgp->ar_coeffs_cr[i] = ar_coeffs_cr_plus_128 - 128; } } fgp->ar_coeff_shift_minus_6 = av1_f(vlc, 2); fgp->grain_scale_shift = av1_f(vlc, 2); if (fgp->num_cb_points) { fgp->cb_mult = av1_f(vlc, 8); fgp->cb_luma_mult = av1_f(vlc, 8); fgp->cb_offset = av1_f(vlc, 9); } if (fgp->num_cr_points) { fgp->cr_mult = av1_f(vlc, 8); fgp->cr_luma_mult = av1_f(vlc, 8); fgp->cr_offset = av1_f(vlc, 9); } fgp->overlap_flag = av1_f(vlc, 1); fgp->clip_to_restricted_range = av1_f(vlc, 1); } static void frame_header_obu(vid_dec_PrivateType *priv, struct vl_vlc *vlc) { struct av1_sequence_header_obu *seq = &(priv->codec_data.av1.seq); struct av1_uncompressed_header_obu *hdr = &(priv->codec_data.av1.uncompressed_header); unsigned idLen = 0; unsigned allFrames; int i, j; memset(hdr, 0, sizeof(*hdr)); if (seq->frame_id_numbers_present_flag) idLen = seq->additional_frame_id_length_minus_1 + seq->delta_frame_id_length_minus_2 + 3; allFrames = (1 << AV1_NUM_REF_FRAMES) - 1; if (seq->reduced_still_picture_header) { hdr->show_existing_frame = 0; hdr->frame_type = AV1_KEY_FRAME; hdr->FrameIsIntra = 1; hdr->show_frame = 1; hdr->showable_frame = 0; } else { hdr->show_existing_frame = av1_f(vlc, 1); if (hdr->show_existing_frame) { hdr->frame_to_show_map_idx = av1_f(vlc, 3); if (seq->decoder_model_info_present_flag && !seq->timing_info.equal_picture_interval) av1_f(vlc, seq->decoder_model_info. frame_presentation_time_length_minus_1 + 1); hdr->refresh_frame_flags = 0; if (seq->frame_id_numbers_present_flag) av1_f(vlc, idLen); /* display_frame_id */ hdr->frame_type = priv->codec_data.av1.RefFrames[priv->codec_data.av1.uncompressed_header. frame_to_show_map_idx].RefFrameType; return; } hdr->frame_type = av1_f(vlc, 2); hdr->FrameIsIntra = (hdr->frame_type == AV1_INTRA_ONLY_FRAME || hdr->frame_type == AV1_KEY_FRAME); hdr->show_frame = av1_f(vlc, 1); if (hdr->show_frame && seq->decoder_model_info_present_flag && !seq->timing_info.equal_picture_interval) av1_f(vlc, seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1); hdr->showable_frame = hdr->show_frame ? (hdr->frame_type != AV1_KEY_FRAME) : av1_f(vlc, 1); hdr->error_resilient_mode = (hdr->frame_type == AV1_SWITCH_FRAME || (hdr->frame_type == AV1_KEY_FRAME && hdr->show_frame)) ? 1 : av1_f(vlc, 1); } if (hdr->frame_type == AV1_KEY_FRAME && hdr->show_frame) { for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) hdr->RefOrderHint[i] = 0; } hdr->disable_cdf_update = av1_f(vlc, 1); hdr->allow_screen_content_tools = (seq->seq_force_screen_content_tools == AV1_SELECT_SCREEN_CONTENT_TOOLS) ? av1_f(vlc, 1) : seq->seq_force_screen_content_tools; if (hdr->allow_screen_content_tools) { if (seq->seq_force_integer_mv == AV1_SELECT_INTEGER_MV) hdr->force_integer_mv = av1_f(vlc, 1); else hdr->force_integer_mv = seq->seq_force_integer_mv; } else { hdr->force_integer_mv = 0; } if (hdr->FrameIsIntra) hdr->force_integer_mv = 1; hdr->current_frame_id = seq->frame_id_numbers_present_flag ? av1_f(vlc, idLen) : 0; if (hdr->frame_type == AV1_SWITCH_FRAME) hdr->frame_size_override_flag = 1; else if (seq->reduced_still_picture_header) hdr->frame_size_override_flag = 0; else hdr->frame_size_override_flag = av1_f(vlc, 1); hdr->OrderHint = av1_f(vlc, seq->OrderHintBits); if (hdr->FrameIsIntra || hdr->error_resilient_mode) hdr->primary_ref_frame = AV1_PRIMARY_REF_NONE; else hdr->primary_ref_frame = av1_f(vlc, 3); if (seq->decoder_model_info_present_flag) { bool buffer_removal_time_present_flag = av1_f(vlc, 1); if (buffer_removal_time_present_flag) { for (i = 0; i <= seq->operating_points_cnt_minus_1; ++i) { if (seq->decoder_model_present_for_this_op[i]) { unsigned opPtIdc; bool inTemporalLayer; bool inSpatialLayer; opPtIdc = seq->operating_point_idc[i]; inTemporalLayer = (opPtIdc >> priv->codec_data.av1.ext.temporal_id) & 1; inSpatialLayer = (opPtIdc >> (priv->codec_data.av1.ext.spatial_id + 8)) & 1; if ((opPtIdc == 0) || (inTemporalLayer && inSpatialLayer)) av1_f(vlc, seq->decoder_model_info. buffer_removal_time_length_minus_1 + 1); } } } } hdr->allow_high_precision_mv = 0; hdr->use_ref_frame_mvs = 0; hdr->allow_intrabc = 0; hdr->refresh_frame_flags = allFrames = (hdr->frame_type == AV1_SWITCH_FRAME || (hdr->frame_type == AV1_KEY_FRAME && hdr->show_frame)) ? allFrames : av1_f(vlc, AV1_NUM_REF_FRAMES); if (!hdr->FrameIsIntra || hdr->refresh_frame_flags != allFrames) { if (hdr->error_resilient_mode && seq->enable_order_hint) { for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) av1_f(vlc, seq->OrderHintBits); } } if (hdr->FrameIsIntra) { frame_size(priv, vlc); render_size(priv, vlc); if (hdr->allow_screen_content_tools && (hdr->UpscaledWidth == hdr->FrameWidth)) hdr->allow_intrabc = av1_f(vlc, 1); } else { bool is_filter_switchable; bool frame_refs_short_signaling; if (!seq->enable_order_hint) { frame_refs_short_signaling = 0; } else { frame_refs_short_signaling = av1_f(vlc, 1); if (frame_refs_short_signaling) { hdr->last_frame_idx = av1_f(vlc, 3); hdr->gold_frame_idx = av1_f(vlc, 3); set_frame_refs(priv, vlc); } } for (i = 0; i < AV1_REFS_PER_FRAME; ++i) { if (!frame_refs_short_signaling) hdr->ref_frame_idx[i] = av1_f(vlc, 3); if (seq->frame_id_numbers_present_flag) av1_f(vlc, seq->delta_frame_id_length_minus_2 + 2); } if (hdr->frame_size_override_flag && !hdr->error_resilient_mode) { frame_size_with_refs(priv, vlc); } else { frame_size(priv, vlc); render_size(priv, vlc); } hdr->allow_high_precision_mv = hdr->force_integer_mv ? 0 : av1_f(vlc, 1); is_filter_switchable = av1_f(vlc, 1); hdr->interpolation_filter = is_filter_switchable ? 4 /* SWITCHABLE */ : av1_f(vlc, 2); hdr->is_motion_mode_switchable = av1_f(vlc, 1); hdr->use_ref_frame_mvs = (hdr->error_resilient_mode || !seq->enable_ref_frame_mvs) ? 0 : av1_f(vlc, 1); } hdr->disable_frame_end_update_cdf = (seq->reduced_still_picture_header || hdr->disable_cdf_update) ? 1 : av1_f(vlc, 1); tile_info(priv, vlc); quantization_params(priv, vlc); segmentation_params(priv, vlc); delta_q_params(priv, vlc); delta_lf_params(priv, vlc); hdr->CodedLossless = 1; for (i = 0; i < AV1_MAX_SEGMENTS; ++i) { unsigned qindex = get_qindex(priv, 1, i); bool LosslessArray = (qindex == 0) && (hdr->qp.DeltaQYDc == 0) && (hdr->qp.DeltaQUAc == 0) && (hdr->qp.DeltaQUDc == 0) && (hdr->qp.DeltaQVAc == 0) && (hdr->qp.DeltaQVDc == 0); if (!LosslessArray) hdr->CodedLossless = 0; } hdr->AllLossless = hdr->CodedLossless && (hdr->FrameWidth == hdr->UpscaledWidth); loop_filter_params(priv, vlc); cdef_params(priv, vlc); lr_params(priv, vlc); tx_mode(priv, vlc); frame_reference_mode(priv, vlc); skip_mode_params(priv, vlc); if (hdr->FrameIsIntra || hdr->error_resilient_mode || !seq->enable_warped_motion) hdr->allow_warped_motion = 0; else hdr->allow_warped_motion = av1_f(vlc, 1); hdr->reduced_tx_set = av1_f(vlc, 1); global_motion_params(priv, vlc); film_grain_params(priv, vlc); priv->picture.av1.picture_parameter.pic_info_fields.frame_type = hdr->frame_type; priv->picture.av1.picture_parameter.pic_info_fields.show_frame = hdr->show_frame; priv->picture.av1.picture_parameter.pic_info_fields.error_resilient_mode = hdr->error_resilient_mode; priv->picture.av1.picture_parameter.pic_info_fields.disable_cdf_update = hdr->disable_cdf_update; priv->picture.av1.picture_parameter.pic_info_fields.allow_screen_content_tools = hdr->allow_screen_content_tools; priv->picture.av1.picture_parameter.pic_info_fields.force_integer_mv = hdr->force_integer_mv; priv->picture.av1.picture_parameter.current_frame_id = hdr->current_frame_id; priv->picture.av1.picture_parameter.order_hint = hdr->OrderHint; priv->picture.av1.picture_parameter.primary_ref_frame = hdr->primary_ref_frame; priv->picture.av1.picture_parameter.frame_width = hdr->FrameWidth; priv->picture.av1.picture_parameter.frame_height = hdr->FrameHeight; priv->picture.av1.picture_parameter.pic_info_fields.use_superres = hdr->use_superres; priv->picture.av1.picture_parameter.superres_scale_denominator = hdr->SuperresDenom; for (i = 0; i < AV1_REFS_PER_FRAME; ++i) priv->picture.av1.picture_parameter.ref_frame_idx[i] = hdr->ref_frame_idx[i]; priv->picture.av1.picture_parameter.pic_info_fields.allow_high_precision_mv = hdr->allow_high_precision_mv; priv->picture.av1.picture_parameter.pic_info_fields.allow_intrabc = hdr->allow_intrabc; priv->picture.av1.picture_parameter.pic_info_fields.use_ref_frame_mvs = hdr->use_ref_frame_mvs; priv->picture.av1.picture_parameter.interp_filter = hdr->interpolation_filter; priv->picture.av1.picture_parameter.pic_info_fields.is_motion_mode_switchable = hdr->is_motion_mode_switchable; priv->picture.av1.picture_parameter.refresh_frame_flags = hdr->refresh_frame_flags; priv->picture.av1.picture_parameter.pic_info_fields.disable_frame_end_update_cdf = hdr->disable_frame_end_update_cdf; /* Tile Info */ priv->picture.av1.picture_parameter.tile_rows = hdr->ti.TileRows; priv->picture.av1.picture_parameter.tile_cols = hdr->ti.TileCols; priv->picture.av1.picture_parameter.context_update_tile_id = hdr->ti.context_update_tile_id; for (i = 0; i picture.av1.picture_parameter.tile_row_start_sb[i] = hdr->ti.tile_row_start_sb[i]; for (i = 0; i picture.av1.picture_parameter.tile_col_start_sb[i] = hdr->ti.tile_col_start_sb[i]; /* Quantization Params */ priv->picture.av1.picture_parameter.base_qindex = hdr->qp.base_q_idx; priv->picture.av1.picture_parameter.y_dc_delta_q = hdr->qp.DeltaQYDc; priv->picture.av1.picture_parameter.u_dc_delta_q = hdr->qp.DeltaQUDc; priv->picture.av1.picture_parameter.u_ac_delta_q = hdr->qp.DeltaQUAc; priv->picture.av1.picture_parameter.v_dc_delta_q = hdr->qp.DeltaQVDc; priv->picture.av1.picture_parameter.v_ac_delta_q = hdr->qp.DeltaQVAc; priv->picture.av1.picture_parameter.qmatrix_fields.qm_y = hdr->qp.qm_y; priv->picture.av1.picture_parameter.qmatrix_fields.qm_u = hdr->qp.qm_u; priv->picture.av1.picture_parameter.qmatrix_fields.qm_v = hdr->qp.qm_v; /* Segmentation Params */ priv->picture.av1.picture_parameter.seg_info.segment_info_fields.enabled = hdr->sp.segmentation_enabled; priv->picture.av1.picture_parameter.seg_info.segment_info_fields.update_map = hdr->sp.segmentation_update_map; priv->picture.av1.picture_parameter.seg_info.segment_info_fields.temporal_update = hdr->sp.segmentation_temporal_update; for (i = 0; i < AV1_MAX_SEGMENTS; ++i) { for (j = 0; j < AV1_SEG_LVL_MAX; ++j) priv->picture.av1.picture_parameter.seg_info.feature_data[i][j] = hdr->sp.FeatureData[i][j]; priv->picture.av1.picture_parameter.seg_info.feature_mask[i] = hdr->sp.FeatureMask[i]; } /* Delta Q Params */ priv->picture.av1.picture_parameter.mode_control_fields.delta_q_present_flag = hdr->dqp.delta_q_present; priv->picture.av1.picture_parameter.mode_control_fields.log2_delta_q_res = hdr->dqp.delta_q_res; /* Delta LF Params */ priv->picture.av1.picture_parameter.mode_control_fields.delta_lf_present_flag = hdr->dlfp.delta_lf_present; priv->picture.av1.picture_parameter.mode_control_fields.log2_delta_lf_res = hdr->dlfp.delta_lf_res; priv->picture.av1.picture_parameter.mode_control_fields.delta_lf_multi = hdr->dlfp.delta_lf_multi; /* Loop Filter Params */ for (i = 0; i < 2; ++i) priv->picture.av1.picture_parameter.filter_level[i] = hdr->lfp.loop_filter_level[i]; priv->picture.av1.picture_parameter.filter_level_u = hdr->lfp.loop_filter_level[2]; priv->picture.av1.picture_parameter.filter_level_v = hdr->lfp.loop_filter_level[3]; priv->picture.av1.picture_parameter.loop_filter_info_fields.sharpness_level = hdr->lfp.loop_filter_sharpness; priv->picture.av1.picture_parameter.loop_filter_info_fields.mode_ref_delta_enabled = hdr->lfp.loop_filter_delta_enabled; priv->picture.av1.picture_parameter.loop_filter_info_fields.mode_ref_delta_update = hdr->lfp.loop_filter_delta_update; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) priv->picture.av1.picture_parameter.ref_deltas[i] = hdr->lfp.loop_filter_ref_deltas[i]; for (i = 0; i < 2; ++i) priv->picture.av1.picture_parameter.mode_deltas[i] = hdr->lfp.loop_filter_mode_deltas[i]; /* CDEF Params */ priv->picture.av1.picture_parameter.cdef_damping_minus_3 = hdr->cdefp.cdef_damping_minus_3; priv->picture.av1.picture_parameter.cdef_bits = hdr->cdefp.cdef_bits; for (i = 0; i < AV1_MAX_CDEF_BITS_ARRAY; ++i) { priv->picture.av1.picture_parameter.cdef_y_strengths[i] = hdr->cdefp.cdef_y_strengths[i]; priv->picture.av1.picture_parameter.cdef_uv_strengths[i] = hdr->cdefp.cdef_uv_strengths[i]; } /* Loop Restoration Params */ priv->picture.av1.picture_parameter.loop_restoration_fields.yframe_restoration_type = hdr->lrp.FrameRestorationType[0]; priv->picture.av1.picture_parameter.loop_restoration_fields.cbframe_restoration_type = hdr->lrp.FrameRestorationType[1]; priv->picture.av1.picture_parameter.loop_restoration_fields.crframe_restoration_type = hdr->lrp.FrameRestorationType[2]; for (i = 0; i < 3; ++i) priv->picture.av1.picture_parameter.lr_unit_size[i] = hdr->lrp.LoopRestorationSize[i]; priv->picture.av1.picture_parameter.mode_control_fields.tx_mode = hdr->tm.TxMode; priv->picture.av1.picture_parameter.mode_control_fields.reference_select = (hdr->reference_select == REFERENCE_MODE_SELECT) ? COMPOUND_REFERENCE : SINGLE_REFERENCE; priv->picture.av1.picture_parameter.mode_control_fields.skip_mode_present = hdr->smp.skip_mode_present; priv->picture.av1.picture_parameter.pic_info_fields.allow_warped_motion = hdr->allow_warped_motion; priv->picture.av1.picture_parameter.mode_control_fields.reduced_tx_set_used = hdr->reduced_tx_set; /* Global Motion Params */ for (i = 0; i < 7; ++i) { priv->picture.av1.picture_parameter.wm[i].wmtype = hdr->gmp.GmType[i + 1]; for (j = 0; j < 6; ++j) priv->picture.av1.picture_parameter.wm[i].wmmat[j] = hdr->gmp.gm_params[i + 1][j]; } /* Film Grain Params */ priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields.apply_grain = hdr->fgp.apply_grain; priv->picture.av1.picture_parameter.film_grain_info.grain_seed = hdr->fgp.grain_seed; priv->picture.av1.picture_parameter.film_grain_info.num_y_points = hdr->fgp.num_y_points; for (i = 0; i < AV1_FG_MAX_NUM_Y_POINTS; ++i) { priv->picture.av1.picture_parameter.film_grain_info.point_y_value[i] = hdr->fgp.point_y_value[i]; priv->picture.av1.picture_parameter.film_grain_info.point_y_scaling[i] = hdr->fgp.point_y_scaling[i]; } priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. chroma_scaling_from_luma = hdr->fgp.chroma_scaling_from_luma; priv->picture.av1.picture_parameter.film_grain_info.num_cb_points = hdr->fgp.num_cb_points; priv->picture.av1.picture_parameter.film_grain_info.num_cr_points = hdr->fgp.num_cr_points; for (i = 0; i < AV1_FG_MAX_NUM_CBR_POINTS; ++i) { priv->picture.av1.picture_parameter.film_grain_info.point_cb_value[i] = hdr->fgp.point_cb_value[i]; priv->picture.av1.picture_parameter.film_grain_info.point_cb_scaling[i] = hdr->fgp.point_cb_scaling[i]; priv->picture.av1.picture_parameter.film_grain_info.point_cr_value[i] = hdr->fgp.point_cr_value[i]; priv->picture.av1.picture_parameter.film_grain_info.point_cr_scaling[i] = hdr->fgp.point_cr_scaling[i]; } priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. grain_scaling_minus_8 = hdr->fgp.grain_scaling_minus_8; priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. ar_coeff_lag = hdr->fgp.ar_coeff_lag; for (i = 0; i < AV1_FG_MAX_NUM_POS_LUMA; ++i) priv->picture.av1.picture_parameter.film_grain_info.ar_coeffs_y[i] = hdr->fgp.ar_coeffs_y[i]; for (i = 0; i < AV1_FG_MAX_NUM_POS_CHROMA; ++i) { priv->picture.av1.picture_parameter.film_grain_info.ar_coeffs_cb[i] = hdr->fgp.ar_coeffs_cb[i]; priv->picture.av1.picture_parameter.film_grain_info.ar_coeffs_cr[i] = hdr->fgp.ar_coeffs_cr[i]; } priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. ar_coeff_shift_minus_6 = hdr->fgp.ar_coeff_shift_minus_6; priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. grain_scale_shift = hdr->fgp.grain_scale_shift; priv->picture.av1.picture_parameter.film_grain_info.cb_mult = hdr->fgp.cb_mult; priv->picture.av1.picture_parameter.film_grain_info.cb_luma_mult = hdr->fgp.cb_luma_mult; priv->picture.av1.picture_parameter.film_grain_info.cb_offset = hdr->fgp.cb_offset; priv->picture.av1.picture_parameter.film_grain_info.cr_mult = hdr->fgp.cr_mult; priv->picture.av1.picture_parameter.film_grain_info.cr_luma_mult = hdr->fgp.cr_luma_mult; priv->picture.av1.picture_parameter.film_grain_info.cr_offset = hdr->fgp.cr_offset; priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. overlap_flag = hdr->fgp.overlap_flag; priv->picture.av1.picture_parameter.film_grain_info.film_grain_info_fields. clip_to_restricted_range = hdr->fgp.clip_to_restricted_range; } static void parse_tile_hdr(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned start_bits_pos, unsigned total_obu_len) { struct tile_info *ti = &(priv->codec_data.av1.uncompressed_header.ti); unsigned tg_start, tg_end; unsigned NumTiles, tileBits; bool tile_start_and_end_present_flag; unsigned size[AV1_MAX_NUM_TILES] = { 0 }; unsigned offset[AV1_MAX_NUM_TILES] = { 0 }; unsigned frame_header_size, left_size; unsigned i, j; NumTiles = ti->TileCols * ti->TileRows; tile_start_and_end_present_flag = 0; if (NumTiles > 1) tile_start_and_end_present_flag = av1_f(vlc, 1); if (NumTiles == 1 || !tile_start_and_end_present_flag) { tg_start = 0; tg_end = NumTiles - 1; } else { tileBits = ti->TileColsLog2 + ti->TileRowsLog2; tg_start = av1_f(vlc, tileBits); tg_end = av1_f(vlc, tileBits); } av1_byte_alignment(vlc); frame_header_size = (start_bits_pos - vl_vlc_bits_left(vlc)) / 8; left_size = total_obu_len - frame_header_size; for (i = tg_start; i <= tg_end; ++i) { if (i == tg_start) { offset[i] = priv->codec_data.av1.bs_obu_td_sz + priv->codec_data.av1.bs_obu_seq_sz + frame_header_size + ti->TileSizeBytes; if (tg_start == tg_end) { size[i] = left_size; for (j = 0; j < size[i]; ++j) { vl_vlc_fillbits(vlc); vl_vlc_eatbits(vlc, 8); } break; } } else { offset[i] = offset[i - 1] + ti->TileSizeBytes + size[i - 1]; left_size -= ti->TileSizeBytes + size[i - 1]; } if (i != tg_end) { size[i] = av1_le(vlc, ti->TileSizeBytes) + 1; } else { offset[i] = offset[i - 1] + size[i - 1]; size[i] = left_size; } for (j = 0; j < size[i]; ++j) { vl_vlc_fillbits(vlc); vl_vlc_eatbits(vlc, 8); } } for (i = tg_start; i <= tg_end; ++i) { priv->picture.av1.slice_parameter.slice_data_offset[i] = offset[i]; priv->picture.av1.slice_parameter.slice_data_size[i] = size[i]; } } static struct dec_av1_task *dec_av1_NeedTask(vid_dec_PrivateType *priv) { struct pipe_video_buffer templat = {}; struct dec_av1_task *task; struct vl_screen *omx_screen; struct pipe_screen *pscreen; omx_screen = priv->screen; assert(omx_screen); pscreen = omx_screen->pscreen; assert(pscreen); if (!list_is_empty(&priv->codec_data.av1.free_tasks)) { task = list_entry(priv->codec_data.av1.free_tasks.next, struct dec_av1_task, list); task->buf_ref_count = 1; list_del(&task->list); return task; } task = CALLOC_STRUCT(dec_av1_task); if (!task) return NULL; memset(&templat, 0, sizeof(templat)); templat.width = priv->codec->width; templat.height = priv->codec->height; templat.buffer_format = pscreen->get_video_param( pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_PREFERED_FORMAT ); templat.interlaced = false; task->buf = priv->pipe->create_video_buffer(priv->pipe, &templat); if (!task->buf) { FREE(task); return NULL; } task->buf_ref_count = 1; task->is_sef_task = false; return task; } static void dec_av1_ReleaseTask(vid_dec_PrivateType *priv, struct list_head *head) { if (!head || !head->next) return; list_for_each_entry_safe(struct dec_av1_task, task, head, list) { task->buf->destroy(task->buf); FREE(task); } } static void dec_av1_MoveTask(struct list_head *from, struct list_head *to) { to->prev->next = from->next; from->next->prev = to->prev; from->prev->next = to; to->prev = from->prev; list_inithead(from); } static void dec_av1_SortTask(vid_dec_PrivateType *priv) { int i; list_for_each_entry_safe(struct dec_av1_task, t, &priv->codec_data.av1.finished_tasks, list) { bool found = false; for (i = 0; i < 8; ++i) { if (t->buf == priv->picture.av1.ref[i]) { found = true; break; } } if (!found && t->buf_ref_count == 0) { list_del(&t->list); list_addtail(&t->list, &priv->codec_data.av1.free_tasks); } } } static struct dec_av1_task *dec_av1_SearchTask(vid_dec_PrivateType *priv, struct list_head *tasks) { unsigned idx = priv->codec_data.av1.uncompressed_header.frame_to_show_map_idx; list_for_each_entry_safe(struct dec_av1_task, t, tasks, list) { if (t->buf == priv->picture.av1.ref[idx]) return t; } return NULL; } static bool dec_av1_GetStartedTask(vid_dec_PrivateType *priv, struct dec_av1_task *task, struct list_head *tasks) { struct dec_av1_task *started_task; ++priv->codec_data.av1.que_num; list_addtail(&task->list, &priv->codec_data.av1.started_tasks); if (priv->codec_data.av1.que_num <= 16) return false; started_task = list_entry(priv->codec_data.av1.started_tasks.next, struct dec_av1_task, list); list_del(&started_task->list); list_addtail(&started_task->list, tasks); --priv->codec_data.av1.que_num; return true; } static void dec_av1_ShowExistingframe(vid_dec_PrivateType *priv) { struct input_buf_private *inp = priv->in_buffers[0]->pInputPortPrivate; struct dec_av1_task *task, *existing_task; bool fnd; task = CALLOC_STRUCT(dec_av1_task); if (!task) return; task->is_sef_task = true; mtx_lock(&priv->codec_data.av1.mutex); dec_av1_MoveTask(&inp->tasks, &priv->codec_data.av1.finished_tasks); dec_av1_SortTask(priv); existing_task = dec_av1_SearchTask(priv, &priv->codec_data.av1.started_tasks); if (existing_task) { ++existing_task->buf_ref_count; task->buf = existing_task->buf; task->buf_ref = &existing_task->buf; task->buf_ref_count = 0; } else { existing_task = dec_av1_SearchTask(priv, &priv->codec_data.av1.finished_tasks); if (existing_task) { struct vl_screen *omx_screen; struct pipe_screen *pscreen; struct pipe_video_buffer templat = {}; struct pipe_video_buffer *buf; struct pipe_box box={}; omx_screen = priv->screen; assert(omx_screen); pscreen = omx_screen->pscreen; assert(pscreen); memset(&templat, 0, sizeof(templat)); templat.width = priv->codec->width; templat.height = priv->codec->height; templat.buffer_format = pscreen->get_video_param( pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_PREFERED_FORMAT ); templat.interlaced = false; buf = priv->pipe->create_video_buffer(priv->pipe, &templat); if (!buf) { FREE(task); mtx_unlock(&priv->codec_data.av1.mutex); return; } box.width = priv->codec->width; box.height = priv->codec->height; box.depth = 1; priv->pipe->resource_copy_region(priv->pipe, ((struct vl_video_buffer *)buf)->resources[0], 0, 0, 0, 0, ((struct vl_video_buffer *)(existing_task->buf))->resources[0], 0, &box); box.width /= 2; box.height/= 2; priv->pipe->resource_copy_region(priv->pipe, ((struct vl_video_buffer *)buf)->resources[1], 0, 0, 0, 0, ((struct vl_video_buffer *)(existing_task->buf))->resources[1], 0, &box); priv->pipe->flush(priv->pipe, NULL, 0); existing_task->buf_ref_count = 0; task->buf = buf; task->buf_ref_count = 1; } else { FREE(task); mtx_unlock(&priv->codec_data.av1.mutex); return; } } dec_av1_SortTask(priv); fnd = dec_av1_GetStartedTask(priv, task, &inp->tasks); mtx_unlock(&priv->codec_data.av1.mutex); if (fnd) priv->frame_finished = 1; } static struct dec_av1_task *dec_av1_BeginFrame(vid_dec_PrivateType *priv) { struct input_buf_private *inp = priv->in_buffers[0]->pInputPortPrivate; struct dec_av1_task *task; if (priv->frame_started) return NULL; if (!priv->codec) { struct vl_screen *omx_screen; struct pipe_screen *pscreen; struct pipe_video_codec templat = {}; bool supported; omx_screen = priv->screen; assert(omx_screen); pscreen = omx_screen->pscreen; assert(pscreen); supported = vl_codec_supported(pscreen, priv->profile, false); assert(supported && "AV1 is not supported"); templat.profile = priv->profile; templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM; templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; templat.max_references = AV1_NUM_REF_FRAMES; templat.expect_chunked_decode = true; omx_base_video_PortType *port; port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX]; templat.width = port->sPortParam.format.video.nFrameWidth; templat.height = port->sPortParam.format.video.nFrameHeight; priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat); } mtx_lock(&priv->codec_data.av1.mutex); dec_av1_MoveTask(&inp->tasks, &priv->codec_data.av1.finished_tasks); dec_av1_SortTask(priv); mtx_unlock(&priv->codec_data.av1.mutex); task = dec_av1_NeedTask(priv); if (!task) return NULL; priv->codec->begin_frame(priv->codec, task->buf, &priv->picture.base); priv->frame_started = true; return task; } static void dec_av1_EndFrame(vid_dec_PrivateType *priv, struct dec_av1_task *task) { struct input_buf_private *inp = priv->in_buffers[0]->pInputPortPrivate; unsigned refresh_frame_flags; bool fnd; unsigned i; if (!priv->frame_started || ! task) return; priv->codec->end_frame(priv->codec, task->buf, &priv->picture.base); priv->frame_started = false; refresh_frame_flags = priv->codec_data.av1.uncompressed_header.refresh_frame_flags; for (i = 0; i < AV1_NUM_REF_FRAMES; ++i) { if (refresh_frame_flags & (1 << i)) { memcpy(&priv->codec_data.av1.refs[i], &priv->codec_data.av1.uncompressed_header, sizeof(struct av1_uncompressed_header_obu)); priv->picture.av1.ref[i] = task->buf; priv->codec_data.av1.RefFrames[i].RefFrameType = priv->codec_data.av1.uncompressed_header.frame_type; priv->codec_data.av1.RefFrames[i].RefFrameId = priv->codec_data.av1.uncompressed_header.current_frame_id; priv->codec_data.av1.RefFrames[i].RefUpscaledWidth = priv->codec_data.av1.uncompressed_header.UpscaledWidth; priv->codec_data.av1.RefFrames[i].RefFrameWidth = priv->codec_data.av1.uncompressed_header.FrameWidth; priv->codec_data.av1.RefFrames[i].RefFrameHeight = priv->codec_data.av1.uncompressed_header.FrameHeight; priv->codec_data.av1.RefFrames[i].RefRenderWidth = priv->codec_data.av1.uncompressed_header.RenderWidth; priv->codec_data.av1.RefFrames[i].RefRenderHeight = priv->codec_data.av1.uncompressed_header.RenderHeight; } } if (!priv->picture.av1.picture_parameter.pic_info_fields.show_frame) task->no_show_frame = true; mtx_lock(&priv->codec_data.av1.mutex); fnd = dec_av1_GetStartedTask(priv, task, &priv->codec_data.av1.decode_tasks); if (!fnd) { mtx_unlock(&priv->codec_data.av1.mutex); return; } if (!priv->codec_data.av1.stacked_frame) dec_av1_MoveTask(&priv->codec_data.av1.decode_tasks, &inp->tasks); mtx_unlock(&priv->codec_data.av1.mutex); priv->frame_finished = 1; } static void dec_av1_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left) { unsigned start_bits_pos = vl_vlc_bits_left(vlc); unsigned start_bits = vl_vlc_valid_bits(vlc); unsigned start_bytes = start_bits / 8; const void *obu_data = vlc->data; uint8_t start_buf[8]; unsigned num_buffers = 0; void * const * buffers[4]; unsigned sizes[4]; unsigned obu_size = 0; unsigned total_obu_len; enum av1_obu_type type; bool obu_extension_flag; bool obu_has_size_field; unsigned i; for (i = 0; i < start_bytes; ++i) start_buf[i] = vl_vlc_peekbits(vlc, start_bits) >> ((start_bytes - i - 1) * 8); /* obu header */ av1_f(vlc, 1); /* obu_forbidden_bit */ type = av1_f(vlc, 4); obu_extension_flag = av1_f(vlc, 1); obu_has_size_field = av1_f(vlc, 1); av1_f(vlc, 1); /* obu_reserved_1bit */ if (obu_extension_flag) { priv->codec_data.av1.ext.temporal_id = av1_f(vlc, 3); priv->codec_data.av1.ext.spatial_id = av1_f(vlc, 2); av1_f(vlc, 3); /* extension_header_reserved_3bits */ } obu_size = (obu_has_size_field) ? av1_uleb128(vlc) : (priv->sizes[0] - (unsigned)obu_extension_flag - 1); total_obu_len = (start_bits_pos - vl_vlc_bits_left(vlc)) / 8 + obu_size; switch (type) { case AV1_OBU_SEQUENCE_HEADER: { sequence_header_obu(priv, vlc); av1_byte_alignment(vlc); priv->codec_data.av1.bs_obu_seq_sz = total_obu_len; memcpy(priv->codec_data.av1.bs_obu_seq_buf, start_buf, start_bytes); memcpy(priv->codec_data.av1.bs_obu_seq_buf + start_bytes, obu_data, total_obu_len - start_bytes); break; } case AV1_OBU_TEMPORAL_DELIMITER: av1_byte_alignment(vlc); priv->codec_data.av1.bs_obu_td_sz = total_obu_len; memcpy(priv->codec_data.av1.bs_obu_td_buf, start_buf, total_obu_len); break; case AV1_OBU_FRAME_HEADER: frame_header_obu(priv, vlc); if (priv->codec_data.av1.uncompressed_header.show_existing_frame) dec_av1_ShowExistingframe(priv); av1_byte_alignment(vlc); break; case AV1_OBU_FRAME: { struct dec_av1_task *task; frame_header_obu(priv, vlc); av1_byte_alignment(vlc); parse_tile_hdr(priv, vlc, start_bits_pos, total_obu_len); av1_byte_alignment(vlc); task = dec_av1_BeginFrame(priv); if (!task) return; if (priv->codec_data.av1.bs_obu_td_sz) { buffers[num_buffers] = (void *)priv->codec_data.av1.bs_obu_td_buf; sizes[num_buffers++] = priv->codec_data.av1.bs_obu_td_sz; priv->codec_data.av1.bs_obu_td_sz = 0; } if (priv->codec_data.av1.bs_obu_seq_sz) { buffers[num_buffers] = (void *)priv->codec_data.av1.bs_obu_seq_buf; sizes[num_buffers++] = priv->codec_data.av1.bs_obu_seq_sz; priv->codec_data.av1.bs_obu_seq_sz = 0; } buffers[num_buffers] = (void *)start_buf; sizes[num_buffers++] = start_bytes; buffers[num_buffers] = (void *)obu_data; sizes[num_buffers++] = total_obu_len - start_bytes; priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base, num_buffers, (const void * const*)buffers, sizes); priv->codec_data.av1.stacked_frame = (vl_vlc_bits_left(vlc) > min_bits_left) ? true : false; dec_av1_EndFrame(priv, task); break; } default: av1_byte_alignment(vlc); break; } return; } OMX_ERRORTYPE vid_dec_av1_AllocateInBuffer(omx_base_PortType *port, OMX_INOUT OMX_BUFFERHEADERTYPE **buf, OMX_IN OMX_U32 idx, OMX_IN OMX_PTR private, OMX_IN OMX_U32 size) { struct input_buf_private *inp; OMX_ERRORTYPE r; r = base_port_AllocateBuffer(port, buf, idx, private, size); if (r) return r; inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private); if (!inp) { base_port_FreeBuffer(port, idx, *buf); return OMX_ErrorInsufficientResources; } list_inithead(&inp->tasks); return OMX_ErrorNone; } OMX_ERRORTYPE vid_dec_av1_UseInBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE **buf, OMX_U32 idx, OMX_PTR private, OMX_U32 size, OMX_U8 *mem) { struct input_buf_private *inp; OMX_ERRORTYPE r; r = base_port_UseBuffer(port, buf, idx, private, size, mem); if (r) return r; inp = (*buf)->pInputPortPrivate = CALLOC_STRUCT(input_buf_private); if (!inp) { base_port_FreeBuffer(port, idx, *buf); return OMX_ErrorInsufficientResources; } list_inithead(&inp->tasks); return OMX_ErrorNone; } void vid_dec_av1_FreeInputPortPrivate(vid_dec_PrivateType *priv, OMX_BUFFERHEADERTYPE *buf) { struct input_buf_private *inp = buf->pInputPortPrivate; if (!inp || !inp->tasks.next) return; list_for_each_entry_safe(struct dec_av1_task, task, &inp->tasks, list) { task->buf->destroy(task->buf); FREE(task); } } void vid_dec_av1_ReleaseTasks(vid_dec_PrivateType *priv) { dec_av1_ReleaseTask(priv, &priv->codec_data.av1.free_tasks); dec_av1_ReleaseTask(priv, &priv->codec_data.av1.started_tasks); dec_av1_ReleaseTask(priv, &priv->codec_data.av1.decode_tasks); dec_av1_ReleaseTask(priv, &priv->codec_data.av1.finished_tasks); mtx_destroy(&priv->codec_data.av1.mutex); } void vid_dec_av1_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output) { vid_dec_PrivateType *priv = comp->pComponentPrivate; bool eos = !!(input->nFlags & OMX_BUFFERFLAG_EOS); struct input_buf_private *inp = input->pInputPortPrivate; struct dec_av1_task *task; bool stacked = false; mtx_lock(&priv->codec_data.av1.mutex); if (list_length(&inp->tasks) > 1) stacked = true; if (list_is_empty(&inp->tasks)) { task = list_entry(priv->codec_data.av1.started_tasks.next, struct dec_av1_task, list); list_del(&task->list); list_addtail(&task->list, &inp->tasks); --priv->codec_data.av1.que_num; } task = list_entry(inp->tasks.next, struct dec_av1_task, list); if (!task->no_show_frame) { vid_dec_FillOutput(priv, task->buf, output); output->nFilledLen = output->nAllocLen; output->nTimeStamp = input->nTimeStamp; } else { task->no_show_frame = false; output->nFilledLen = 0; } if (task->is_sef_task) { if (task->buf_ref_count == 0) { struct dec_av1_task *t = container_of(task->buf_ref, struct dec_av1_task, buf); list_del(&task->list); t->buf_ref_count--; list_del(&t->list); list_addtail(&t->list, &priv->codec_data.av1.finished_tasks); } else if (task->buf_ref_count == 1) { list_del(&task->list); task->buf->destroy(task->buf); task->buf_ref_count--; } FREE(task); } else { if (task->buf_ref_count == 1) { list_del(&task->list); list_addtail(&task->list, &priv->codec_data.av1.finished_tasks); task->buf_ref_count--; } else if (task->buf_ref_count == 2) { list_del(&task->list); task->buf_ref_count--; list_addtail(&task->list, &priv->codec_data.av1.finished_tasks); } } if (eos && input->pInputPortPrivate) { if (!priv->codec_data.av1.que_num) input->nFilledLen = 0; else vid_dec_av1_FreeInputPortPrivate(priv, input); } else { if (!stacked) input->nFilledLen = 0; } mtx_unlock(&priv->codec_data.av1.mutex); } void vid_dec_av1_Init(vid_dec_PrivateType *priv) { priv->picture.base.profile = PIPE_VIDEO_PROFILE_AV1_MAIN; priv->Decode = dec_av1_Decode; list_inithead(&priv->codec_data.av1.free_tasks); list_inithead(&priv->codec_data.av1.started_tasks); list_inithead(&priv->codec_data.av1.decode_tasks); list_inithead(&priv->codec_data.av1.finished_tasks); (void)mtx_init(&priv->codec_data.av1.mutex, mtx_plain); }