text: /**************************************************************************
   *
   * 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 "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 <AV1_MAX_TILE_ROWS; ++i)
        priv->picture.av1.picture_parameter.tile_row_start_sb[i] =
           hdr->ti.tile_row_start_sb[i];
     for (i = 0; i <AV1_MAX_TILE_COLS; ++i)
        priv->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(struct dec_av1_task,
              priv->codec_data.av1.free_tasks.next, 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(struct dec_av1_task,
        priv->codec_data.av1.started_tasks.next, 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 = pscreen->get_video_param(pscreen, priv->profile,
              PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_SUPPORTED);
        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(struct dec_av1_task,
              priv->codec_data.av1.started_tasks.next, list);
        list_del(&task->list);
        list_addtail(&task->list, &inp->tasks);
        --priv->codec_data.av1.que_num;
     }
  
     task = LIST_ENTRY(struct dec_av1_task, inp->tasks.next, 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);
  }
  