/* gstav1parser.c
 *
 *  Copyright (C) 2018 Georg Ottinger
 *  Copyright (C) 2019-2020 Intel Corporation
 *    Author: Georg Ottinger <g.ottinger@gmx.at>
 *    Author: Junyan He <junyan.he@hotmail.com>
 *    Author: Victor Jaquez <vjaquez@igalia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
/**
 * SECTION:gstav1parser
 * @title: GstAV1Parser
 * @short_description: Convenience library for parsing AV1 video bitstream.
 *
 * For more details about the structures, you can refer to the AV1 Bitstream &
 * Decoding Process Specification V1.0.0
 * [specification](https://aomediacodec.github.io/av1-spec/av1-spec.pdf)
 *
 * It offers you bitstream parsing of low overhead bistream format (Section 5)
 * or Annex B according to the setting of the parser. By calling the function of
 * gst_av1_parser_reset(), user can switch between bistream mode and Annex B mode.
 *
 * To retrieve OBUs and parse its headers, you should firstly call the function of
 * gst_av1_parser_identify_one_obu() to get the OBU type if succeeds or just discard
 * the data if fails.
 *
 * Then, depending on the #GstAV1OBUType of the newly parsed #GstAV1OBU,
 * you should call the differents functions to parse the structure details:
 *
 *   * #GST_AV1_OBU_SEQUENCE_HEADER: gst_av1_parser_parse_sequence_header_obu()
 *
 *   * #GST_AV1_OBU_TEMPORAL_DELIMITER: gst_av1_parser_parse_temporal_delimiter_obu()
 *
 *   * #GST_AV1_OBU_FRAME: gst_av1_parser_parse_frame_obu()
 *
 *   * #GST_AV1_OBU_FRAME_HEADER: gst_av1_parser_parse_frame_header_obu()
 *
 *   * #GST_AV1_OBU_TILE_GROUP: gst_av1_parser_parse_tile_group_obu()
 *
 *   * #GST_AV1_OBU_METADATA: gst_av1_parser_parse_metadata_obu()
 *
 *   * #GST_AV1_OBU_REDUNDANT_FRAME_HEADER: gst_av1_parser_parse_frame_header_obu()
 *
 *   * #GST_AV1_OBU_TILE_LIST: gst_av1_parser_parse_tile_list_obu()
 *
 * Note: Some parser functions are dependent on information provided in the sequence
 * header and reference frame's information. It maintains a state inside itself, which
 * contains all global vars and reference information during the whole parsing process.
 * Calling gst_av1_parser_reset() or a new sequence's arriving can clear and reset this
 * inside state.
 *
 * After successfully handled a frame(for example, decode a frame successfully), you
 * should call gst_av1_parser_reference_frame_update() to update the parser's inside
 * state(such as reference information, global segmentation information, etc).
 *
 * Note: If the frame is actived by show_existing_frame in #GST_AV1_OBU_FRAME_HEADER,
 * the function of gst_av1_parser_reference_frame_loading() should be called before
 * really showing that frame.
 *
 * @since: 1.18.00
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gstav1parser.h"

#include <gst/base/gstbitreader.h>

#include <string.h>
#include <stdlib.h>

#ifndef GST_DISABLE_GST_DEBUG
#define GST_CAT_DEFAULT gst_av1_debug_category_get ()
static GstDebugCategory *
gst_av1_debug_category_get (void)
{
  static gsize cat_gonce = 0;

  if (g_once_init_enter (&cat_gonce)) {
    GstDebugCategory *cat = NULL;

    GST_DEBUG_CATEGORY_INIT (cat, "codecparsers_av1", 0, "av1 parse library");

    g_once_init_leave (&cat_gonce, (gsize) cat);
  }

  return (GstDebugCategory *) cat_gonce;
}
#endif /* GST_DISABLE_GST_DEBUG */

#define AV1_READ_BIT(br)    ((guint8) gst_bit_reader_get_bits_uint32_unchecked (br, 1))
#define AV1_READ_UINT8(br)  ((guint8) gst_bit_reader_get_bits_uint32_unchecked (br, 8))
#define AV1_READ_UINT16(br) ((guint16) gst_bit_reader_get_bits_uint32_unchecked (br, 16))
#define AV1_READ_UINT32(br) gst_bit_reader_get_bits_uint32_unchecked (br, 32)
#define AV1_READ_UINT64(br) gst_bit_reader_get_bits_uint64_unchecked (br, 64)
#define AV1_READ_BITS(br, nbits)                                        \
  ((nbits <= 32) ? (gst_bit_reader_get_bits_uint32_unchecked (br, nbits)) : \
   (gst_bit_reader_get_bits_uint64_unchecked (br, nbits)))

static guint64
av1_read_bits_checked (GstBitReader * br, guint nbits,
    GstAV1ParserResult * retval, const char *func_name, gint line)
{
  guint64 read_bits = 0;
  gboolean result;

  if (nbits <= 64)
    result = gst_bit_reader_get_bits_uint64 (br, &read_bits, nbits);
  else
    result = FALSE;

  if (result == TRUE) {
    *retval = GST_AV1_PARSER_OK;
    return read_bits;
  } else {
    *retval = GST_AV1_PARSER_NO_MORE_DATA;
    GST_WARNING ("Read %d bits failed in func: %s, line %d", nbits, func_name,
        line);
    return 0;
  }
}

#define AV1_READ_BIT_CHECKED(br, ret)                                   \
  ((guint8) av1_read_bits_checked (br, 1, ret, __func__, __LINE__))
#define AV1_READ_UINT8_CHECKED(br, ret)                                 \
  ((guint8) av1_read_bits_checked (br, 8, ret, __func__, __LINE__))
#define AV1_READ_UINT16_CHECKED(br, ret)                                \
  ((guint16) av1_read_bits_checked (br, 16, ret, __func__, __LINE__))
#define AV1_READ_UINT32_CHECKED(br, ret)                                \
  ((guint32) av1_read_bits_checked (br, 32, ret, __func__, __LINE__))
#define AV1_READ_BITS_CHECKED(br, nbits, ret)                   \
  av1_read_bits_checked (br, nbits, ret, __func__, __LINE__)

#define AV1_REMAINING_BYTES(br) (gst_bit_reader_get_remaining (br) / 8)
#define AV1_REMAINING_BITS(br)  (gst_bit_reader_get_remaining (br))

/*************************************
 *                                   *
 * Helperfunctions                   *
 *                                   *
 *************************************/

/* 4.7
 *
 * floor of the base 2 logarithm of the input x */
static gint
av1_helpers_floor_log2 (guint32 x)
{
  gint s = 0;

  while (x != 0) {
    x = x >> 1;
    s++;
  }
  return s - 1;
}

/* 5.9.16 Tile size calculation
 *
 * returns the smallest value for k such that blkSize << k is greater
 * than or equal to target */
static gint
av1_helper_tile_log2 (gint blkSize, gint target)
{
  gint k;
  for (k = 0; (blkSize << k) < target; k++);
  return k;
}

/* 5.9.29 */
static gint
av1_helper_inverse_recenter (gint r, gint v)
{
  if (v > 2 * r)
    return v;
  else if (v & 1)
    return r - ((v + 1) >> 1);
  else
    return r + (v >> 1);
}

/* Shift down with rounding for use when n >= 0, value >= 0 */
static guint64
av1_helper_round_power_of_two (guint64 value, guint16 n)
{
  return (value + (((guint64) (1) << n) >> 1)) >> n;
}

 /* Shift down with rounding for signed integers, for use when n >= 0 */
static gint64
av1_helper_round_power_of_two_signed (gint64 value, guint16 n)
{
  return (value < 0) ? -((gint64) (av1_helper_round_power_of_two (-value, n)))
      : (gint64) av1_helper_round_power_of_two (value, n);
}

static gint
av1_helper_msb (guint n)
{
  int log = 0;
  guint value = n;
  int i;

  g_assert (n != 0);

  for (i = 4; i >= 0; --i) {
    const gint shift = (1 << i);
    const guint x = value >> shift;
    if (x != 0) {
      value = x;
      log += shift;
    }
  }
  return log;
}

static const guint16 div_lut[GST_AV1_DIV_LUT_NUM + 1] = {
  16384, 16320, 16257, 16194, 16132, 16070, 16009, 15948, 15888, 15828, 15768,
  15709, 15650, 15592, 15534, 15477, 15420, 15364, 15308, 15252, 15197, 15142,
  15087, 15033, 14980, 14926, 14873, 14821, 14769, 14717, 14665, 14614, 14564,
  14513, 14463, 14413, 14364, 14315, 14266, 14218, 14170, 14122, 14075, 14028,
  13981, 13935, 13888, 13843, 13797, 13752, 13707, 13662, 13618, 13574, 13530,
  13487, 13443, 13400, 13358, 13315, 13273, 13231, 13190, 13148, 13107, 13066,
  13026, 12985, 12945, 12906, 12866, 12827, 12788, 12749, 12710, 12672, 12633,
  12596, 12558, 12520, 12483, 12446, 12409, 12373, 12336, 12300, 12264, 12228,
  12193, 12157, 12122, 12087, 12053, 12018, 11984, 11950, 11916, 11882, 11848,
  11815, 11782, 11749, 11716, 11683, 11651, 11619, 11586, 11555, 11523, 11491,
  11460, 11429, 11398, 11367, 11336, 11305, 11275, 11245, 11215, 11185, 11155,
  11125, 11096, 11067, 11038, 11009, 10980, 10951, 10923, 10894, 10866, 10838,
  10810, 10782, 10755, 10727, 10700, 10673, 10645, 10618, 10592, 10565, 10538,
  10512, 10486, 10460, 10434, 10408, 10382, 10356, 10331, 10305, 10280, 10255,
  10230, 10205, 10180, 10156, 10131, 10107, 10082, 10058, 10034, 10010, 9986,
  9963, 9939, 9916, 9892, 9869, 9846, 9823, 9800, 9777, 9754, 9732,
  9709, 9687, 9664, 9642, 9620, 9598, 9576, 9554, 9533, 9511, 9489,
  9468, 9447, 9425, 9404, 9383, 9362, 9341, 9321, 9300, 9279, 9259,
  9239, 9218, 9198, 9178, 9158, 9138, 9118, 9098, 9079, 9059, 9039,
  9020, 9001, 8981, 8962, 8943, 8924, 8905, 8886, 8867, 8849, 8830,
  8812, 8793, 8775, 8756, 8738, 8720, 8702, 8684, 8666, 8648, 8630,
  8613, 8595, 8577, 8560, 8542, 8525, 8508, 8490, 8473, 8456, 8439,
  8422, 8405, 8389, 8372, 8355, 8339, 8322, 8306, 8289, 8273, 8257,
  8240, 8224, 8208, 8192,
};

static gint16
av1_helper_resolve_divisor_32 (guint32 D, gint16 * shift)
{
  gint32 f;
  gint32 e;

  *shift = av1_helper_msb (D);
  // e is obtained from D after resetting the most significant 1 bit.
  e = D - ((guint32) 1 << *shift);
  // Get the most significant DIV_LUT_BITS (8) bits of e into f
  if (*shift > GST_AV1_DIV_LUT_BITS)
    f = av1_helper_round_power_of_two (e, *shift - GST_AV1_DIV_LUT_BITS);
  else
    f = e << (GST_AV1_DIV_LUT_BITS - *shift);
  g_assert (f <= GST_AV1_DIV_LUT_NUM);
  *shift += GST_AV1_DIV_LUT_PREC_BITS;
  // Use f as lookup into the precomputed table of multipliers
  return div_lut[f];
}

/*************************************
 *                                   *
 * Bitstream Functions               *
 *                                   *
 *************************************/
/* 4.10.5
 *
 * Unsigned integer represented by a variable number of little-endian
 * bytes. */
static guint32
av1_bitstreamfn_leb128 (GstBitReader * br, GstAV1ParserResult * retval)
{
  guint8 leb128_byte = 0;
  guint64 value = 0;
  gint i;

  for (i = 0; i < 8; i++) {
    leb128_byte = AV1_READ_UINT8_CHECKED (br, retval);
    if (*retval != GST_AV1_PARSER_OK)
      return 0;

    value |= (((gint) leb128_byte & 0x7f) << (i * 7));
    if (!(leb128_byte & 0x80))
      break;
  }

  /* check for bitstream conformance see chapter4.10.5 */
  if (value < G_MAXUINT32) {
    return (guint32) value;
  } else {
    GST_WARNING ("invalid leb128");
    *retval = GST_AV1_PARSER_BITSTREAM_ERROR;
    return 0;
  }
}

/* 4.10.3
 *
 * Variable length unsigned n-bit number appearing directly in the
 * bitstream */
static guint32
av1_bitstreamfn_uvlc (GstBitReader * br, GstAV1ParserResult * retval)
{
  guint8 leadingZero = 0;
  guint32 readv;
  guint32 value;
  gboolean done;

  while (1) {
    done = AV1_READ_BIT_CHECKED (br, retval);
    if (*retval != GST_AV1_PARSER_OK) {
      GST_WARNING ("invalid uvlc");
      return 0;
    }

    if (done)
      break;
    leadingZero++;
  }

  if (leadingZero >= 32) {
    value = G_MAXUINT32;
    return value;
  }
  readv = AV1_READ_BITS_CHECKED (br, leadingZero, retval);
  if (*retval != GST_AV1_PARSER_OK) {
    GST_WARNING ("invalid uvlc");
    return 0;
  }

  value = readv + (1 << leadingZero) - 1;

  return value;
}

/* 4.10.6
 *
 * Signed integer converted from an n bits unsigned integer in the
 * bitstream */
static guint32
av1_bitstreamfn_su (GstBitReader * br, guint8 n, GstAV1ParserResult * retval)
{
  guint32 v, signMask;

  v = AV1_READ_BITS_CHECKED (br, n, retval);
  if (*retval != GST_AV1_PARSER_OK)
    return 0;

  signMask = 1 << (n - 1);
  if (v & signMask)
    return v - 2 * signMask;
  else
    return v;
}

/* 4.10.7
 *
 * Unsigned encoded integer with maximum number of values n */
static guint32
av1_bitstreamfn_ns (GstBitReader * br, guint32 n, GstAV1ParserResult * retval)
{
  gint w, m, v;
  gint extra_bit;

  w = av1_helpers_floor_log2 (n) + 1;
  m = (1 << w) - n;
  v = AV1_READ_BITS_CHECKED (br, w - 1, retval);
  if (*retval != GST_AV1_PARSER_OK)
    return 0;

  if (v < m)
    return v;
  extra_bit = AV1_READ_BITS_CHECKED (br, 1, retval);
  if (*retval != GST_AV1_PARSER_OK)
    return 0;

  return (v << 1) - m + extra_bit;
}

/* 4.10.4
 *
 * Unsigned little-endian n-byte number appearing directly in the
 * bitstream */
static guint
av1_bitstreamfn_le (GstBitReader * br, guint8 n, GstAV1ParserResult * retval)
{
  guint t = 0;
  guint8 byte;
  gint i;

  for (i = 0; i < n; i++) {
    byte = AV1_READ_BITS_CHECKED (br, 8, retval);
    if (*retval != GST_AV1_PARSER_OK)
      return 0;

    t += (byte << (i * 8));
  }
  return t;
}

/* 5.9.13
 *
 * Delta quantizer */
static gint8
av1_bitstreamfn_delta_q (GstBitReader * br, GstAV1ParserResult * retval)
{
  guint8 delta_coded;

  delta_coded = AV1_READ_BIT_CHECKED (br, retval);
  if (*retval != GST_AV1_PARSER_OK)
    return 0;

  if (delta_coded) {
    gint delta_q = av1_bitstreamfn_su (br, 7, retval);
    if (*retval != GST_AV1_PARSER_OK)
      return 0;
    return delta_q;
  } else {
    return 0;
  }

  return 0;
}

/* 5.3.4 */
static GstAV1ParserResult
av1_bitstreamfn_trailing_bits (GstBitReader * br, guint32 nbBits)
{
  guint8 trailing_one_bit, trailing_zero_bit;

  g_assert (nbBits);

  trailing_one_bit = AV1_READ_BIT (br);
  if (trailing_one_bit != 1) {
    return GST_AV1_PARSER_BITSTREAM_ERROR;
  }

  nbBits--;
  while (nbBits > 0) {
    trailing_zero_bit = AV1_READ_BIT (br);
    if (trailing_zero_bit != 0)
      return GST_AV1_PARSER_BITSTREAM_ERROR;
    nbBits--;
  }

  return GST_AV1_PARSER_OK;
}

static GstAV1ParserResult
av1_skip_trailing_bits (GstAV1Parser * parser, GstBitReader * br,
    GstAV1OBU * obu)
{
  guint32 payloadBits = gst_bit_reader_get_pos (br);
  GstAV1ParserResult ret;

  if (obu->obu_size > 0
      && obu->obu_type != GST_AV1_OBU_TILE_GROUP
      && obu->obu_type != GST_AV1_OBU_TILE_LIST
      && obu->obu_type != GST_AV1_OBU_FRAME) {
    if (payloadBits >= obu->obu_size * 8)
      return GST_AV1_PARSER_NO_MORE_DATA;

    ret = av1_bitstreamfn_trailing_bits (br, obu->obu_size * 8 - payloadBits);
    if (ret != GST_AV1_PARSER_OK)
      return ret;
  }
  return GST_AV1_PARSER_OK;
}

static gboolean
av1_seq_level_idx_is_valid (GstAV1SeqLevels seq_level_idx)
{
  return seq_level_idx == GST_AV1_SEQ_LEVEL_MAX
      || (seq_level_idx < GST_AV1_SEQ_LEVELS
      /* The following levels are currently undefined. */
      && seq_level_idx != GST_AV1_SEQ_LEVEL_2_2
      && seq_level_idx != GST_AV1_SEQ_LEVEL_2_3
      && seq_level_idx != GST_AV1_SEQ_LEVEL_3_2
      && seq_level_idx != GST_AV1_SEQ_LEVEL_3_3
      && seq_level_idx != GST_AV1_SEQ_LEVEL_4_2
      && seq_level_idx != GST_AV1_SEQ_LEVEL_4_3
      && seq_level_idx != GST_AV1_SEQ_LEVEL_7_0
      && seq_level_idx != GST_AV1_SEQ_LEVEL_7_1
      && seq_level_idx != GST_AV1_SEQ_LEVEL_7_2
      && seq_level_idx != GST_AV1_SEQ_LEVEL_7_3);
}

static void
av1_parser_init_sequence_header (GstAV1SequenceHeaderOBU * seq_header)
{
  memset (seq_header, 0, sizeof (*seq_header));
  seq_header->bit_depth = 8;
  seq_header->num_planes = 1;
}

/*************************************
 *                                   *
 * Parser Functions                  *
 *                                   *
 *************************************/
static void
gst_av1_parse_reset_state (GstAV1Parser * parser, gboolean free_sps)
{
  parser->state.begin_first_frame = FALSE;

  parser->state.prev_frame_id = 0;
  parser->state.current_frame_id = 0;
  memset (&parser->state.ref_info, 0, sizeof (parser->state.ref_info));
  parser->state.frame_width = 0;
  parser->state.frame_height = 0;
  parser->state.upscaled_width = 0;
  parser->state.mi_cols = 0;
  parser->state.mi_rows = 0;
  parser->state.render_width = 0;
  parser->state.render_height = 0;

  memset (parser->state.mi_col_starts, 0, sizeof (parser->state.mi_col_starts));
  memset (parser->state.mi_row_starts, 0, sizeof (parser->state.mi_row_starts));

  parser->state.tile_cols_log2 = 0;
  parser->state.tile_cols = 0;
  parser->state.tile_rows_log2 = 0;
  parser->state.tile_rows = 0;
  parser->state.tile_size_bytes = 0;

  parser->state.seen_frame_header = 0;

  if (free_sps) {
    parser->state.sequence_changed = FALSE;

    if (parser->seq_header) {
      g_slice_free (GstAV1SequenceHeaderOBU, parser->seq_header);
      parser->seq_header = NULL;
    }
  }
}

/**
 * gst_av1_parser_reset:
 * @parser: the #GstAV1Parser
 * @annex_b: indicate whether conforms to annex b
 *
 * Reset the current #GstAV1Parser's state totally.
 *
 * Since: 1.18
 */
void
gst_av1_parser_reset (GstAV1Parser * parser, gboolean annex_b)
{
  g_return_if_fail (parser != NULL);

  parser->annex_b = annex_b;
  if (parser->annex_b)
    gst_av1_parser_reset_annex_b (parser);

  gst_av1_parse_reset_state (parser, TRUE);
}

/**
 * gst_av1_parser_reset_annex_b:
 * @parser: the #GstAV1Parser
 *
 * Only reset the current #GstAV1Parser's annex b context.
 * The other part of the state is kept.
 *
 * Since: 1.20
 */
void
gst_av1_parser_reset_annex_b (GstAV1Parser * parser)
{
  g_return_if_fail (parser != NULL);
  g_return_if_fail (parser->annex_b);

  if (parser->temporal_unit_consumed < parser->temporal_unit_size)
    GST_DEBUG ("temporal_unit_consumed: %d, temporal_unit_size:%d, "
        "discard the left %d bytes for a temporal_unit.",
        parser->temporal_unit_consumed, parser->temporal_unit_size,
        parser->temporal_unit_size - parser->temporal_unit_consumed);

  if (parser->frame_unit_consumed < parser->frame_unit_size)
    GST_DEBUG (" frame_unit_consumed %d, frame_unit_size: %d "
        "discard the left %d bytes for a frame_unit.",
        parser->frame_unit_consumed, parser->frame_unit_size,
        parser->frame_unit_size - parser->frame_unit_consumed);

  parser->temporal_unit_consumed = 0;
  parser->temporal_unit_size = 0;
  parser->frame_unit_consumed = 0;
  parser->frame_unit_size = 0;
}

/* 5.3.2 */
static GstAV1ParserResult
gst_av1_parse_obu_header (GstAV1Parser * parser, GstBitReader * br,
    GstAV1OBUHeader * obu_header)
{
  guint8 obu_forbidden_bit;
  guint8 obu_reserved_1bit;
  guint8 obu_extension_header_reserved_3bits;
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;

  if (AV1_REMAINING_BYTES (br) < 1) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  obu_forbidden_bit = AV1_READ_BIT (br);
  if (obu_forbidden_bit != 0) {
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  obu_header->obu_type = AV1_READ_BITS (br, 4);
  obu_header->obu_extention_flag = AV1_READ_BIT (br);
  obu_header->obu_has_size_field = AV1_READ_BIT (br);
  obu_reserved_1bit = AV1_READ_BIT (br);
  if (obu_reserved_1bit != 0) {
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  if (obu_header->obu_extention_flag) {
    if (AV1_REMAINING_BYTES (br) < 1) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }

    /* 5.3.3 OBU extension header */
    obu_header->obu_temporal_id = AV1_READ_BITS (br, 3);
    obu_header->obu_spatial_id = AV1_READ_BITS (br, 2);
    obu_extension_header_reserved_3bits = AV1_READ_BITS (br, 3);
    if (obu_extension_header_reserved_3bits != 0) {
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse OBU header error %d", ret);
  return ret;
}

/**
 * gst_av1_parser_identify_one_obu:
 * @parser: the #GstAV1Parser
 * @data: the data to parse
 * @size: the size of @data
 * @obu: a #GstAV1OBU to store the identified result
 * @consumed: (out): the consumed data size
 *
 * Identify one @obu's type from the incoming data stream. This function
 * should be called first to know the type of @obu before other parse APIs.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_identify_one_obu (GstAV1Parser * parser, const guint8 * data,
    guint32 size, GstAV1OBU * obu, guint32 * consumed)
{
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;
  GstBitReader br;
  guint obu_length = 0;
  guint32 used;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (data != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (consumed != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  *consumed = 0;
  memset (obu, 0, sizeof (*obu));

  if (parser->annex_b) {
    GST_LOG ("temporal_unit_consumed: %d, temporal_unit_size:%d,"
        " frame_unit_consumed %d, frame_unit_size: %d",
        parser->temporal_unit_consumed, parser->temporal_unit_size,
        parser->frame_unit_consumed, parser->frame_unit_size);
  }

  if (!size) {
    return ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  /* parse the data size if annex_b */
  if (parser->annex_b) {
    guint last_pos;
  annex_b_again:
    last_pos = 0;

    if (*consumed > size)
      goto error;
    if (*consumed == size) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    gst_bit_reader_init (&br, data + *consumed, size - *consumed);

    if (parser->temporal_unit_consumed > parser->temporal_unit_size)
      goto error;

    if (parser->temporal_unit_consumed &&
        parser->temporal_unit_consumed == parser->temporal_unit_size) {
      GST_LOG ("Complete a temporal unit of size %d",
          parser->temporal_unit_size);
      parser->temporal_unit_consumed = parser->temporal_unit_size = 0;
    }

    if (parser->temporal_unit_size == 0) {
      parser->temporal_unit_size = av1_bitstreamfn_leb128 (&br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;

      g_assert (gst_bit_reader_get_pos (&br) % 8 == 0);
      used = (gst_bit_reader_get_pos (&br) / 8 - last_pos);
      last_pos = gst_bit_reader_get_pos (&br) / 8;
      *consumed += used;

      if (parser->temporal_unit_consumed == parser->temporal_unit_size) {
        /* Some extreme case like a temporal unit just
           hold a temporal_unit_size = 0 */
        goto annex_b_again;
      }
    }

    if (parser->frame_unit_consumed > parser->frame_unit_size)
      goto error;

    if (parser->frame_unit_consumed &&
        parser->frame_unit_consumed == parser->frame_unit_size) {
      GST_LOG ("Complete a frame unit of size %d", parser->frame_unit_size);
      parser->frame_unit_size = parser->frame_unit_consumed = 0;
    }

    if (parser->frame_unit_size == 0) {
      parser->frame_unit_size = av1_bitstreamfn_leb128 (&br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;

      g_assert (gst_bit_reader_get_pos (&br) % 8 == 0);
      used = gst_bit_reader_get_pos (&br) / 8 - last_pos;
      last_pos = gst_bit_reader_get_pos (&br) / 8;
      *consumed += used;
      parser->temporal_unit_consumed += used;

      if (parser->frame_unit_size >
          parser->temporal_unit_size - parser->temporal_unit_consumed) {
        GST_INFO ("Error stream, frame unit size %d, bigger than the left"
            "temporal unit size %d", parser->frame_unit_size,
            parser->temporal_unit_size - parser->temporal_unit_consumed);
        ret = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }

      if (parser->temporal_unit_consumed == parser->temporal_unit_size ||
          parser->frame_unit_consumed == parser->frame_unit_size) {
        /* Some extreme case like a temporal unit just hold a frame_unit_size,
           or a frame unit just hold frame_unit_size = 0 */
        goto annex_b_again;
      }
    }

    obu_length = av1_bitstreamfn_leb128 (&br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    if (obu_length > parser->frame_unit_size - parser->frame_unit_consumed) {
      GST_INFO ("Error stream, obu_length is %d, bigger than the left"
          "frame unit size %d", obu_length,
          parser->frame_unit_size - parser->frame_unit_consumed);
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
    /* update the consumed */
    used = gst_bit_reader_get_pos (&br) / 8 - last_pos;
    last_pos = gst_bit_reader_get_pos (&br) / 8;
    *consumed += used;
    parser->temporal_unit_consumed += used;
    parser->frame_unit_consumed += used;

    if (obu_length == 0) {
      /* An empty obu? let continue to the next */
      ret = GST_AV1_PARSER_DROP;
      goto error;
    }
  }

  if (*consumed > size)
    goto error;
  if (*consumed == size) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }
  gst_bit_reader_init (&br, data + *consumed, size - *consumed);

  ret = gst_av1_parse_obu_header (parser, &br, &obu->header);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  obu->obu_type = obu->header.obu_type;
  GST_LOG ("identify obu type is %d", obu->obu_type);

  if (obu->header.obu_has_size_field) {
    guint size_sz = gst_bit_reader_get_pos (&br) / 8;

    obu->obu_size = av1_bitstreamfn_leb128 (&br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    size_sz = gst_bit_reader_get_pos (&br) / 8 - size_sz;
    if (obu_length
        && obu_length - 1 - obu->header.obu_extention_flag - size_sz !=
        obu->obu_size) {
      /* If obu_size and obu_length are both present, but inconsistent,
         then the packed bitstream is deemed invalid. */
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    if (AV1_REMAINING_BYTES (&br) < obu->obu_size) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
  } else {
    if (obu_length == 0) {
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    obu->obu_size = obu_length - 1 - obu->header.obu_extention_flag;
  }

  g_assert (gst_bit_reader_get_pos (&br) % 8 == 0);
  used = gst_bit_reader_get_pos (&br) / 8;
  /* fail if not a complete obu */
  if (size - *consumed - used < obu->obu_size) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  /* update the consumed */
  *consumed += used;
  if (parser->annex_b) {
    parser->temporal_unit_consumed += used;
    parser->frame_unit_consumed += used;
  }

  obu->data = (guint8 *) (data + *consumed);

  *consumed += obu->obu_size;
  if (parser->annex_b) {
    parser->temporal_unit_consumed += obu->obu_size;
    parser->frame_unit_consumed += obu->obu_size;
  }

  if (obu->obu_type != GST_AV1_OBU_SEQUENCE_HEADER
      && obu->obu_type != GST_AV1_OBU_TEMPORAL_DELIMITER
      && parser->state.operating_point_idc && obu->header.obu_extention_flag) {
    guint32 inTemporalLayer =
        (parser->state.operating_point_idc >> obu->header.obu_temporal_id) & 1;
    guint32 inSpatialLayer =
        (parser->state.operating_point_idc >> (obu->header.obu_spatial_id +
            8)) & 1;
    if (!inTemporalLayer || !inSpatialLayer) {
      ret = GST_AV1_PARSER_DROP;
      goto error;
    }
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("can not identify obu, error %d", ret);
  return ret;
}

/* 5.5.2 */
static GstAV1ParserResult
gst_av1_parse_color_config (GstAV1Parser * parser, GstBitReader * br,
    GstAV1SequenceHeaderOBU * seq_header, GstAV1ColorConfig * color_config)
{
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;

  color_config->high_bitdepth = AV1_READ_BIT_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (seq_header->seq_profile == GST_AV1_PROFILE_2
      && color_config->high_bitdepth) {
    color_config->twelve_bit = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    seq_header->bit_depth = color_config->twelve_bit ? 12 : 10;
  } else if (seq_header->seq_profile <= GST_AV1_PROFILE_2) {
    seq_header->bit_depth = color_config->high_bitdepth ? 10 : 8;
  } else {
    GST_INFO ("Unsupported profile/bit-depth combination");
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  if (seq_header->seq_profile == GST_AV1_PROFILE_1)
    color_config->mono_chrome = 0;
  else {
    color_config->mono_chrome = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
  }
  seq_header->num_planes = color_config->mono_chrome ? 1 : 3;

  color_config->color_description_present_flag =
      AV1_READ_BIT_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (color_config->color_description_present_flag) {
    if (AV1_REMAINING_BITS (br) < 8 + 8 + 8) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    color_config->color_primaries = AV1_READ_BITS (br, 8);
    color_config->transfer_characteristics = AV1_READ_BITS (br, 8);
    color_config->matrix_coefficients = AV1_READ_BITS (br, 8);
  } else {
    color_config->color_primaries = GST_AV1_CP_UNSPECIFIED;
    color_config->transfer_characteristics = GST_AV1_TC_UNSPECIFIED;
    color_config->matrix_coefficients = GST_AV1_MC_UNSPECIFIED;
  }

  if (color_config->mono_chrome) {
    color_config->color_range = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    color_config->subsampling_x = 1;
    color_config->subsampling_y = 1;
    color_config->chroma_sample_position = GST_AV1_CSP_UNKNOWN;
    color_config->separate_uv_delta_q = 0;
    goto success;
  } else if (color_config->color_primaries == GST_AV1_CP_BT_709 &&
      color_config->transfer_characteristics == GST_AV1_TC_SRGB &&
      color_config->matrix_coefficients == GST_AV1_MC_IDENTITY) {
    color_config->color_range = 1;
    color_config->subsampling_x = 0;
    color_config->subsampling_y = 0;
    if (!(seq_header->seq_profile == GST_AV1_PROFILE_1 ||
            (seq_header->seq_profile == GST_AV1_PROFILE_2
                && seq_header->bit_depth == 12))) {
      GST_INFO ("sRGB colorspace not compatible with specified profile");
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
  } else {
    color_config->color_range = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    if (seq_header->seq_profile == GST_AV1_PROFILE_0) {
      /* 420 only */
      color_config->subsampling_x = 1;
      color_config->subsampling_y = 1;
    } else if (seq_header->seq_profile == GST_AV1_PROFILE_1) {
      /* 444 only */
      color_config->subsampling_x = 0;
      color_config->subsampling_y = 0;
    } else {
      g_assert (seq_header->seq_profile == GST_AV1_PROFILE_2);
      if (seq_header->bit_depth == 12) {
        color_config->subsampling_x = AV1_READ_BIT_CHECKED (br, &ret);
        if (ret != GST_AV1_PARSER_OK)
          goto error;

        if (color_config->subsampling_x) {
          /* 422 or 420 */
          color_config->subsampling_y = AV1_READ_BIT_CHECKED (br, &ret);
          if (ret != GST_AV1_PARSER_OK)
            goto error;
        } else
          /* 444 */
          color_config->subsampling_y = 0;
      } else {
        /* 422 */
        color_config->subsampling_x = 1;
        color_config->subsampling_y = 0;
      }
    }

    if (color_config->matrix_coefficients == GST_AV1_MC_IDENTITY &&
        (color_config->subsampling_x || color_config->subsampling_y)) {
      GST_INFO ("Identity CICP Matrix incompatible with"
          " non 4:4:4 color sampling");
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    if (color_config->subsampling_x && color_config->subsampling_y) {
      color_config->chroma_sample_position =
          AV1_READ_BITS_CHECKED (br, 2, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  color_config->separate_uv_delta_q = AV1_READ_BIT_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (!(color_config->subsampling_x == 0 && color_config->subsampling_y == 0) &&
      !(color_config->subsampling_x == 1 && color_config->subsampling_y == 1) &&
      !(color_config->subsampling_x == 1 && color_config->subsampling_y == 0)) {
    GST_INFO ("Only 4:4:4, 4:2:2 and 4:2:0 are currently supported, "
        "%d %d subsampling is not supported.\n",
        color_config->subsampling_x, color_config->subsampling_y);
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse color config error %d", ret);
  return ret;
}

/* 5.5.3 */
static GstAV1ParserResult
gst_av1_parse_timing_info (GstAV1Parser * parser, GstBitReader * br,
    GstAV1TimingInfo * timing_info)
{
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;

  if (AV1_REMAINING_BITS (br) < 32 + 32 + 1) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  timing_info->num_units_in_display_tick = AV1_READ_UINT32 (br);
  timing_info->time_scale = AV1_READ_UINT32 (br);
  if (timing_info->num_units_in_display_tick == 0 ||
      timing_info->time_scale == 0) {
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  timing_info->equal_picture_interval = AV1_READ_BIT (br);
  if (timing_info->equal_picture_interval) {
    timing_info->num_ticks_per_picture_minus_1 =
        av1_bitstreamfn_uvlc (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    if (timing_info->num_ticks_per_picture_minus_1 == G_MAXUINT) {
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse timing info error %d", ret);
  return ret;
}

/* 5.5.4 */
static GstAV1ParserResult
gst_av1_parse_decoder_model_info (GstAV1Parser * parser, GstBitReader * br,
    GstAV1DecoderModelInfo * decoder_model_info)
{
  if (AV1_REMAINING_BITS (br) < 5 + 32 + 5 + 5)
    return GST_AV1_PARSER_NO_MORE_DATA;

  decoder_model_info->buffer_delay_length_minus_1 = AV1_READ_BITS (br, 5);
  decoder_model_info->num_units_in_decoding_tick = AV1_READ_BITS (br, 32);
  decoder_model_info->buffer_removal_time_length_minus_1 =
      AV1_READ_BITS (br, 5);
  decoder_model_info->frame_presentation_time_length_minus_1 =
      AV1_READ_BITS (br, 5);

  return GST_AV1_PARSER_OK;
}

/* 5.5.5 */
static GstAV1ParserResult
gst_av1_parse_operating_parameters_info (GstAV1Parser * parser,
    GstBitReader * br, GstAV1SequenceHeaderOBU * seq_header,
    GstAV1OperatingPoint * op_point)
{
  guint32 n = seq_header->decoder_model_info.buffer_delay_length_minus_1 + 1;

  if (AV1_REMAINING_BITS (br) < n + n + 1)
    return GST_AV1_PARSER_NO_MORE_DATA;

  op_point->decoder_buffer_delay = AV1_READ_BITS (br, n);
  op_point->encoder_buffer_delay = AV1_READ_BITS (br, n);
  op_point->low_delay_mode_flag = AV1_READ_BIT (br);
  return GST_AV1_PARSER_OK;
}

/* 5.5.1 General sequence header OBU */
/**
 * gst_av1_parser_parse_sequence_header_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @seq_header: a #GstAV1SequenceHeaderOBU to store the parsed result.
 *
 * Parse one sequence header @obu based on the @parser context, store the
 * result in the @seq_header.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_sequence_header_obu (GstAV1Parser * parser,
    GstAV1OBU * obu, GstAV1SequenceHeaderOBU * seq_header)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  gint i;
  GstBitReader bit_reader;
  GstBitReader *br = &bit_reader;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_SEQUENCE_HEADER,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (seq_header != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  av1_parser_init_sequence_header (seq_header);
  gst_bit_reader_init (br, obu->data, obu->obu_size);

  if (AV1_REMAINING_BITS (br) < 8) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  seq_header->seq_profile = AV1_READ_BITS (br, 3);
  if (seq_header->seq_profile > GST_AV1_PROFILE_2) {
    GST_INFO ("Unsupported profile %d", seq_header->seq_profile);
    retval = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  seq_header->still_picture = AV1_READ_BIT (br);
  seq_header->reduced_still_picture_header = AV1_READ_BIT (br);
  if (!seq_header->still_picture && seq_header->reduced_still_picture_header) {
    GST_INFO (" If reduced_still_picture_header is equal to 1, it is a"
        " requirement of bitstream conformance that still_picture is equal"
        " to 1. ");
    retval = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  if (seq_header->reduced_still_picture_header) {
    seq_header->timing_info_present_flag = 0;
    seq_header->decoder_model_info_present_flag = 0;
    seq_header->initial_display_delay_present_flag = 0;
    seq_header->operating_points_cnt_minus_1 = 0;
    seq_header->operating_points[0].idc = 0;
    seq_header->operating_points[0].seq_level_idx = AV1_READ_BITS (br, 5);
    if (!av1_seq_level_idx_is_valid
        (seq_header->operating_points[0].seq_level_idx)) {
      GST_INFO ("The seq_level_idx is unsupported");
      retval = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
    seq_header->operating_points[0].seq_tier = 0;
    seq_header->operating_points[0].decoder_model_present_for_this_op = 0;
    seq_header->operating_points[0].initial_display_delay_present_for_this_op =
        0;
  } else {
    seq_header->timing_info_present_flag = AV1_READ_BIT (br);

    if (seq_header->timing_info_present_flag) {
      retval =
          gst_av1_parse_timing_info (parser, br, &(seq_header->timing_info));
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      seq_header->decoder_model_info_present_flag =
          AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (seq_header->decoder_model_info_present_flag) {
        retval = gst_av1_parse_decoder_model_info (parser, br,
            &(seq_header->decoder_model_info));
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      }
    } else {
      seq_header->decoder_model_info_present_flag = 0;
    }

    if (AV1_REMAINING_BITS (br) < 6) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    seq_header->initial_display_delay_present_flag = AV1_READ_BIT (br);
    seq_header->operating_points_cnt_minus_1 = AV1_READ_BITS (br, 5);
    if (seq_header->operating_points_cnt_minus_1 + 1 >
        GST_AV1_MAX_OPERATING_POINTS) {
      GST_INFO ("The operating points number %d is too big",
          seq_header->operating_points_cnt_minus_1 + 1);
      retval = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    for (i = 0; i < seq_header->operating_points_cnt_minus_1 + 1; i++) {
      if (AV1_REMAINING_BITS (br) < 17) {
        retval = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }
      seq_header->operating_points[i].idc = AV1_READ_BITS (br, 12);
      seq_header->operating_points[i].seq_level_idx = AV1_READ_BITS (br, 5);
      if (!av1_seq_level_idx_is_valid
          (seq_header->operating_points[0].seq_level_idx)) {
        GST_INFO ("The seq_level_idx is unsupported");
        retval = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }
      if (seq_header->operating_points[i].seq_level_idx > GST_AV1_SEQ_LEVEL_3_3) {
        seq_header->operating_points[i].seq_tier = AV1_READ_BIT (br);
      } else {
        seq_header->operating_points[i].seq_tier = 0;
      }
      if (seq_header->decoder_model_info_present_flag) {
        seq_header->operating_points[i].decoder_model_present_for_this_op =
            AV1_READ_BIT (br);
        if (seq_header->operating_points[i].decoder_model_present_for_this_op)
          retval =
              gst_av1_parse_operating_parameters_info (parser, br, seq_header,
              &(seq_header->operating_points[i]));
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      } else {
        seq_header->operating_points[i].decoder_model_present_for_this_op = 0;
      }

      if (seq_header->initial_display_delay_present_flag) {
        seq_header->
            operating_points[i].initial_display_delay_present_for_this_op =
            AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        if (seq_header->
            operating_points[i].initial_display_delay_present_for_this_op) {
          seq_header->operating_points[i].initial_display_delay_minus_1 =
              AV1_READ_BITS_CHECKED (br, 4, &retval);
          if (retval != GST_AV1_PARSER_OK)
            goto error;

          if (seq_header->operating_points[i].initial_display_delay_minus_1 +
              1 > 10) {
            GST_INFO ("AV1 does not support more than 10 decoded frames delay");
            retval = GST_AV1_PARSER_BITSTREAM_ERROR;
            goto error;
          }
        } else {
          seq_header->operating_points[i].initial_display_delay_minus_1 = 9;
        }
      } else {
        seq_header->
            operating_points[i].initial_display_delay_present_for_this_op = 0;
        seq_header->operating_points[i].initial_display_delay_minus_1 = 9;
      }
    }
  }

  /* Let user decide the operatingPoint,
     implemented by calling gst_av1_parser_set_operating_point()
     operatingPoint = choose_operating_point( )
     operating_point_idc = operating_point_idc[ operatingPoint ] */

  if (AV1_REMAINING_BITS (br) < 4 + 4 +
      (seq_header->frame_width_bits_minus_1 + 1) +
      (seq_header->frame_height_bits_minus_1 + 1)) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  seq_header->frame_width_bits_minus_1 = AV1_READ_BITS (br, 4);
  seq_header->frame_height_bits_minus_1 = AV1_READ_BITS (br, 4);
  seq_header->max_frame_width_minus_1 =
      AV1_READ_BITS (br, seq_header->frame_width_bits_minus_1 + 1);
  seq_header->max_frame_height_minus_1 =
      AV1_READ_BITS (br, seq_header->frame_height_bits_minus_1 + 1);

  if (seq_header->reduced_still_picture_header)
    seq_header->frame_id_numbers_present_flag = 0;
  else {
    seq_header->frame_id_numbers_present_flag =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  if (seq_header->frame_id_numbers_present_flag) {
    if (AV1_REMAINING_BITS (br) < 4 + 3) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    seq_header->delta_frame_id_length_minus_2 = AV1_READ_BITS (br, 4);
    seq_header->additional_frame_id_length_minus_1 = AV1_READ_BITS (br, 3);

    if (seq_header->additional_frame_id_length_minus_1 + 1 +
        seq_header->delta_frame_id_length_minus_2 + 2 > 16) {
      GST_INFO ("Invalid frame_id_length");
      retval = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
  }

  if (AV1_REMAINING_BITS (br) < 3) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }
  seq_header->use_128x128_superblock = AV1_READ_BIT (br);
  seq_header->enable_filter_intra = AV1_READ_BIT (br);
  seq_header->enable_intra_edge_filter = AV1_READ_BIT (br);

  if (seq_header->reduced_still_picture_header) {
    seq_header->enable_interintra_compound = 0;
    seq_header->enable_masked_compound = 0;
    seq_header->enable_warped_motion = 0;
    seq_header->enable_dual_filter = 0;
    seq_header->enable_order_hint = 0;
    seq_header->enable_jnt_comp = 0;
    seq_header->enable_ref_frame_mvs = 0;
    seq_header->seq_force_screen_content_tools =
        GST_AV1_SELECT_SCREEN_CONTENT_TOOLS;
    seq_header->seq_force_integer_mv = GST_AV1_SELECT_INTEGER_MV;
    seq_header->order_hint_bits_minus_1 = -1;
    seq_header->order_hint_bits = 0;
  } else {
    if (AV1_REMAINING_BITS (br) < 5) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    seq_header->enable_interintra_compound = AV1_READ_BIT (br);
    seq_header->enable_masked_compound = AV1_READ_BIT (br);
    seq_header->enable_warped_motion = AV1_READ_BIT (br);
    seq_header->enable_dual_filter = AV1_READ_BIT (br);
    seq_header->enable_order_hint = AV1_READ_BIT (br);
    if (seq_header->enable_order_hint) {
      if (AV1_REMAINING_BITS (br) < 2) {
        retval = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }
      seq_header->enable_jnt_comp = AV1_READ_BIT (br);
      seq_header->enable_ref_frame_mvs = AV1_READ_BIT (br);
    } else {
      seq_header->enable_jnt_comp = 0;
      seq_header->enable_ref_frame_mvs = 0;
    }

    seq_header->seq_choose_screen_content_tools =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
    if (seq_header->seq_choose_screen_content_tools)
      seq_header->seq_force_screen_content_tools =
          GST_AV1_SELECT_SCREEN_CONTENT_TOOLS;
    else {
      seq_header->seq_force_screen_content_tools =
          AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    if (seq_header->seq_force_screen_content_tools > 0) {
      seq_header->seq_choose_integer_mv = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
      if (seq_header->seq_choose_integer_mv)
        seq_header->seq_force_integer_mv = GST_AV1_SELECT_INTEGER_MV;
      else {
        seq_header->seq_force_integer_mv = AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      }
    } else {
      seq_header->seq_force_integer_mv = GST_AV1_SELECT_INTEGER_MV;
    }
    if (seq_header->enable_order_hint) {
      seq_header->order_hint_bits_minus_1 =
          AV1_READ_BITS_CHECKED (br, 3, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
      seq_header->order_hint_bits = seq_header->order_hint_bits_minus_1 + 1;
    } else {
      seq_header->order_hint_bits_minus_1 = -1;
      seq_header->order_hint_bits = 0;
    }
  }

  if (AV1_REMAINING_BITS (br) < 3) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }
  seq_header->enable_superres = AV1_READ_BIT (br);
  seq_header->enable_cdef = AV1_READ_BIT (br);
  seq_header->enable_restoration = AV1_READ_BIT (br);

  retval = gst_av1_parse_color_config (parser, br, seq_header,
      &seq_header->color_config);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  seq_header->film_grain_params_present = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = av1_skip_trailing_bits (parser, br, obu);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (parser->seq_header) {
    if (!memcmp (parser->seq_header, seq_header,
            sizeof (GstAV1SequenceHeaderOBU)))
      goto success;

    g_slice_free (GstAV1SequenceHeaderOBU, parser->seq_header);
  }

  parser->seq_header = g_slice_dup (GstAV1SequenceHeaderOBU, seq_header);
  gst_av1_parse_reset_state (parser, FALSE);

  /* choose_operating_point() set the operating_point */
  if (parser->state.operating_point < 0 ||
      parser->state.operating_point >
      seq_header->operating_points_cnt_minus_1) {
    GST_WARNING ("Invalid operating_point %d set by user, just use 0",
        parser->state.operating_point);
    parser->state.operating_point_idc = seq_header->operating_points[0].idc;
  } else {
    parser->state.operating_point_idc =
        seq_header->operating_points[parser->state.operating_point].idc;
  }

  parser->state.sequence_changed = TRUE;

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse sequence header error %d", retval);
  return retval;
}

/* 5.6 */
/**
 * gst_av1_parser_parse_temporal_delimiter_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 *
 * Parse one temporal delimiter @obu based on the @parser context.
 * The temporal delimiter is just delimiter and contains no content.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_temporal_delimiter_obu (GstAV1Parser * parser,
    GstAV1OBU * obu)
{
  GstBitReader bit_reader;
  GstAV1ParserResult ret;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_TEMPORAL_DELIMITER,
      GST_AV1_PARSER_INVALID_OPERATION);

  gst_bit_reader_init (&bit_reader, obu->data, obu->obu_size);

  parser->state.seen_frame_header = 0;

  ret = av1_skip_trailing_bits (parser, &bit_reader, obu);
  if (ret != GST_AV1_PARSER_OK)
    GST_WARNING ("parse temporal delimiter error %d", ret);

  return ret;
}

/* 5.8.2 */
static GstAV1ParserResult
gst_av1_parse_metadata_itut_t35 (GstAV1Parser * parser, GstBitReader * br,
    GstAV1MetadataITUT_T35 * itut_t35)
{
  GstAV1ParserResult ret;

  itut_t35->itu_t_t35_country_code = AV1_READ_BITS_CHECKED (br, 8, &ret);
  if (ret != GST_AV1_PARSER_OK)
    return ret;

  if (itut_t35->itu_t_t35_country_code == 0xFF) {
    itut_t35->itu_t_t35_country_code_extention_byte =
        AV1_READ_BITS_CHECKED (br, 8, &ret);
    if (ret != GST_AV1_PARSER_OK)
      return ret;
  }
  /* itu_t_t35_payload_bytes is not defined in specification.
     Just skip this part. */

  return GST_AV1_PARSER_OK;
}

/* 5.8.3 */
static GstAV1ParserResult
gst_av1_parse_metadata_hdr_cll (GstAV1Parser * parser, GstBitReader * br,
    GstAV1MetadataHdrCll * hdr_cll)
{
  if (AV1_REMAINING_BITS (br) < 32)
    return GST_AV1_PARSER_NO_MORE_DATA;

  hdr_cll->max_cll = AV1_READ_UINT16 (br);
  hdr_cll->max_fall = AV1_READ_UINT16 (br);

  return GST_AV1_PARSER_OK;
}

/* 5.8.4 */
static GstAV1ParserResult
gst_av1_parse_metadata_hdr_mdcv (GstAV1Parser * parser, GstBitReader * br,
    GstAV1MetadataHdrMdcv * hdr_mdcv)
{
  gint i;

  if (AV1_REMAINING_BITS (br) < 3 * (16 + 16) + 16 + 16 + 32 + 32)
    return GST_AV1_PARSER_NO_MORE_DATA;

  for (i = 0; i < 3; i++) {
    hdr_mdcv->primary_chromaticity_x[i] = AV1_READ_UINT16 (br);
    hdr_mdcv->primary_chromaticity_y[i] = AV1_READ_UINT16 (br);
  }

  hdr_mdcv->white_point_chromaticity_x = AV1_READ_UINT16 (br);
  hdr_mdcv->white_point_chromaticity_y = AV1_READ_UINT16 (br);

  hdr_mdcv->luminance_max = AV1_READ_UINT32 (br);
  hdr_mdcv->luminance_min = AV1_READ_UINT32 (br);

  return GST_AV1_PARSER_OK;
}

/* 5.8.5 */
static GstAV1ParserResult
gst_av1_parse_metadata_scalability (GstAV1Parser * parser,
    GstBitReader * br, GstAV1MetadataScalability * scalability)
{
  gint i, j;
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;
  guint8 scalability_structure_reserved_3bits;

  scalability->scalability_mode_idc = AV1_READ_UINT8_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (scalability->scalability_mode_idc != GST_AV1_SCALABILITY_SS)
    goto success;

  if (AV1_REMAINING_BITS (br) < 8) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  /* 5.8.6 */
  scalability->spatial_layers_cnt_minus_1 = AV1_READ_BITS (br, 2);
  scalability->spatial_layer_dimensions_present_flag = AV1_READ_BIT (br);
  scalability->spatial_layer_description_present_flag = AV1_READ_BIT (br);
  scalability->temporal_group_description_present_flag = AV1_READ_BIT (br);
  scalability_structure_reserved_3bits = AV1_READ_BITS (br, 3);
  /* scalability_structure_reserved_3bits: must be set to zero and
     be ignored by decoders. */
  if (scalability_structure_reserved_3bits) {
    ret = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  if (scalability->spatial_layer_dimensions_present_flag) {
    for (i = 0; i <= scalability->spatial_layers_cnt_minus_1; i++) {
      if (AV1_REMAINING_BITS (br) < 16 * 2) {
        ret = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }

      scalability->spatial_layer_max_width[i] = AV1_READ_UINT16 (br);
      scalability->spatial_layer_max_height[i] = AV1_READ_UINT16 (br);
    }
  }

  if (scalability->spatial_layer_description_present_flag) {
    for (i = 0; i <= scalability->spatial_layers_cnt_minus_1; i++) {
      scalability->spatial_layer_ref_id[i] = AV1_READ_UINT8_CHECKED (br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  if (scalability->temporal_group_description_present_flag) {
    scalability->temporal_group_size = AV1_READ_UINT8_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    for (i = 0; i < scalability->temporal_group_size; i++) {
      if (AV1_REMAINING_BITS (br) < 8) {
        ret = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }

      scalability->temporal_group_temporal_id[i] = AV1_READ_BITS (br, 3);
      scalability->temporal_group_temporal_switching_up_point_flag[i] =
          AV1_READ_BIT (br);
      scalability->temporal_group_spatial_switching_up_point_flag[i] =
          AV1_READ_BIT (br);
      scalability->temporal_group_ref_cnt[i] = AV1_READ_BITS (br, 3);
      for (j = 0; j < scalability->temporal_group_ref_cnt[i]; j++) {
        scalability->temporal_group_ref_pic_diff[i][j] =
            AV1_READ_UINT8_CHECKED (br, &ret);
        if (ret != GST_AV1_PARSER_OK)
          goto error;
      }
    }
  }

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse metadata scalability error %d", ret);
  return ret;
}

/* 5.8.7 */
static GstAV1ParserResult
gst_av1_parse_metadata_timecode (GstAV1Parser * parser, GstBitReader * br,
    GstAV1MetadataTimecode * timecode)
{
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;

  if (AV1_REMAINING_BITS (br) < 17) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  timecode->counting_type = AV1_READ_BITS (br, 5);
  timecode->full_timestamp_flag = AV1_READ_BIT (br);
  timecode->discontinuity_flag = AV1_READ_BIT (br);
  timecode->cnt_dropped_flag = AV1_READ_BIT (br);
  timecode->n_frames = AV1_READ_BITS (br, 9);

  if (timecode->full_timestamp_flag) {
    if (AV1_REMAINING_BITS (br) < 17) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    timecode->seconds_value = AV1_READ_BITS (br, 6);
    timecode->minutes_value = AV1_READ_BITS (br, 6);
    timecode->hours_value = AV1_READ_BITS (br, 5);
  } else {
    timecode->seconds_flag = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    if (timecode->seconds_flag) {
      if (AV1_REMAINING_BITS (br) < 7) {
        ret = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }
      timecode->seconds_value = AV1_READ_BITS (br, 6);
      timecode->minutes_flag = AV1_READ_BIT (br);

      if (timecode->minutes_flag) {
        if (AV1_REMAINING_BITS (br) < 7) {
          ret = GST_AV1_PARSER_NO_MORE_DATA;
          goto error;
        }
        timecode->minutes_value = AV1_READ_BITS (br, 6);
        timecode->hours_flag = AV1_READ_BIT (br);

        if (timecode->hours_flag) {
          timecode->hours_value = AV1_READ_BITS_CHECKED (br, 6, &ret);
          if (ret != GST_AV1_PARSER_OK)
            goto error;
        }
      }
    }
  }

  timecode->time_offset_length = AV1_READ_BITS_CHECKED (br, 5, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (timecode->time_offset_length > 0) {
    timecode->time_offset_value =
        AV1_READ_BITS_CHECKED (br, timecode->time_offset_length, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse metadata timecode error %d", ret);
  return ret;
}

/* 5.8.1 */
/**
 * gst_av1_parser_parse_metadata_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @metadata: a #GstAV1MetadataOBU to store the parsed result.
 *
 * Parse one meta data @obu based on the @parser context.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_metadata_obu (GstAV1Parser * parser, GstAV1OBU * obu,
    GstAV1MetadataOBU * metadata)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstBitReader bit_reader;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_METADATA,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (metadata != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  gst_bit_reader_init (&bit_reader, obu->data, obu->obu_size);

  memset (metadata, 0, sizeof (*metadata));

  metadata->metadata_type = av1_bitstreamfn_leb128 (&bit_reader, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  switch (metadata->metadata_type) {
    case GST_AV1_METADATA_TYPE_ITUT_T35:
      retval = gst_av1_parse_metadata_itut_t35 (parser,
          &bit_reader, &(metadata->itut_t35));
      break;
    case GST_AV1_METADATA_TYPE_HDR_CLL:
      retval = gst_av1_parse_metadata_hdr_cll (parser,
          &bit_reader, &(metadata->hdr_cll));
      break;
    case GST_AV1_METADATA_TYPE_HDR_MDCV:
      retval = gst_av1_parse_metadata_hdr_mdcv (parser,
          &bit_reader, &(metadata->hdr_mdcv));
      break;
    case GST_AV1_METADATA_TYPE_SCALABILITY:
      retval = gst_av1_parse_metadata_scalability (parser,
          &bit_reader, &(metadata->scalability));
      break;
    case GST_AV1_METADATA_TYPE_TIMECODE:
      retval = gst_av1_parse_metadata_timecode (parser,
          &bit_reader, &(metadata->timecode));
      break;
    default:
      return GST_AV1_PARSER_BITSTREAM_ERROR;
  }

  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = av1_skip_trailing_bits (parser, &bit_reader, obu);
  if (retval != GST_AV1_PARSER_OK) {
    GST_WARNING ("Metadata type %d may have wrong trailings.",
        metadata->metadata_type);
    retval = GST_AV1_PARSER_OK;
  }

  return retval;

error:
  GST_WARNING ("parse metadata error %d", retval);
  return retval;
}

/* 5.9.8 */
static GstAV1ParserResult
gst_av1_parse_superres_params_compute_image_size (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult ret;
  GstAV1SequenceHeaderOBU *seq_header;

  g_assert (parser->seq_header);
  seq_header = parser->seq_header;

  if (seq_header->enable_superres) {
    frame_header->use_superres = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      return ret;
  } else {
    frame_header->use_superres = 0;
  }

  if (frame_header->use_superres) {
    guint8 coded_denom;
    coded_denom = AV1_READ_BITS_CHECKED (br, GST_AV1_SUPERRES_DENOM_BITS, &ret);
    if (ret != GST_AV1_PARSER_OK)
      return ret;

    frame_header->superres_denom = coded_denom + GST_AV1_SUPERRES_DENOM_MIN;
  } else {
    frame_header->superres_denom = GST_AV1_SUPERRES_NUM;
  }
  parser->state.upscaled_width = parser->state.frame_width;
  parser->state.frame_width =
      (parser->state.upscaled_width * GST_AV1_SUPERRES_NUM +
      (frame_header->superres_denom / 2)) / frame_header->superres_denom;

  /* 5.9.9 compute_image_size */
  parser->state.mi_cols = 2 * ((parser->state.frame_width + 7) >> 3);
  parser->state.mi_rows = 2 * ((parser->state.frame_height + 7) >> 3);

  return GST_AV1_PARSER_OK;
}

/* 5.9.5 */
static GstAV1ParserResult
gst_av1_parse_frame_size (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval;
  GstAV1SequenceHeaderOBU *seq_header;

  g_assert (parser->seq_header);
  seq_header = parser->seq_header;

  if (frame_header->frame_size_override_flag) {
    guint16 frame_width_minus_1;
    guint16 frame_height_minus_1;

    if (AV1_REMAINING_BITS (br) <
        seq_header->frame_width_bits_minus_1 + 1 +
        seq_header->frame_height_bits_minus_1 + 1)
      return GST_AV1_PARSER_NO_MORE_DATA;

    frame_width_minus_1 =
        AV1_READ_BITS (br, seq_header->frame_width_bits_minus_1 + 1);
    frame_height_minus_1 =
        AV1_READ_BITS (br, seq_header->frame_height_bits_minus_1 + 1);
    parser->state.frame_width = frame_width_minus_1 + 1;
    parser->state.frame_height = frame_height_minus_1 + 1;
  } else {
    parser->state.frame_width = seq_header->max_frame_width_minus_1 + 1;
    parser->state.frame_height = seq_header->max_frame_height_minus_1 + 1;
  }

  retval = gst_av1_parse_superres_params_compute_image_size (parser, br,
      frame_header);
  return retval;
}

/* 5.9.6 */
static GstAV1ParserResult
gst_av1_parse_render_size (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval;

  frame_header->render_and_frame_size_different =
      AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    return retval;

  if (frame_header->render_and_frame_size_different) {
    guint16 render_width_minus_1;
    guint16 render_height_minus_1;

    if (AV1_REMAINING_BITS (br) < 16 + 16)
      return GST_AV1_PARSER_NO_MORE_DATA;

    render_width_minus_1 = AV1_READ_UINT16 (br);
    render_height_minus_1 = AV1_READ_UINT16 (br);
    parser->state.render_width = render_width_minus_1 + 1;
    parser->state.render_height = render_height_minus_1 + 1;
  } else {
    parser->state.render_width = parser->state.upscaled_width;
    parser->state.render_height = parser->state.frame_height;
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.7 */
static GstAV1ParserResult
gst_av1_parse_frame_size_with_refs (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval;
  GstAV1ReferenceFrameInfo *ref_info;
  gboolean found_ref = FALSE;
  gint i;

  ref_info = &(parser->state.ref_info);

  for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
    found_ref = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      return retval;

    if (found_ref == 1) {
      gint ref_idx = frame_header->ref_frame_idx[i];
      parser->state.upscaled_width =
          ref_info->entry[ref_idx].ref_upscaled_width;
      parser->state.frame_width = parser->state.upscaled_width;
      parser->state.frame_height = ref_info->entry[ref_idx].ref_frame_height;
      parser->state.render_width = ref_info->entry[ref_idx].ref_render_width;
      parser->state.render_height = ref_info->entry[ref_idx].ref_render_height;
      break;
    }
  }
  if (found_ref == 0) {
    retval = gst_av1_parse_frame_size (parser, br, frame_header);
    if (retval != GST_AV1_PARSER_OK)
      return retval;

    retval = gst_av1_parse_render_size (parser, br, frame_header);
    if (retval != GST_AV1_PARSER_OK)
      return retval;
  } else {
    retval = gst_av1_parse_superres_params_compute_image_size (parser, br,
        frame_header);
    if (retval != GST_AV1_PARSER_OK)
      return retval;
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.12 */
static GstAV1ParserResult
gst_av1_parse_quantization_params (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstAV1ColorConfig *color_config;
  GstAV1QuantizationParams *quant_params = &(frame_header->quantization_params);

  g_assert (parser->seq_header);

  color_config = &(parser->seq_header->color_config);

  quant_params->base_q_idx = AV1_READ_UINT8_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  frame_header->quantization_params.delta_q_y_dc =
      av1_bitstreamfn_delta_q (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (parser->seq_header->num_planes > 1) {
    if (color_config->separate_uv_delta_q) {
      quant_params->diff_uv_delta = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    } else {
      quant_params->diff_uv_delta = 0;
    }
    frame_header->quantization_params.delta_q_u_dc =
        av1_bitstreamfn_delta_q (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    frame_header->quantization_params.delta_q_u_ac =
        av1_bitstreamfn_delta_q (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (quant_params->diff_uv_delta) {
      frame_header->quantization_params.delta_q_v_dc =
          av1_bitstreamfn_delta_q (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      frame_header->quantization_params.delta_q_v_ac =
          av1_bitstreamfn_delta_q (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    } else {
      frame_header->quantization_params.delta_q_v_dc =
          frame_header->quantization_params.delta_q_u_dc;
      frame_header->quantization_params.delta_q_v_ac =
          frame_header->quantization_params.delta_q_u_ac;
    }
  } else {
    frame_header->quantization_params.delta_q_u_dc = 0;
    frame_header->quantization_params.delta_q_u_ac = 0;
    frame_header->quantization_params.delta_q_v_dc = 0;
    frame_header->quantization_params.delta_q_v_ac = 0;
  }

  quant_params->using_qmatrix = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (quant_params->using_qmatrix) {
    if (AV1_REMAINING_BITS (br) < 4 + 4) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }

    quant_params->qm_y = AV1_READ_BITS (br, 4);
    quant_params->qm_u = AV1_READ_BITS (br, 4);

    if (!color_config->separate_uv_delta_q) {
      quant_params->qm_v = quant_params->qm_u;
    } else {
      quant_params->qm_v = AV1_READ_BITS_CHECKED (br, 4, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse quantization params error %d", retval);
  return retval;
}

/* 5.9.14 */
static GstAV1ParserResult
gst_av1_parse_segmentation_params (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  gint i, j;
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  gint clipped_value /* clippedValue */ ;
  GstAV1SegmenationParams *seg_params;
  gint feature_value = 0;

  const guint8 segmentation_feature_bits[GST_AV1_SEG_LVL_MAX] = {
    8, 6, 6, 6, 6, 3, 0, 0
  };
  const guint8 segmentation_feature_signed[GST_AV1_SEG_LVL_MAX] = {
    1, 1, 1, 1, 1, 0, 0, 0
  };
  const guint8 segmentation_feature_max[GST_AV1_SEG_LVL_MAX] = {
    255, GST_AV1_MAX_LOOP_FILTER, GST_AV1_MAX_LOOP_FILTER,
    GST_AV1_MAX_LOOP_FILTER, GST_AV1_MAX_LOOP_FILTER, 7, 0, 0
  };

  seg_params = &frame_header->segmentation_params;

  seg_params->segmentation_enabled = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (seg_params->segmentation_enabled) {
    if (frame_header->primary_ref_frame == GST_AV1_PRIMARY_REF_NONE) {
      seg_params->segmentation_update_map = 1;
      seg_params->segmentation_temporal_update = 0;
      seg_params->segmentation_update_data = 1;
    } else {
      seg_params->segmentation_update_map = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (seg_params->segmentation_update_map) {
        seg_params->segmentation_temporal_update =
            AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      }
      seg_params->segmentation_update_data = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    if (seg_params->segmentation_update_data) {
      for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) {
        for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) {
          seg_params->feature_enabled[i][j] =
              AV1_READ_BIT_CHECKED (br, &retval);
          if (retval != GST_AV1_PARSER_OK)
            goto error;

          clipped_value = 0;
          feature_value = 0;
          if (seg_params->feature_enabled[i][j]) {
            gint bits_to_read = segmentation_feature_bits[j];
            gint limit = segmentation_feature_max[j];
            if (segmentation_feature_signed[j]) {
              feature_value =
                  av1_bitstreamfn_su (br, 1 + bits_to_read, &retval);
              if (retval != GST_AV1_PARSER_OK)
                goto error;

              clipped_value = CLAMP (feature_value, limit * (-1), limit);
            } else {
              feature_value = AV1_READ_BITS_CHECKED (br, bits_to_read, &retval);
              if (retval != GST_AV1_PARSER_OK)
                goto error;

              clipped_value = CLAMP (feature_value, 0, limit);
            }
          }
          seg_params->feature_data[i][j] = clipped_value;
        }
      }
    } else {
      /* Copy it from prime_ref */
      g_assert (frame_header->primary_ref_frame != GST_AV1_PRIMARY_REF_NONE);
      g_assert (parser->state.ref_info.
          entry[frame_header->ref_frame_idx[frame_header->primary_ref_frame]].
          ref_valid);
      memcpy (seg_params,
          &parser->state.ref_info.
          entry[frame_header->ref_frame_idx[frame_header->
                  primary_ref_frame]].ref_segmentation_params,
          sizeof (GstAV1SegmenationParams));

      seg_params->segmentation_update_map = 0;
      seg_params->segmentation_temporal_update = 0;
      seg_params->segmentation_update_data = 0;
    }
  } else {
    seg_params->segmentation_update_map = 0;
    seg_params->segmentation_temporal_update = 0;
    seg_params->segmentation_update_data = 0;
    for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) {
      for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) {
        seg_params->feature_enabled[i][j] = 0;
        seg_params->feature_data[i][j] = 0;
      }
    }
  }

  seg_params->seg_id_pre_skip = 0;
  seg_params->last_active_seg_id = 0;
  for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) {
    for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) {
      if (seg_params->feature_enabled[i][j]) {
        seg_params->last_active_seg_id = i;
        if (j >= GST_AV1_SEG_LVL_REF_FRAME) {
          seg_params->seg_id_pre_skip = 1;
        }
      }
    }
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse segmentation params error %d", retval);
  return retval;
}

/* 5.9.15 */
static GstAV1ParserResult
gst_av1_parse_tile_info (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstAV1SequenceHeaderOBU *seq_header;
  GstAV1TileInfo *tile_info;
  gint i;
  gint start_sb /* startSb */ ;
  gint sb_cols /* sbCols */ ;
  gint sb_rows /* sbRows */ ;
  gint sb_shift /*sbShift */ ;
  gint sb_size /* sbSize */ ;
  gint max_tile_width_sb /* maxTileWidthSb */ ;
  gint max_tile_height_sb /* maxTileHeightSb */ ;
  gint max_tile_area_sb /* maxTileAreaSb */ ;
  gint min_log2_tile_cols /* minLog2TileCols */ ;
  gint max_log2_tile_cols /* maxLog2TileCols */ ;
  gint min_log2_tile_rows /* minLog2TileRows */ ;
  gint max_log2_tile_rows /* maxLog2TileRows */ ;
  gint min_log2_tiles /* minLog2Tiles */ ;
  gint tile_width_sb /* tileWidthSb */ ;
  gint tile_height_sb /* tileHeightSb */ ;
  gint max_width /* maxWidth */ , max_height /* maxHeight */ ;
  gint size_sb /* sizeSb */ ;
  gint widest_tile_sb /* widestTileSb */ ;

  g_assert (parser->seq_header);
  seq_header = parser->seq_header;
  tile_info = &frame_header->tile_info;

  sb_cols = seq_header->use_128x128_superblock ?
      ((parser->state.mi_cols + 31) >> 5) : ((parser->state.mi_cols + 15) >> 4);
  sb_rows = seq_header->use_128x128_superblock ? ((parser->state.mi_rows +
          31) >> 5) : ((parser->state.mi_rows + 15) >> 4);
  sb_shift = seq_header->use_128x128_superblock ? 5 : 4;
  sb_size = sb_shift + 2;
  max_tile_width_sb = GST_AV1_MAX_TILE_WIDTH >> sb_size;
  max_tile_area_sb = GST_AV1_MAX_TILE_AREA >> (2 * sb_size);
  min_log2_tile_cols = av1_helper_tile_log2 (max_tile_width_sb, sb_cols);
  max_log2_tile_cols = av1_helper_tile_log2 (1, MIN (sb_cols,
          GST_AV1_MAX_TILE_COLS));
  max_log2_tile_rows = av1_helper_tile_log2 (1, MIN (sb_rows,
          GST_AV1_MAX_TILE_ROWS));
  min_log2_tiles = MAX (min_log2_tile_cols,
      av1_helper_tile_log2 (max_tile_area_sb, sb_rows * sb_cols));

  tile_info->uniform_tile_spacing_flag = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (tile_info->uniform_tile_spacing_flag) {
    parser->state.tile_cols_log2 = min_log2_tile_cols;
    while (parser->state.tile_cols_log2 < max_log2_tile_cols) {
      gint increment_tile_cols_log2 = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (increment_tile_cols_log2 == 1)
        parser->state.tile_cols_log2++;
      else
        break;
    }
    tile_width_sb = (sb_cols + (1 << parser->state.tile_cols_log2) -
        1) >> parser->state.tile_cols_log2;
    i = 0;
    for (start_sb = 0; start_sb < sb_cols; start_sb += tile_width_sb) {
      parser->state.mi_col_starts[i] = start_sb << sb_shift;
      i += 1;
    }
    parser->state.mi_col_starts[i] = parser->state.mi_cols;
    parser->state.tile_cols = i;

    while (i >= 1) {
      tile_info->width_in_sbs_minus_1[i - 1] =
          ((parser->state.mi_col_starts[i] - parser->state.mi_col_starts[i - 1]
              + ((1 << sb_shift) - 1)) >> sb_shift) - 1;
      i--;
    }

    min_log2_tile_rows = MAX (min_log2_tiles - parser->state.tile_cols_log2, 0);
    parser->state.tile_rows_log2 = min_log2_tile_rows;
    while (parser->state.tile_rows_log2 < max_log2_tile_rows) {
      tile_info->increment_tile_rows_log2 = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (tile_info->increment_tile_rows_log2 == 1)
        parser->state.tile_rows_log2++;
      else
        break;
    }
    tile_height_sb = (sb_rows + (1 << parser->state.tile_rows_log2) -
        1) >> parser->state.tile_rows_log2;
    i = 0;
    for (start_sb = 0; start_sb < sb_rows; start_sb += tile_height_sb) {
      parser->state.mi_row_starts[i] = start_sb << sb_shift;
      i += 1;
    }
    parser->state.mi_row_starts[i] = parser->state.mi_rows;
    parser->state.tile_rows = i;
    while (i >= 1) {
      tile_info->height_in_sbs_minus_1[i - 1] =
          ((parser->state.mi_row_starts[i] - parser->state.mi_row_starts[i - 1]
              + ((1 << sb_shift) - 1)) >> sb_shift) - 1;
      i--;
    }
  } else {
    widest_tile_sb = 0;
    start_sb = 0;
    for (i = 0; start_sb < sb_cols; i++) {
      parser->state.mi_col_starts[i] = start_sb << sb_shift;
      max_width = MIN (sb_cols - start_sb, max_tile_width_sb);
      tile_info->width_in_sbs_minus_1[i] =
          av1_bitstreamfn_ns (br, max_width, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      size_sb = tile_info->width_in_sbs_minus_1[i] + 1;
      widest_tile_sb = MAX (size_sb, widest_tile_sb);
      start_sb += size_sb;
    }
    parser->state.mi_col_starts[i] = parser->state.mi_cols;
    parser->state.tile_cols = i;
    parser->state.tile_cols_log2 =
        av1_helper_tile_log2 (1, parser->state.tile_cols);

    if (min_log2_tiles > 0)
      max_tile_area_sb = (sb_rows * sb_cols) >> (min_log2_tiles + 1);
    else
      max_tile_area_sb = sb_rows * sb_cols;

    max_tile_height_sb = MAX (max_tile_area_sb / widest_tile_sb, 1);

    start_sb = 0;
    for (i = 0; start_sb < sb_rows; i++) {
      parser->state.mi_row_starts[i] = start_sb << sb_shift;
      max_height = MIN (sb_rows - start_sb, max_tile_height_sb);
      tile_info->height_in_sbs_minus_1[i] =
          av1_bitstreamfn_ns (br, max_height, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      size_sb = tile_info->height_in_sbs_minus_1[i] + 1;
      start_sb += size_sb;
    }

    parser->state.mi_row_starts[i] = parser->state.mi_rows;
    parser->state.tile_rows = i;
    parser->state.tile_rows_log2 =
        av1_helper_tile_log2 (1, parser->state.tile_rows);
  }

  if (parser->state.tile_cols_log2 > 0 || parser->state.tile_rows_log2 > 0) {
    tile_info->context_update_tile_id =
        AV1_READ_BITS_CHECKED (br,
        parser->state.tile_cols_log2 + parser->state.tile_rows_log2, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    tile_info->tile_size_bytes_minus_1 = AV1_READ_BITS_CHECKED (br, 2, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    parser->state.tile_size_bytes = tile_info->tile_size_bytes_minus_1 + 1;
  } else {
    tile_info->context_update_tile_id = 0;
  }

  memcpy (tile_info->mi_col_starts, parser->state.mi_col_starts,
      sizeof (guint32) * (GST_AV1_MAX_TILE_COLS + 1));
  memcpy (tile_info->mi_row_starts, parser->state.mi_row_starts,
      sizeof (guint32) * (GST_AV1_MAX_TILE_ROWS + 1));
  tile_info->tile_cols_log2 = parser->state.tile_cols_log2;
  tile_info->tile_cols = parser->state.tile_cols;
  tile_info->tile_rows_log2 = parser->state.tile_rows_log2;
  tile_info->tile_rows = parser->state.tile_rows;
  tile_info->tile_size_bytes = parser->state.tile_size_bytes;

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse tile info error %d", retval);
  return retval;
}

static GstAV1ParserResult
gst_av1_parse_loop_filter_params (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstAV1LoopFilterParams *lf_params;
  gint i;
  guint8 update_ref_deltas = 0;
  guint8 update_mode_deltas = 0;

  g_assert (parser->seq_header);

  lf_params = &frame_header->loop_filter_params;

  if (frame_header->coded_lossless || frame_header->allow_intrabc) {
    lf_params->loop_filter_level[0] = 0;
    lf_params->loop_filter_level[1] = 0;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME] = 1;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME] = 0;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME] = 0;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME] = 0;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME] = 0;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME] = -1;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF_FRAME] = -1;
    lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME] = -1;
    for (i = 0; i < 2; i++)
      lf_params->loop_filter_mode_deltas[i] = 0;

    goto success;
  }

  if (AV1_REMAINING_BITS (br) < 6 + 6) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  lf_params->loop_filter_level[0] = AV1_READ_BITS (br, 6);
  lf_params->loop_filter_level[1] = AV1_READ_BITS (br, 6);
  if (parser->seq_header->num_planes > 1) {
    if (lf_params->loop_filter_level[0] || lf_params->loop_filter_level[1]) {
      if (AV1_REMAINING_BITS (br) < 6 + 6) {
        retval = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }

      lf_params->loop_filter_level[2] = AV1_READ_BITS (br, 6);
      lf_params->loop_filter_level[3] = AV1_READ_BITS (br, 6);
    }
  }

  if (AV1_REMAINING_BITS (br) < 3 + 1) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  lf_params->loop_filter_sharpness = AV1_READ_BITS (br, 3);

  lf_params->loop_filter_delta_enabled = AV1_READ_BIT (br);
  if (lf_params->loop_filter_delta_enabled) {
    lf_params->loop_filter_delta_update = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (lf_params->loop_filter_delta_update) {
      for (i = 0; i < GST_AV1_TOTAL_REFS_PER_FRAME; i++) {
        update_ref_deltas = AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        if (update_ref_deltas) {
          lf_params->loop_filter_ref_deltas[i] =
              av1_bitstreamfn_su (br, 7, &retval);
          if (retval != GST_AV1_PARSER_OK)
            goto error;
        }
      }
      for (i = 0; i < 2; i++) {
        update_mode_deltas = AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        if (update_mode_deltas) {
          lf_params->loop_filter_mode_deltas[i] =
              av1_bitstreamfn_su (br, 7, &retval);
          if (retval != GST_AV1_PARSER_OK)
            goto error;
        }
      }
    }
  }

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse loop filter params error %d", retval);
  return retval;
}

/* 5.9.17 */
static GstAV1ParserResult
gst_av1_parse_delta_q_params (GstAV1Parser * parser,
    GstBitReader * br, GstAV1QuantizationParams * quant_params)
{
  GstAV1ParserResult retval;

  quant_params->delta_q_res = 0;
  quant_params->delta_q_present = 0;
  if (quant_params->base_q_idx > 0) {
    quant_params->delta_q_present = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      return retval;
  }

  if (quant_params->delta_q_present) {
    quant_params->delta_q_res = AV1_READ_BITS_CHECKED (br, 2, &retval);
    if (retval != GST_AV1_PARSER_OK)
      return retval;
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.18 */
static GstAV1ParserResult
gst_av1_parse_delta_lf_params (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval;
  GstAV1LoopFilterParams *lf_params;

  lf_params = &frame_header->loop_filter_params;
  lf_params->delta_lf_present = 0;
  lf_params->delta_lf_res = 0;
  lf_params->delta_lf_multi = 0;

  if (frame_header->quantization_params.delta_q_present) {
    if (!frame_header->allow_intrabc) {
      lf_params->delta_lf_present = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        return retval;
    }
    if (lf_params->delta_lf_present) {
      if (AV1_REMAINING_BITS (br) < 2 + 1)
        return GST_AV1_PARSER_NO_MORE_DATA;
      lf_params->delta_lf_res = AV1_READ_BITS (br, 2);
      lf_params->delta_lf_multi = AV1_READ_BIT (br);
    }
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.19 */
static GstAV1ParserResult
gst_av1_parse_cdef_params (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1SequenceHeaderOBU *seq_header;
  GstAV1CDEFParams *cdef_params;
  guint8 cdef_damping_minus_3;
  gint i;

  g_assert (parser->seq_header);

  cdef_params = &frame_header->cdef_params;
  seq_header = parser->seq_header;

  if (frame_header->coded_lossless || frame_header->allow_intrabc
      || !seq_header->enable_cdef) {
    cdef_params->cdef_bits = 0;
    cdef_params->cdef_y_pri_strength[0] = 0;
    cdef_params->cdef_y_sec_strength[0] = 0;
    cdef_params->cdef_uv_pri_strength[0] = 0;
    cdef_params->cdef_uv_sec_strength[0] = 0;
    cdef_params->cdef_damping = 3;
    return GST_AV1_PARSER_OK;
  }

  if (AV1_REMAINING_BITS (br) < 2 + 2)
    return GST_AV1_PARSER_NO_MORE_DATA;

  cdef_damping_minus_3 = AV1_READ_BITS (br, 2);
  cdef_params->cdef_damping = cdef_damping_minus_3 + 3;
  cdef_params->cdef_bits = AV1_READ_BITS (br, 2);
  for (i = 0; i < (1 << cdef_params->cdef_bits); i++) {
    if (AV1_REMAINING_BITS (br) < 4 + 2)
      return GST_AV1_PARSER_NO_MORE_DATA;

    cdef_params->cdef_y_pri_strength[i] = AV1_READ_BITS (br, 4);
    cdef_params->cdef_y_sec_strength[i] = AV1_READ_BITS (br, 2);
    if (cdef_params->cdef_y_sec_strength[i] == 3)
      cdef_params->cdef_y_sec_strength[i] += 1;

    if (parser->seq_header->num_planes > 1) {
      if (AV1_REMAINING_BITS (br) < 4 + 2)
        return GST_AV1_PARSER_NO_MORE_DATA;

      cdef_params->cdef_uv_pri_strength[i] = AV1_READ_BITS (br, 4);
      cdef_params->cdef_uv_sec_strength[i] = AV1_READ_BITS (br, 2);
      if (cdef_params->cdef_uv_sec_strength[i] == 3)
        cdef_params->cdef_uv_sec_strength[i] += 1;
    }
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.20 */
static GstAV1ParserResult
gst_av1_parse_loop_restoration_params (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1LoopRestorationParams *lr_params;
  GstAV1SequenceHeaderOBU *seq_header;
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  guint8 lr_type;
  gint i;
  guint8 use_chroma_lr /* useChromaLr */ ;
  const GstAV1FrameRestorationType remap_lr_type /* Remap_Lr_Type */ [4] = {
    GST_AV1_FRAME_RESTORE_NONE,
    GST_AV1_FRAME_RESTORE_SWITCHABLE,
    GST_AV1_FRAME_RESTORE_WIENER, GST_AV1_FRAME_RESTORE_SGRPROJ
  };

  g_assert (parser->seq_header);

  lr_params = &frame_header->loop_restoration_params;
  seq_header = parser->seq_header;

  if (frame_header->all_lossless || frame_header->allow_intrabc
      || !seq_header->enable_restoration) {
    for (i = 0; i < GST_AV1_MAX_NUM_PLANES; i++)
      lr_params->frame_restoration_type[i] = GST_AV1_FRAME_RESTORE_NONE;

    lr_params->uses_lr = 0;
    goto success;
  }

  lr_params->uses_lr = 0;
  use_chroma_lr = 0;
  for (i = 0; i < seq_header->num_planes; i++) {
    lr_type = AV1_READ_BITS_CHECKED (br, 2, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    lr_params->frame_restoration_type[i] = remap_lr_type[lr_type];
    if (lr_params->frame_restoration_type[i] != GST_AV1_FRAME_RESTORE_NONE) {
      lr_params->uses_lr = 1;
      if (i > 0) {
        use_chroma_lr = 1;
      }
    }
  }

  if (lr_params->uses_lr) {
    if (seq_header->use_128x128_superblock) {
      lr_params->lr_unit_shift = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      lr_params->lr_unit_shift++;
    } else {
      guint8 lr_unit_extra_shift;

      lr_params->lr_unit_shift = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (lr_params->lr_unit_shift) {
        lr_unit_extra_shift = AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        lr_params->lr_unit_shift += lr_unit_extra_shift;
      }
    }

    lr_params->loop_restoration_size[0] =
        GST_AV1_RESTORATION_TILESIZE_MAX >> (2 - lr_params->lr_unit_shift);
    if (seq_header->color_config.subsampling_x
        && seq_header->color_config.subsampling_y && use_chroma_lr) {
      lr_params->lr_uv_shift = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    } else {
      lr_params->lr_uv_shift = 0;
    }

    lr_params->loop_restoration_size[1] =
        lr_params->loop_restoration_size[0] >> lr_params->lr_uv_shift;
    lr_params->loop_restoration_size[2] =
        lr_params->loop_restoration_size[0] >> lr_params->lr_uv_shift;
  }

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse loop restoration params error %d", retval);
  return retval;
}

/* 5.9.21 */
static GstAV1ParserResult
gst_av1_parse_tx_mode (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval;

  if (frame_header->coded_lossless == 1) {
    frame_header->tx_mode = GST_AV1_TX_MODE_ONLY_4x4;
  } else {
    frame_header->tx_mode_select = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      return retval;

    if (frame_header->tx_mode_select) {
      frame_header->tx_mode = GST_AV1_TX_MODE_SELECT;
    } else {
      frame_header->tx_mode = GST_AV1_TX_MODE_LARGEST;
    }
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.3 */
static gint
gst_av1_get_relative_dist (GstAV1SequenceHeaderOBU * seq_header, gint a, gint b)
{
  gint m, diff;
  if (!seq_header->enable_order_hint)
    return 0;
  diff = a - b;
  m = 1 << seq_header->order_hint_bits_minus_1;
  diff = (diff & (m - 1)) - (diff & m);
  return diff;
}

/* 5.9.22 */
static GstAV1ParserResult
gst_av1_parse_skip_mode_params (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ReferenceFrameInfo *ref_info;
  GstAV1SequenceHeaderOBU *seq_header;
  gint i;
  gint skip_mode_allowed /* skipModeAllowed */ ;
  GstAV1ParserResult retval;

  g_assert (parser->seq_header);

  seq_header = parser->seq_header;
  ref_info = &(parser->state.ref_info);
  skip_mode_allowed = 0;
  if (frame_header->frame_is_intra || !frame_header->reference_select
      || !seq_header->enable_order_hint) {
    skip_mode_allowed = 0;
  } else {
    gint forward_idx = -1 /* forwardIdx */ ;
    gint forward_hint = 0 /* forwardHint */ ;
    gint backward_idx = -1 /* backwardIdx */ ;
    gint backward_hint = 0 /* backwardHint */ ;
    gint ref_hint = 0 /* refHint */ ;

    for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
      ref_hint = ref_info->entry[frame_header->ref_frame_idx[i]].ref_order_hint;
      if (gst_av1_get_relative_dist (parser->seq_header, ref_hint,
              frame_header->order_hint) < 0) {
        if (forward_idx < 0
            || gst_av1_get_relative_dist (parser->seq_header, ref_hint,
                forward_hint) > 0) {
          forward_idx = i;
          forward_hint = ref_hint;
        }
      } else
          if (gst_av1_get_relative_dist (parser->seq_header, ref_hint,
              frame_header->order_hint) > 0) {
        if (backward_idx < 0
            || gst_av1_get_relative_dist (parser->seq_header, ref_hint,
                backward_hint) < 0) {
          backward_idx = i;
          backward_hint = ref_hint;
        }
      }
    }

    if (forward_idx < 0) {
      skip_mode_allowed = 0;
    } else if (backward_idx >= 0) {
      skip_mode_allowed = 1;
      frame_header->skip_mode_frame[0] =
          GST_AV1_REF_LAST_FRAME + MIN (forward_idx, backward_idx);
      frame_header->skip_mode_frame[1] =
          GST_AV1_REF_LAST_FRAME + MAX (forward_idx, backward_idx);
    } else {
      gint second_forward_idx = -1 /* secondForwardIdx */ ;
      gint second_forward_hint = 0 /* secondForwardHint */ ;
      for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
        ref_hint =
            ref_info->entry[frame_header->ref_frame_idx[i]].ref_order_hint;
        if (gst_av1_get_relative_dist (parser->seq_header, ref_hint,
                forward_hint) < 0) {
          if (second_forward_idx < 0
              || gst_av1_get_relative_dist (parser->seq_header, ref_hint,
                  second_forward_hint) > 0) {
            second_forward_idx = i;
            second_forward_hint = ref_hint;
          }
        }
      }

      if (second_forward_idx < 0) {
        skip_mode_allowed = 0;
      } else {
        skip_mode_allowed = 1;
        frame_header->skip_mode_frame[0] =
            GST_AV1_REF_LAST_FRAME + MIN (forward_idx, second_forward_idx);
        frame_header->skip_mode_frame[1] =
            GST_AV1_REF_LAST_FRAME + MAX (forward_idx, second_forward_idx);
      }
    }
  }

  if (skip_mode_allowed) {
    frame_header->skip_mode_present = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      return retval;
  } else {
    frame_header->skip_mode_present = 0;
  }

  return GST_AV1_PARSER_OK;
}

/* 5.9.28 */
static gint
gst_av1_decode_subexp (GstBitReader * br, gint numSyms,
    GstAV1ParserResult * retval)
{
  gint i = 0;
  gint mk = 0;
  gint k = 3;
  gint subexp_final_bits = 0;
  gint subexp_more_bits = 0;
  gint subexp_bits = 0;

  while (1) {
    gint b2 = i ? k + i - 1 : k;
    gint a = 1 << b2;
    if (numSyms <= mk + 3 * a) {
      subexp_final_bits = av1_bitstreamfn_ns (br, numSyms - mk, retval);
      if (*retval != GST_AV1_PARSER_OK)
        return 0;
      return subexp_final_bits + mk;
    } else {
      subexp_more_bits = AV1_READ_BITS_CHECKED (br, 1, retval);
      if (*retval != GST_AV1_PARSER_OK)
        return 0;
      if (subexp_more_bits) {
        i++;
        mk += a;
      } else {
        subexp_bits = AV1_READ_BITS_CHECKED (br, b2, retval);
        if (*retval != GST_AV1_PARSER_OK)
          return 0;
        return subexp_bits + mk;
      }
    }
  }
}

/* 5.9.27 */
static gint
gst_av1_decode_unsigned_subexp_with_ref (GstBitReader * br, gint mx,
    gint r, GstAV1ParserResult * retval)
{
  gint v;

  v = gst_av1_decode_subexp (br, mx, retval);
  if ((r << 1) <= mx) {
    return av1_helper_inverse_recenter (r, v);
  } else {
    return mx - 1 - av1_helper_inverse_recenter (mx - 1 - r, v);
  }
}

/* 5.9.26 */
static gint
gst_av1_decode_signed_subexp_with_ref (GstBitReader * br, gint low,
    gint high, gint r, GstAV1ParserResult * retval)
{
  return gst_av1_decode_unsigned_subexp_with_ref (br,
      high - low, r - low, retval) + low;
}

/* 5.9.25 */
static GstAV1ParserResult
gst_av1_parse_global_param (GstAV1Parser * parser,
    GstAV1FrameHeaderOBU * frame_header, GstBitReader * br,
    GstAV1GlobalMotionParams * gm_params, GstAV1WarpModelType type,
    gint32 prev_gm_params[GST_AV1_NUM_REF_FRAMES][6], gint ref, gint idx)
{
  GstAV1ParserResult retval;
  gint prec_diff /* precDiff */ , wm_round, mx, r;
  gint abs_bits /* absBits */  = GST_AV1_GM_ABS_ALPHA_BITS;
  gint prec_bits /* precBits */  = GST_AV1_GM_ALPHA_PREC_BITS;
  gint sub;

  if (idx < 2) {
    if (type == GST_AV1_WARP_MODEL_TRANSLATION) {
      abs_bits =
          GST_AV1_GM_ABS_TRANS_ONLY_BITS -
          (frame_header->allow_high_precision_mv ? 0 : 1);
      prec_bits =
          GST_AV1_GM_TRANS_ONLY_PREC_BITS -
          (frame_header->allow_high_precision_mv ? 0 : 1);
    } else {
      abs_bits = GST_AV1_GM_ABS_TRANS_BITS;
      prec_bits = GST_AV1_GM_TRANS_PREC_BITS;
    }
  }

  prec_diff = GST_AV1_WARPEDMODEL_PREC_BITS - prec_bits;
  wm_round = (idx % 3) == 2 ? (1 << GST_AV1_WARPEDMODEL_PREC_BITS) : 0;
  sub = (idx % 3) == 2 ? (1 << prec_bits) : 0;
  mx = (1 << abs_bits);
  r = (prev_gm_params[ref][idx] >> prec_diff) - sub;
  gm_params->gm_params[ref][idx] =
      (gst_av1_decode_signed_subexp_with_ref (br, -mx, mx + 1, r,
          &retval) << prec_diff) + wm_round;
  if (retval != GST_AV1_PARSER_OK)
    return retval;
  return GST_AV1_PARSER_OK;
}

static gboolean
gst_av1_parser_is_shear_params_valid (gint32 gm_params[6])
{
  const gint32 *mat = gm_params;
  gint16 alpha, beta, gamma, delta;
  gint16 shift;
  gint16 y;
  gint16 v;
  guint i;
  gboolean default_warp_params;

  if (!(mat[2] > 0))
    return FALSE;

  default_warp_params = TRUE;
  for (i = 0; i < 6; i++) {
    if (gm_params[i] != ((i % 3 == 2) ? 1 << GST_AV1_WARPEDMODEL_PREC_BITS : 0)) {
      default_warp_params = FALSE;
      break;
    }
  }
  if (default_warp_params)
    return TRUE;

  alpha = CLAMP (mat[2] - (1 << GST_AV1_WARPEDMODEL_PREC_BITS),
      G_MININT16, G_MAXINT16);
  beta = CLAMP (mat[3], G_MININT16, G_MAXINT16);
  y = av1_helper_resolve_divisor_32 (ABS (mat[2]), &shift)
      * (mat[2] < 0 ? -1 : 1);
  v = ((gint64) mat[4] * (1 << GST_AV1_WARPEDMODEL_PREC_BITS)) * y;
  gamma =
      CLAMP ((gint) av1_helper_round_power_of_two_signed (v, shift), G_MININT16,
      G_MAXINT16);
  v = ((gint64) mat[3] * mat[4]) * y;
  delta =
      CLAMP (mat[5] - (gint) av1_helper_round_power_of_two_signed (v,
          shift) - (1 << GST_AV1_WARPEDMODEL_PREC_BITS), G_MININT16,
      G_MAXINT16);

  alpha =
      av1_helper_round_power_of_two_signed (alpha,
      GST_AV1_WARP_PARAM_REDUCE_BITS) * (1 << GST_AV1_WARP_PARAM_REDUCE_BITS);
  beta =
      av1_helper_round_power_of_two_signed (beta,
      GST_AV1_WARP_PARAM_REDUCE_BITS) * (1 << GST_AV1_WARP_PARAM_REDUCE_BITS);
  gamma =
      av1_helper_round_power_of_two_signed (gamma,
      GST_AV1_WARP_PARAM_REDUCE_BITS) * (1 << GST_AV1_WARP_PARAM_REDUCE_BITS);
  delta =
      av1_helper_round_power_of_two_signed (delta,
      GST_AV1_WARP_PARAM_REDUCE_BITS) * (1 << GST_AV1_WARP_PARAM_REDUCE_BITS);

  if ((4 * ABS (alpha) + 7 * ABS (beta) >= (1 << GST_AV1_WARPEDMODEL_PREC_BITS))
      || (4 * ABS (gamma) + 4 * ABS (delta) >=
          (1 << GST_AV1_WARPEDMODEL_PREC_BITS)))
    return FALSE;

  return TRUE;
}

/* 5.9.24 */
static GstAV1ParserResult
gst_av1_parse_global_motion_params (GstAV1Parser * parser,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1WarpModelType type;
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  gint i, ref;
  GstAV1GlobalMotionParams *gm_params = &(frame_header->global_motion_params);
  gint32 prev_gm_params[GST_AV1_NUM_REF_FRAMES][6] /* PrevGmParams */ ;

  /* init value */
  gm_params->gm_type[GST_AV1_REF_INTRA_FRAME] = GST_AV1_WARP_MODEL_IDENTITY;
  for (ref = GST_AV1_REF_LAST_FRAME; ref <= GST_AV1_REF_ALTREF_FRAME; ref++) {
    gm_params->invalid[ref] = 0;
    gm_params->gm_type[ref] = GST_AV1_WARP_MODEL_IDENTITY;
    for (i = 0; i < 6; i++) {
      gm_params->gm_params[ref][i] =
          ((i % 3 == 2) ? 1 << GST_AV1_WARPEDMODEL_PREC_BITS : 0);
    }
  }

  if (frame_header->frame_is_intra)
    goto success;

  if (frame_header->primary_ref_frame != GST_AV1_PRIMARY_REF_NONE) {
    GstAV1GlobalMotionParams *ref_global_motion_params =
        &parser->state.ref_info.entry[frame_header->
        ref_frame_idx[frame_header->primary_ref_frame]].
        ref_global_motion_params;
    memcpy (prev_gm_params, ref_global_motion_params->gm_params,
        sizeof (gint32) * GST_AV1_NUM_REF_FRAMES * 6);
  } else {
    for (ref = GST_AV1_REF_INTRA_FRAME; ref < GST_AV1_NUM_REF_FRAMES; ref++)
      for (i = 0; i < 6; i++)
        prev_gm_params[ref][i] =
            ((i % 3 == 2) ? 1 << GST_AV1_WARPEDMODEL_PREC_BITS : 0);
  }

  for (ref = GST_AV1_REF_LAST_FRAME; ref <= GST_AV1_REF_ALTREF_FRAME; ref++) {
    gm_params->is_global[ref] = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (gm_params->is_global[ref]) {
      gm_params->is_rot_zoom[ref] = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (gm_params->is_rot_zoom[ref]) {
        type = GST_AV1_WARP_MODEL_ROTZOOM;
      } else {
        gm_params->is_translation[ref] = AV1_READ_BIT_CHECKED (br, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
        type =
            gm_params->is_translation[ref] ? GST_AV1_WARP_MODEL_TRANSLATION :
            GST_AV1_WARP_MODEL_AFFINE;
      }
    } else {
      type = GST_AV1_WARP_MODEL_IDENTITY;
    }
    gm_params->gm_type[ref] = type;

    if (type >= GST_AV1_WARP_MODEL_ROTZOOM) {
      retval =
          gst_av1_parse_global_param (parser, frame_header, br, gm_params, type,
          prev_gm_params, ref, 2);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      retval =
          gst_av1_parse_global_param (parser, frame_header, br, gm_params, type,
          prev_gm_params, ref, 3);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (type == GST_AV1_WARP_MODEL_AFFINE) {
        retval =
            gst_av1_parse_global_param (parser, frame_header, br, gm_params,
            type, prev_gm_params, ref, 4);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        retval =
            gst_av1_parse_global_param (parser, frame_header, br, gm_params,
            type, prev_gm_params, ref, 5);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      } else {
        gm_params->gm_params[ref][4] = gm_params->gm_params[ref][3] * (-1);
        gm_params->gm_params[ref][5] = gm_params->gm_params[ref][2];
      }
    }
    if (type >= GST_AV1_WARP_MODEL_TRANSLATION) {
      retval =
          gst_av1_parse_global_param (parser, frame_header, br, gm_params, type,
          prev_gm_params, ref, 0);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
      retval =
          gst_av1_parse_global_param (parser, frame_header, br, gm_params, type,
          prev_gm_params, ref, 1);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    if (type <= GST_AV1_WARP_MODEL_AFFINE)
      gm_params->invalid[ref] =
          !gst_av1_parser_is_shear_params_valid (gm_params->gm_params[ref]);
  }

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse global motion params error %d", retval);
  return retval;
}

/* 5.9.30 */
static GstAV1ParserResult
gst_av1_parse_film_grain_params (GstAV1Parser * parser, GstBitReader * br,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1FilmGrainParams *fg_params;
  GstAV1SequenceHeaderOBU *seq_header;
  gint i;
  gint num_pos_chroma /* numPosChroma */ , num_pos_luma /* numPosLuma */ ;
  GstAV1ParserResult ret = GST_AV1_PARSER_OK;

  g_assert (parser->seq_header);

  fg_params = &frame_header->film_grain_params;
  seq_header = parser->seq_header;
  if (!seq_header->film_grain_params_present || (!frame_header->show_frame
          && !frame_header->showable_frame)) {
    /* reset_grain_params() is a function call that indicates that all the
       syntax elements read in film_grain_params should be set equal to 0. */
    memset (fg_params, 0, sizeof (*fg_params));
    goto success;
  }

  fg_params->apply_grain = AV1_READ_BIT_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;
  if (!fg_params->apply_grain) {
    /* reset_grain_params() */
    memset (fg_params, 0, sizeof (*fg_params));
    goto success;
  }

  fg_params->grain_seed = AV1_READ_UINT16_CHECKED (br, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  if (frame_header->frame_type == GST_AV1_INTER_FRAME) {
    fg_params->update_grain = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
  } else {
    fg_params->update_grain = 1;
  }

  if (!fg_params->update_grain) {
    guint16 temp_grain_seed /* tempGrainSeed */ ;
    gint j;
    gboolean found = FALSE;

    fg_params->film_grain_params_ref_idx = AV1_READ_BITS_CHECKED (br, 3, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;

    for (j = 0; j < GST_AV1_REFS_PER_FRAME; j++) {
      if (frame_header->ref_frame_idx[j] ==
          fg_params->film_grain_params_ref_idx) {
        found = TRUE;
        break;
      }
    }

    if (!found) {
      GST_INFO ("Invalid film grain reference idx %d.",
          fg_params->film_grain_params_ref_idx);
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    if (!parser->state.ref_info.entry[fg_params->film_grain_params_ref_idx].
        ref_valid) {
      GST_INFO ("Invalid ref info of film grain idx %d.",
          fg_params->film_grain_params_ref_idx);
      ret = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    temp_grain_seed = fg_params->grain_seed;
    memcpy (fg_params,
        &parser->state.ref_info.entry[fg_params->film_grain_params_ref_idx].
        ref_film_grain_params, sizeof (GstAV1FilmGrainParams));
    fg_params->grain_seed = temp_grain_seed;

    goto success;
  }

  fg_params->num_y_points = AV1_READ_BITS_CHECKED (br, 4, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  for (i = 0; i < fg_params->num_y_points; i++) {
    if (AV1_REMAINING_BITS (br) < 8 + 8) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    fg_params->point_y_value[i] = AV1_READ_UINT8 (br);
    fg_params->point_y_scaling[i] = AV1_READ_UINT8 (br);
  }

  if (seq_header->color_config.mono_chrome) {
    fg_params->chroma_scaling_from_luma = 0;
  } else {
    fg_params->chroma_scaling_from_luma = AV1_READ_BIT_CHECKED (br, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
  }

  if (seq_header->color_config.mono_chrome
      || fg_params->chroma_scaling_from_luma
      || (seq_header->color_config.subsampling_x == 1
          && seq_header->color_config.subsampling_y == 1
          && fg_params->num_y_points == 0)) {
    fg_params->num_cb_points = 0;
    fg_params->num_cr_points = 0;
  } else {
    fg_params->num_cb_points = AV1_READ_BITS_CHECKED (br, 4, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
    for (i = 0; i < fg_params->num_cb_points; i++) {
      if (AV1_REMAINING_BITS (br) < 8 + 8) {
        ret = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }
      fg_params->point_cb_value[i] = AV1_READ_UINT8 (br);
      fg_params->point_cb_scaling[i] = AV1_READ_UINT8 (br);
    }

    fg_params->num_cr_points = AV1_READ_BITS_CHECKED (br, 4, &ret);
    if (ret != GST_AV1_PARSER_OK)
      goto error;
    for (i = 0; i < fg_params->num_cr_points; i++) {
      if (AV1_REMAINING_BITS (br) < 8 + 8) {
        ret = GST_AV1_PARSER_NO_MORE_DATA;
        goto error;
      }
      fg_params->point_cr_value[i] = AV1_READ_UINT8 (br);
      fg_params->point_cr_scaling[i] = AV1_READ_UINT8 (br);
    }
  }

  fg_params->grain_scaling_minus_8 = AV1_READ_BITS_CHECKED (br, 2, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  fg_params->ar_coeff_lag = AV1_READ_BITS_CHECKED (br, 2, &ret);
  if (ret != GST_AV1_PARSER_OK)
    goto error;

  num_pos_luma = 2 * fg_params->ar_coeff_lag * (fg_params->ar_coeff_lag + 1);
  if (fg_params->num_y_points) {
    num_pos_chroma = num_pos_luma + 1;
    for (i = 0; i < num_pos_luma; i++) {
      fg_params->ar_coeffs_y_plus_128[i] = AV1_READ_UINT8_CHECKED (br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;
    }
  } else {
    num_pos_chroma = num_pos_luma;
  }

  if (fg_params->chroma_scaling_from_luma || fg_params->num_cb_points) {
    for (i = 0; i < num_pos_chroma; i++) {
      fg_params->ar_coeffs_cb_plus_128[i] = AV1_READ_UINT8_CHECKED (br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  if (fg_params->chroma_scaling_from_luma || fg_params->num_cr_points) {
    for (i = 0; i < num_pos_chroma; i++) {
      fg_params->ar_coeffs_cr_plus_128[i] = AV1_READ_UINT8_CHECKED (br, &ret);
      if (ret != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  if (AV1_REMAINING_BITS (br) < 2 + 2) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }
  fg_params->ar_coeff_shift_minus_6 = AV1_READ_BITS (br, 2);
  fg_params->grain_scale_shift = AV1_READ_BITS (br, 2);

  if (fg_params->num_cb_points) {
    if (AV1_REMAINING_BITS (br) < 8 + 8 + 9) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    fg_params->cb_mult = AV1_READ_BITS (br, 8);
    fg_params->cb_luma_mult = AV1_READ_BITS (br, 8);
    fg_params->cb_offset = AV1_READ_BITS (br, 9);
  }

  if (fg_params->num_cr_points) {
    if (AV1_REMAINING_BITS (br) < 8 + 8 + 9) {
      ret = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    fg_params->cr_mult = AV1_READ_BITS (br, 8);
    fg_params->cr_luma_mult = AV1_READ_BITS (br, 8);
    fg_params->cr_offset = AV1_READ_BITS (br, 9);
  }

  if (AV1_REMAINING_BITS (br) < 2) {
    ret = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }
  fg_params->overlap_flag = AV1_READ_BIT (br);
  fg_params->clip_to_restricted_range = AV1_READ_BIT (br);

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse film grain params error %d", ret);
  return ret;
}

/* 5.9.4 */
static void
gst_av1_mark_ref_frames (GstAV1Parser * parser, GstBitReader * br, gint idLen)
{
  GstAV1ReferenceFrameInfo *ref_info;
  GstAV1SequenceHeaderOBU *seq_header;
  gint i, diff_len /* diffLen */ ;

  seq_header = parser->seq_header;
  ref_info = &(parser->state.ref_info);
  diff_len = seq_header->delta_frame_id_length_minus_2 + 2;

  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    if (parser->state.current_frame_id > (1 << diff_len)) {
      if (ref_info->entry[i].ref_frame_id > parser->state.current_frame_id
          || ref_info->entry[i].ref_frame_id <
          (parser->state.current_frame_id - (1 << diff_len)))
        ref_info->entry[i].ref_valid = 0;
    } else {
      if (ref_info->entry[i].ref_frame_id > parser->state.current_frame_id
          && ref_info->entry[i].ref_frame_id <
          ((1 << idLen) + parser->state.current_frame_id - (1 << diff_len)))
        ref_info->entry[i].ref_valid = 0;
    }
  }
}

/* 5.11.14 */
static gboolean
gst_av1_seg_feature_active_idx (GstAV1Parser * parser,
    GstAV1FrameHeaderOBU * frame_header, gint idx, gint feature)
{
  return frame_header->segmentation_params.segmentation_enabled
      && frame_header->segmentation_params.feature_enabled[idx][feature];
}

/* 7.12.2 */
static gint
gst_av1_get_qindex (GstAV1Parser * parser,
    GstAV1FrameHeaderOBU * frame_header, gboolean ignoreDeltaQ, gint segmentId)
{
  gint qindex;
  if (gst_av1_seg_feature_active_idx (parser, frame_header, segmentId,
          GST_AV1_SEG_LVL_ALT_Q)) {
    gint data =
        frame_header->
        segmentation_params.feature_data[segmentId][GST_AV1_SEG_LVL_ALT_Q];
    qindex = frame_header->quantization_params.base_q_idx + data;
    if (ignoreDeltaQ == 0 && frame_header->quantization_params.delta_q_present)
      qindex = qindex + frame_header->quantization_params.delta_q_res;
    return CLAMP (qindex, 0, 255);
  } else
    return frame_header->quantization_params.base_q_idx;
}

/* 7.8 */
static void
gst_av1_set_frame_refs (GstAV1Parser * parser,
    GstAV1SequenceHeaderOBU * seq_header, GstAV1FrameHeaderOBU * frame_header)
{
  const GstAV1ReferenceFrame ref_frame_list[GST_AV1_REFS_PER_FRAME - 2] = {
    GST_AV1_REF_LAST2_FRAME,
    GST_AV1_REF_LAST3_FRAME,
    GST_AV1_REF_BWDREF_FRAME,
    GST_AV1_REF_ALTREF2_FRAME,
    GST_AV1_REF_ALTREF_FRAME
  };
  gboolean used_frame[GST_AV1_NUM_REF_FRAMES];
  gint shifted_order_hints[GST_AV1_NUM_REF_FRAMES];
  gint cur_frame_hint = 1 << (seq_header->order_hint_bits - 1);
  gint last_order_hint, earliest_order_hint;
  gint ref, hint;
  gint i, j;

  g_assert (seq_header->enable_order_hint);
  g_assert (seq_header->order_hint_bits_minus_1 >= 0);

  for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++)
    frame_header->ref_frame_idx[i] = -1;
  frame_header->ref_frame_idx[GST_AV1_REF_LAST_FRAME -
      GST_AV1_REF_LAST_FRAME] = frame_header->last_frame_idx;
  frame_header->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME -
      GST_AV1_REF_LAST_FRAME] = frame_header->gold_frame_idx;

  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
    used_frame[i] = 0;
  used_frame[frame_header->last_frame_idx] = 1;
  used_frame[frame_header->gold_frame_idx] = 1;

  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
    shifted_order_hints[i] = cur_frame_hint +
        gst_av1_get_relative_dist (seq_header,
        parser->state.ref_info.entry[i].ref_order_hint,
        frame_header->order_hint);

  last_order_hint = shifted_order_hints[frame_header->last_frame_idx];

  /* === Backward Reference Frames === */
  /* The ALTREF_FRAME reference is set to be a backward
     reference to the frame with highest output order. */
  ref = -1;
  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    hint = shifted_order_hints[i];
    if (!used_frame[i] && hint >= cur_frame_hint
        && (ref < 0 || hint >= last_order_hint)) {
      ref = i;
      last_order_hint = hint;
    }
  }
  if (ref >= 0) {
    frame_header->ref_frame_idx[GST_AV1_REF_ALTREF_FRAME -
        GST_AV1_REF_LAST_FRAME] = ref;
    used_frame[ref] = 1;
  }

  /* The BWDREF_FRAME reference is set to be a backward reference
     to the closest frame. */
  ref = -1;
  earliest_order_hint = last_order_hint;
  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    hint = shifted_order_hints[i];
    if (!used_frame[i] && hint >= cur_frame_hint
        && (ref < 0 || hint < earliest_order_hint)) {
      ref = i;
      earliest_order_hint = hint;
    }
  }
  if (ref >= 0) {
    frame_header->ref_frame_idx[GST_AV1_REF_BWDREF_FRAME -
        GST_AV1_REF_LAST_FRAME] = ref;
    used_frame[ref] = 1;
  }

  /* The ALTREF2_FRAME reference is set to the next closest
     backward reference. */
  ref = -1;
  earliest_order_hint = last_order_hint;
  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    hint = shifted_order_hints[i];
    if (!used_frame[i] && hint >= cur_frame_hint
        && (ref < 0 || hint < earliest_order_hint)) {
      ref = i;
      earliest_order_hint = hint;
    }
  }
  if (ref >= 0) {
    frame_header->ref_frame_idx[GST_AV1_REF_ALTREF2_FRAME -
        GST_AV1_REF_LAST_FRAME] = ref;
    used_frame[ref] = 1;
  }

  /* === Forward Reference Frames === */

  /* The remaining references are set to be forward references
     in anti-chronological order. */
  last_order_hint = 0;
  for (i = 0; i < GST_AV1_REFS_PER_FRAME - 2; i++) {
    GstAV1ReferenceFrame ref_frame = ref_frame_list[i];
    if (frame_header->ref_frame_idx[ref_frame - GST_AV1_REF_LAST_FRAME] < 0) {
      ref = -1;
      for (j = 0; j < GST_AV1_NUM_REF_FRAMES; j++) {
        hint = shifted_order_hints[j];
        if (!used_frame[j] && hint < cur_frame_hint &&
            (ref < 0 || hint >= last_order_hint)) {
          ref = j;
          last_order_hint = hint;
        }
      }

      if (ref >= 0) {
        frame_header->ref_frame_idx[ref_frame - GST_AV1_REF_LAST_FRAME] = ref;
        used_frame[ref] = 1;
      }
    }
  }

  /* Finally, any remaining references are set to the reference frame
     with smallest output order. */
  ref = -1;
  earliest_order_hint = cur_frame_hint * 2;
  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    hint = shifted_order_hints[i];
    if (ref < 0 || hint < earliest_order_hint) {
      ref = i;
      earliest_order_hint = hint;
    }
  }
  for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++)
    if (frame_header->ref_frame_idx[i] < 0)
      frame_header->ref_frame_idx[i] = ref;
}

/* 5.9.2 */
static GstAV1ParserResult
gst_av1_parse_uncompressed_frame_header (GstAV1Parser * parser, GstAV1OBU * obu,
    GstBitReader * br, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstAV1ReferenceFrameInfo *ref_info;
  GstAV1SequenceHeaderOBU *seq_header;
  gint i, op_num /* opNum */ ;
  gint segment_id /* segmentId */ , all_frames /* allFrames */ ;
  gint id_len /* idLen */  = 0;

  if (!parser->seq_header) {
    GST_WARNING ("Missing OBU Reference: seq_header");
    retval = GST_AV1_PARSER_MISSING_OBU_REFERENCE;
    goto error;
  }

  seq_header = parser->seq_header;
  ref_info = &(parser->state.ref_info);
  if (seq_header->frame_id_numbers_present_flag)
    id_len = seq_header->additional_frame_id_length_minus_1 + 1 +
        seq_header->delta_frame_id_length_minus_2 + 2;
  all_frames = (1 << GST_AV1_NUM_REF_FRAMES) - 1;

  if (seq_header->reduced_still_picture_header) {
    frame_header->show_existing_frame = 0;
    frame_header->frame_type = GST_AV1_KEY_FRAME;
    frame_header->frame_is_intra = 1;
    frame_header->show_frame = 1;
    frame_header->showable_frame = 0;
    if (parser->state.sequence_changed) {
      /* This is the start of a new coded video sequence. */
      parser->state.sequence_changed = 0;
      parser->state.begin_first_frame = 1;
    }
  } else {
    frame_header->show_existing_frame = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (frame_header->show_existing_frame) {
      if (parser->state.sequence_changed) {
        GST_INFO ("New sequence header starts with a show_existing_frame.");
        retval = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }

      frame_header->frame_to_show_map_idx =
          AV1_READ_BITS_CHECKED (br, 3, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (!ref_info->entry[frame_header->frame_to_show_map_idx].ref_valid) {
        GST_INFO ("The frame_to_show %d is invalid.",
            frame_header->frame_to_show_map_idx);
        retval = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }

      if (seq_header->decoder_model_info_present_flag
          && !seq_header->timing_info.equal_picture_interval)
        frame_header->frame_presentation_time =
            AV1_READ_BITS_CHECKED (br,
            seq_header->
            decoder_model_info.frame_presentation_time_length_minus_1 + 1,
            &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      frame_header->refresh_frame_flags = 0;
      if (seq_header->frame_id_numbers_present_flag) {
        g_assert (id_len > 0);
        frame_header->display_frame_id =
            AV1_READ_BITS_CHECKED (br, id_len, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
        if (frame_header->display_frame_id !=
            ref_info->entry[frame_header->frame_to_show_map_idx].ref_frame_id) {
          GST_INFO ("Reference frame ID mismatch");
          retval = GST_AV1_PARSER_BITSTREAM_ERROR;
          goto error;
        }
      }

      frame_header->frame_type =
          ref_info->entry[frame_header->frame_to_show_map_idx].ref_frame_type;
      if (frame_header->frame_type == GST_AV1_KEY_FRAME) {
        frame_header->refresh_frame_flags = all_frames;
      }

      /* just use the frame_to_show's grain_params
       * if (seq_header->film_grain_params_present)
       *     load_grain_params () */

      goto success;
    }

    frame_header->frame_type = AV1_READ_BITS_CHECKED (br, 2, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (parser->state.sequence_changed) {
      if (frame_header->frame_type == GST_AV1_KEY_FRAME) {
        /* This is the start of a new coded video sequence. */
        parser->state.sequence_changed = FALSE;
        parser->state.begin_first_frame = TRUE;
      } else {
        GST_INFO ("Sequence header has changed without a keyframe.");
        retval = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }
    }

    frame_header->frame_is_intra =
        (frame_header->frame_type == GST_AV1_INTRA_ONLY_FRAME
        || frame_header->frame_type == GST_AV1_KEY_FRAME);

    frame_header->show_frame = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (seq_header->still_picture &&
        (frame_header->frame_type != GST_AV1_KEY_FRAME
            || !frame_header->show_frame)) {
      GST_INFO ("Still pictures must be coded as shown keyframes");
      retval = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }

    if (frame_header->show_frame
        && seq_header->decoder_model_info_present_flag
        && !seq_header->timing_info.equal_picture_interval) {
      frame_header->frame_presentation_time =
          AV1_READ_BITS_CHECKED (br,
          seq_header->decoder_model_info.
          frame_presentation_time_length_minus_1 + 1, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    if (frame_header->show_frame) {
      frame_header->showable_frame =
          (frame_header->frame_type != GST_AV1_KEY_FRAME);
    } else {
      frame_header->showable_frame = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    if (frame_header->frame_type == GST_AV1_SWITCH_FRAME
        || (frame_header->frame_type == GST_AV1_KEY_FRAME
            && frame_header->show_frame))
      frame_header->error_resilient_mode = 1;
    else {
      frame_header->error_resilient_mode = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  if (frame_header->frame_type == GST_AV1_KEY_FRAME && frame_header->show_frame) {
    for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
      ref_info->entry[i].ref_valid = 0;
      ref_info->entry[i].ref_order_hint = 0;
    }
    for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
      frame_header->order_hints[GST_AV1_REF_LAST_FRAME + i] = 0;
    }
  }

  frame_header->disable_cdf_update = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (seq_header->seq_force_screen_content_tools ==
      GST_AV1_SELECT_SCREEN_CONTENT_TOOLS) {
    frame_header->allow_screen_content_tools =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  } else {
    frame_header->allow_screen_content_tools =
        seq_header->seq_force_screen_content_tools;
  }

  if (frame_header->allow_screen_content_tools) {
    if (seq_header->seq_force_integer_mv == GST_AV1_SELECT_INTEGER_MV) {
      frame_header->force_integer_mv = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    } else {
      frame_header->force_integer_mv = seq_header->seq_force_integer_mv;
    }
  } else {
    frame_header->force_integer_mv = 0;
  }

  if (frame_header->frame_is_intra) {
    frame_header->force_integer_mv = 1;
  }

  if (seq_header->frame_id_numbers_present_flag) {
    gboolean have_prev_frame_id =
        !parser->state.begin_first_frame &&
        (!(frame_header->frame_type == GST_AV1_KEY_FRAME
            && frame_header->show_frame));
    if (have_prev_frame_id)
      parser->state.prev_frame_id = parser->state.current_frame_id;

    g_assert (id_len > 0);
    frame_header->current_frame_id =
        AV1_READ_BITS_CHECKED (br, id_len, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    parser->state.current_frame_id = frame_header->current_frame_id;
    /* Check whether the id and id diff is valid */
    if (have_prev_frame_id) {
      gint32 diff_frame_id;
      if (parser->state.current_frame_id > parser->state.prev_frame_id) {
        diff_frame_id =
            parser->state.current_frame_id - parser->state.prev_frame_id;
      } else {
        diff_frame_id = (1 << id_len) +
            parser->state.current_frame_id - parser->state.prev_frame_id;
      }
      if (parser->state.current_frame_id == parser->state.prev_frame_id ||
          diff_frame_id >= (1 << (id_len - 1))) {
        GST_INFO ("Invalid value of current_frame_id");
        retval = GST_AV1_PARSER_BITSTREAM_ERROR;
        goto error;
      }
    }

    gst_av1_mark_ref_frames (parser, br, id_len);
  } else {
    frame_header->current_frame_id = 0;
    parser->state.prev_frame_id = parser->state.current_frame_id;
    parser->state.current_frame_id = frame_header->current_frame_id;
  }

  if (frame_header->frame_type == GST_AV1_SWITCH_FRAME) {
    frame_header->frame_size_override_flag = 1;
  } else if (seq_header->reduced_still_picture_header) {
    frame_header->frame_size_override_flag = 0;
  } else {
    frame_header->frame_size_override_flag = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  frame_header->order_hint =
      AV1_READ_BITS_CHECKED (br, seq_header->order_hint_bits_minus_1 + 1,
      &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (frame_header->frame_is_intra || frame_header->error_resilient_mode) {
    frame_header->primary_ref_frame = GST_AV1_PRIMARY_REF_NONE;
  } else {
    frame_header->primary_ref_frame = AV1_READ_BITS_CHECKED (br, 3, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  if (seq_header->decoder_model_info_present_flag) {
    frame_header->buffer_removal_time_present_flag =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (frame_header->buffer_removal_time_present_flag) {
      for (op_num = 0; op_num <= seq_header->operating_points_cnt_minus_1;
          op_num++) {
        if (seq_header->
            operating_points[op_num].decoder_model_present_for_this_op) {
          gint op_pt_idc = seq_header->operating_points[op_num].idc;
          gint in_temporal_layer =
              (op_pt_idc >> obu->header.obu_temporal_id) & 1;
          gint in_spatial_layer =
              (op_pt_idc >> (obu->header.obu_spatial_id + 8)) & 1;
          if (op_pt_idc == 0 || (in_temporal_layer && in_spatial_layer)) {
            frame_header->buffer_removal_time[op_num] =
                AV1_READ_BITS_CHECKED (br,
                seq_header->decoder_model_info.
                buffer_removal_time_length_minus_1 + 1, &retval);
            if (retval != GST_AV1_PARSER_OK)
              goto error;
          } else {
            frame_header->buffer_removal_time[op_num] = 0;
          }
        } else {
          frame_header->buffer_removal_time[op_num] = 0;
        }
      }
    }
  }

  frame_header->allow_high_precision_mv = 0;
  frame_header->use_ref_frame_mvs = 0;
  frame_header->allow_intrabc = 0;
  if (frame_header->frame_type == GST_AV1_SWITCH_FRAME ||
      (frame_header->frame_type == GST_AV1_KEY_FRAME
          && frame_header->show_frame)) {
    frame_header->refresh_frame_flags = all_frames;
  } else {
    frame_header->refresh_frame_flags = AV1_READ_UINT8_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }
  if (frame_header->frame_type == GST_AV1_INTRA_ONLY_FRAME) {
    if (frame_header->refresh_frame_flags == 0xFF) {
      GST_INFO ("Intra only frames cannot have refresh flags 0xFF");
      retval = GST_AV1_PARSER_BITSTREAM_ERROR;
      goto error;
    }
  }

  if (!frame_header->frame_is_intra
      || frame_header->refresh_frame_flags != all_frames) {
    if (frame_header->error_resilient_mode && seq_header->enable_order_hint) {
      for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
        frame_header->ref_order_hint[i] = AV1_READ_BITS_CHECKED (br,
            seq_header->order_hint_bits_minus_1 + 1, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        if (frame_header->ref_order_hint[i] !=
            ref_info->entry[i].ref_order_hint)
          ref_info->entry[i].ref_valid = 0;
      }
    }
  }

  if (frame_header->frame_is_intra) {
    retval = gst_av1_parse_frame_size (parser, br, frame_header);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
    retval = gst_av1_parse_render_size (parser, br, frame_header);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
    if (frame_header->allow_screen_content_tools
        && parser->state.upscaled_width == parser->state.frame_width) {
      frame_header->allow_intrabc = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    frame_header->upscaled_width = parser->state.upscaled_width;
    frame_header->frame_width = parser->state.frame_width;
    frame_header->frame_height = parser->state.frame_height;
    frame_header->render_width = parser->state.render_width;
    frame_header->render_height = parser->state.render_height;
  } else {
    if (!seq_header->enable_order_hint) {
      frame_header->frame_refs_short_signaling = 0;
    } else {
      frame_header->frame_refs_short_signaling =
          AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;

      if (frame_header->frame_refs_short_signaling) {
        if (AV1_REMAINING_BITS (br) < 3 + 3) {
          retval = GST_AV1_PARSER_NO_MORE_DATA;
          goto error;
        }
        frame_header->last_frame_idx = AV1_READ_BITS (br, 3);
        frame_header->gold_frame_idx = AV1_READ_BITS (br, 3);
        gst_av1_set_frame_refs (parser, seq_header, frame_header);
      }
    }

    for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
      if (!frame_header->frame_refs_short_signaling) {
        frame_header->ref_frame_idx[i] = AV1_READ_BITS_CHECKED (br, 3, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;
      }

      if (seq_header->frame_id_numbers_present_flag) {
        gint32 delta_frame_id /* DeltaFrameId */ ;
        gint32 expected_frame_id;
        guint32 delta_frame_id_minus_1;

        g_assert (id_len > 0);

        delta_frame_id_minus_1 = AV1_READ_BITS_CHECKED (br,
            seq_header->delta_frame_id_length_minus_2 + 2, &retval);
        if (retval != GST_AV1_PARSER_OK)
          goto error;

        delta_frame_id = delta_frame_id_minus_1 + 1;
        expected_frame_id = (frame_header->current_frame_id + (1 << id_len) -
            delta_frame_id) % (1 << id_len);
        if (expected_frame_id !=
            parser->state.ref_info.entry[frame_header->
                ref_frame_idx[i]].ref_frame_id) {
          GST_INFO ("Reference buffer frame ID mismatch, expectedFrameId"
              " is %d wihle ref frame id is %d", expected_frame_id,
              parser->state.ref_info.entry[frame_header->
                  ref_frame_idx[i]].ref_frame_id);
          retval = GST_AV1_PARSER_BITSTREAM_ERROR;
          goto error;
        }
      }
    }

    if (frame_header->frame_size_override_flag
        && !frame_header->error_resilient_mode) {
      retval = gst_av1_parse_frame_size_with_refs (parser, br, frame_header);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    } else {
      retval = gst_av1_parse_frame_size (parser, br, frame_header);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
      retval = gst_av1_parse_render_size (parser, br, frame_header);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }
    frame_header->upscaled_width = parser->state.upscaled_width;
    frame_header->frame_width = parser->state.frame_width;
    frame_header->frame_height = parser->state.frame_height;
    frame_header->render_width = parser->state.render_width;
    frame_header->render_height = parser->state.render_height;

    if (frame_header->force_integer_mv) {
      frame_header->allow_high_precision_mv = 0;
    } else {
      frame_header->allow_high_precision_mv =
          AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    /* read_interpolation_filter() expand */
    frame_header->is_filter_switchable = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (frame_header->is_filter_switchable) {
      frame_header->interpolation_filter =
          GST_AV1_INTERPOLATION_FILTER_SWITCHABLE;
    } else {
      frame_header->interpolation_filter =
          AV1_READ_BITS_CHECKED (br, 2, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }

    frame_header->is_motion_mode_switchable =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    if (frame_header->error_resilient_mode || !seq_header->enable_ref_frame_mvs) {
      frame_header->use_ref_frame_mvs = 0;
    } else {
      frame_header->use_ref_frame_mvs = AV1_READ_BIT_CHECKED (br, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
    }
  }

  if (!frame_header->frame_is_intra) {
    for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
      gint refFrame = GST_AV1_REF_LAST_FRAME + i;
      gint hint =
          ref_info->entry[frame_header->ref_frame_idx[i]].ref_order_hint;
      frame_header->order_hints[refFrame] = hint;
      if (!seq_header->enable_order_hint) {
        frame_header->ref_frame_sign_bias[refFrame] = 0;
      } else {
        frame_header->ref_frame_sign_bias[refFrame] =
            (gst_av1_get_relative_dist (parser->seq_header, hint,
                frame_header->order_hint) > 0);
      }
    }
  }

  if (seq_header->reduced_still_picture_header
      || frame_header->disable_cdf_update)
    frame_header->disable_frame_end_update_cdf = 1;
  else {
    frame_header->disable_frame_end_update_cdf =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  if (frame_header->primary_ref_frame != GST_AV1_PRIMARY_REF_NONE &&
      !ref_info->entry[frame_header->ref_frame_idx[frame_header->
              primary_ref_frame]].ref_valid) {
    GST_INFO ("Primary ref point to an invalid frame");
    retval = GST_AV1_PARSER_BITSTREAM_ERROR;
    goto error;
  }

  if (frame_header->primary_ref_frame == GST_AV1_PRIMARY_REF_NONE) {
    /* do something in setup_past_independence() of parser level */
    gint8 *loop_filter_ref_deltas =
        frame_header->loop_filter_params.loop_filter_ref_deltas;

    frame_header->loop_filter_params.loop_filter_delta_enabled = 1;
    loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME] = 1;
    loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME] = 0;
    loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME] = 0;
    loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME] = 0;
    loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME] = 0;
    loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME] = -1;
    loop_filter_ref_deltas[GST_AV1_REF_ALTREF_FRAME] = -1;
    loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME] = -1;
    frame_header->loop_filter_params.loop_filter_mode_deltas[0] = 0;
    frame_header->loop_filter_params.loop_filter_mode_deltas[1] = 0;
  } else {
    /* do something in load_previous() of parser level */
    /*   load_loop_filter_params() */
    GstAV1LoopFilterParams *ref_lf_params =
        &parser->state.ref_info.entry[frame_header->
        ref_frame_idx[frame_header->primary_ref_frame]].ref_lf_params;
    gint8 *loop_filter_ref_deltas =
        frame_header->loop_filter_params.loop_filter_ref_deltas;

    /* Copy all from prime_ref */
    g_assert (parser->state.ref_info.
        entry[frame_header->ref_frame_idx[frame_header->primary_ref_frame]].
        ref_valid);
    loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME];
    loop_filter_ref_deltas[GST_AV1_REF_ALTREF_FRAME] =
        ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF_FRAME];
    for (i = 0; i < 2; i++)
      frame_header->loop_filter_params.loop_filter_mode_deltas[i] =
          ref_lf_params->loop_filter_mode_deltas[i];
  }

  /* @TODO:
     if ( primary_ref_frame == PRIMARY_REF_NONE ) {
     init_non_coeff_cdfs( )
     } else {
     load_cdfs( ref_frame_idx[primary_ref_frame] )
     }
   */
  /* @TODO:
     if ( use_ref_frame_mvs == 1 )
     motion_field_estimation( )
   */

  retval = gst_av1_parse_tile_info (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_quantization_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_segmentation_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_delta_q_params (parser, br,
      &(frame_header->quantization_params));
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_delta_lf_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  /* @TODO:
     if ( primary_ref_frame == PRIMARY_REF_NONE ) {
     init_coeff_cdfs( )
     } else {
     load_previous_segment_ids( )
     }
   */

  frame_header->coded_lossless = 1;
  for (segment_id = 0; segment_id < GST_AV1_MAX_SEGMENTS; segment_id++) {
    gint qindex = gst_av1_get_qindex (parser, frame_header, 1, segment_id);
    frame_header->lossless_array[segment_id] = (qindex == 0)
        && (frame_header->quantization_params.delta_q_y_dc == 0)
        && (frame_header->quantization_params.delta_q_u_ac == 0)
        && (frame_header->quantization_params.delta_q_u_dc == 0)
        && (frame_header->quantization_params.delta_q_v_ac == 0)
        && (frame_header->quantization_params.delta_q_v_dc == 0);
    if (!frame_header->lossless_array[segment_id])
      frame_header->coded_lossless = 0;
    if (frame_header->quantization_params.using_qmatrix) {
      if (frame_header->lossless_array[segment_id]) {
        frame_header->seg_qm_Level[0][segment_id] = 15;
        frame_header->seg_qm_Level[1][segment_id] = 15;
        frame_header->seg_qm_Level[2][segment_id] = 15;
      } else {
        frame_header->seg_qm_Level[0][segment_id] =
            frame_header->quantization_params.qm_y;
        frame_header->seg_qm_Level[1][segment_id] =
            frame_header->quantization_params.qm_u;
        frame_header->seg_qm_Level[2][segment_id] =
            frame_header->quantization_params.qm_v;
      }
    }
  }
  frame_header->all_lossless = frame_header->coded_lossless
      && (parser->state.frame_width == parser->state.upscaled_width);

  retval = gst_av1_parse_loop_filter_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_cdef_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_loop_restoration_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_tx_mode (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  /* 5.9.23 inlined frame_reference_mode () */
  if (frame_header->frame_is_intra) {
    frame_header->reference_select = 0;
  } else {
    frame_header->reference_select = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  retval = gst_av1_parse_skip_mode_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  if (frame_header->frame_is_intra ||
      frame_header->error_resilient_mode || !seq_header->enable_warped_motion)
    frame_header->allow_warped_motion = 0;
  else {
    frame_header->allow_warped_motion = AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  frame_header->reduced_tx_set = AV1_READ_BIT_CHECKED (br, &retval);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_global_motion_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  retval = gst_av1_parse_film_grain_params (parser, br, frame_header);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

success:
  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse uncompressed frame header error %d", retval);
  return retval;
}

/* 7.21 */
/**
 * gst_av1_parser_reference_frame_loading:
 * @parser: the #GstAV1Parser
 * @frame_header: a #GstAV1FrameHeaderOBU to load
 *
 * Load the context of @frame_header to parser's state. This function is
 * used when we want to show already parsed frames before.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_reference_frame_loading (GstAV1Parser * parser,
    GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ReferenceFrameInfo *ref_info;
  GstAV1TileInfo *ref_tile_info;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (frame_header != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  if (!parser->seq_header) {
    GST_WARNING ("Missing OBU Reference: seq_header");
    return GST_AV1_PARSER_MISSING_OBU_REFERENCE;
  }

  ref_info = &(parser->state.ref_info);

  if (frame_header->frame_to_show_map_idx > GST_AV1_NUM_REF_FRAMES - 1)
    return GST_AV1_PARSER_BITSTREAM_ERROR;

  g_assert (ref_info->entry[frame_header->frame_to_show_map_idx].ref_valid);

  parser->state.current_frame_id =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_frame_id;
  parser->state.upscaled_width =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_upscaled_width;
  parser->state.frame_width =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_frame_width;
  parser->state.frame_height =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_frame_height;
  parser->state.render_width =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_render_width;
  parser->state.render_height =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_render_height;
  parser->state.mi_cols =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_mi_cols;
  parser->state.mi_rows =
      ref_info->entry[frame_header->frame_to_show_map_idx].ref_mi_rows;

  ref_tile_info =
      &ref_info->entry[frame_header->frame_to_show_map_idx].ref_tile_info;

  memcpy (parser->state.mi_col_starts, ref_tile_info->mi_col_starts,
      sizeof (guint32) * (GST_AV1_MAX_TILE_COLS + 1));
  memcpy (parser->state.mi_row_starts, ref_tile_info->mi_row_starts,
      sizeof (guint32) * (GST_AV1_MAX_TILE_ROWS + 1));
  parser->state.tile_cols_log2 = ref_tile_info->tile_cols_log2;
  parser->state.tile_cols = ref_tile_info->tile_cols;
  parser->state.tile_rows_log2 = ref_tile_info->tile_rows_log2;
  parser->state.tile_rows = ref_tile_info->tile_rows;
  parser->state.tile_size_bytes = ref_tile_info->tile_size_bytes;

  return GST_AV1_PARSER_OK;
}

/**
 * gst_av1_parser_reference_frame_update:
 * @parser: the #GstAV1Parser
 * @frame_header: a #GstAV1FrameHeaderOBU to load
 *
 * Update the context of @frame_header to parser's state. This function is
 * used when we finish one frame's decoding/showing, and need to update info
 * such as reference, global parameters.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_reference_frame_update (GstAV1Parser * parser,
    GstAV1FrameHeaderOBU * frame_header)
{
  gint i;
  GstAV1SequenceHeaderOBU *seq_header;
  GstAV1ReferenceFrameInfo *ref_info;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (frame_header != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  if (!parser->seq_header) {
    GST_WARNING ("Missing OBU Reference: seq_header");
    return GST_AV1_PARSER_MISSING_OBU_REFERENCE;
  }

  seq_header = parser->seq_header;
  ref_info = &(parser->state.ref_info);
  if (frame_header->frame_type == GST_AV1_INTRA_ONLY_FRAME
      && frame_header->refresh_frame_flags == 0xff)
    return GST_AV1_PARSER_BITSTREAM_ERROR;

  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
    if ((frame_header->refresh_frame_flags >> i) & 1) {
      ref_info->entry[i].ref_valid = 1;
      ref_info->entry[i].ref_frame_id = frame_header->current_frame_id;
      ref_info->entry[i].ref_frame_type = frame_header->frame_type;
      ref_info->entry[i].ref_upscaled_width = frame_header->upscaled_width;
      ref_info->entry[i].ref_frame_width = frame_header->frame_width;
      ref_info->entry[i].ref_frame_height = frame_header->frame_height;
      ref_info->entry[i].ref_render_width = frame_header->render_width;
      ref_info->entry[i].ref_render_height = frame_header->render_height;
      ref_info->entry[i].ref_order_hint = frame_header->order_hint;
      ref_info->entry[i].ref_mi_cols = parser->state.mi_cols;
      ref_info->entry[i].ref_mi_rows = parser->state.mi_rows;
      ref_info->entry[i].ref_subsampling_x =
          seq_header->color_config.subsampling_x;
      ref_info->entry[i].ref_subsampling_y =
          seq_header->color_config.subsampling_y;
      ref_info->entry[i].ref_bit_depth = seq_header->bit_depth;
      ref_info->entry[i].ref_segmentation_params =
          frame_header->segmentation_params;
      ref_info->entry[i].ref_global_motion_params =
          frame_header->global_motion_params;
      ref_info->entry[i].ref_lf_params = frame_header->loop_filter_params;
      ref_info->entry[i].ref_tile_info = frame_header->tile_info;
      if (seq_header->film_grain_params_present)
        ref_info->entry[i].ref_film_grain_params =
            frame_header->film_grain_params;
    }
  }

  return GST_AV1_PARSER_OK;
}

/* 5.12.1 */
/**
 * gst_av1_parser_parse_tile_list_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @tile_list: a #GstAV1TileListOBU to store the parsed result.
 *
 * Parse one tile list @obu based on the @parser context, store the result
 * in the @tile_list. It is for large scale tile coding mode.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_tile_list_obu (GstAV1Parser * parser,
    GstAV1OBU * obu, GstAV1TileListOBU * tile_list)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  GstBitReader *br;
  GstBitReader bitreader;
  gint tile;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_TILE_LIST,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (tile_list != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  br = &bitreader;
  memset (tile_list, 0, sizeof (*tile_list));
  gst_bit_reader_init (br, obu->data, obu->obu_size);
  if (AV1_REMAINING_BITS (br) < 8 + 8 + 16) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  tile_list->output_frame_width_in_tiles_minus_1 = AV1_READ_BITS (br, 8);
  tile_list->output_frame_height_in_tiles_minus_1 = AV1_READ_BITS (br, 8);
  tile_list->tile_count_minus_1 = AV1_READ_BITS (br, 16);
  for (tile = 0; tile <= tile_list->tile_count_minus_1; tile++) {
    if (AV1_REMAINING_BITS (br) < 8 + 8 + 8 + 16) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
    tile_list->entry[tile].anchor_frame_idx = AV1_READ_BITS (br, 8);
    tile_list->entry[tile].anchor_tile_row = AV1_READ_BITS (br, 8);
    tile_list->entry[tile].anchor_tile_col = AV1_READ_BITS (br, 8);
    tile_list->entry[tile].tile_data_size_minus_1 = AV1_READ_BITS (br, 16);

    g_assert (gst_bit_reader_get_pos (br) % 8 == 0);

    tile_list->entry[tile].coded_tile_data =
        obu->data + gst_bit_reader_get_pos (br) / 8;
    /* skip the coded_tile_data */
    if (!gst_bit_reader_skip (br,
            tile_list->entry[tile].tile_data_size_minus_1 + 1)) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
  }

  retval = av1_skip_trailing_bits (parser, br, obu);
  if (retval != GST_AV1_PARSER_OK)
    goto error;

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse tile list error %d", retval);
  return retval;
}

/* 5.11.1 */
static GstAV1ParserResult
gst_av1_parse_tile_group (GstAV1Parser * parser, GstBitReader * br,
    GstAV1TileGroupOBU * tile_group)
{
  GstAV1ParserResult retval = GST_AV1_PARSER_OK;
  gint tile_num /* TileNum */ , end_bit_pos /* endBitPos */ ;
  gint header_bytes /* headerBytes */ , start_bitpos /* startBitPos */ ;
  guint32 sz = AV1_REMAINING_BYTES (br);
  guint32 tile_row /* tileRow */ ;
  guint32 tile_col /* tileCol */ ;
  guint32 tile_size /* tileSize */ ;

  memset (tile_group, 0, sizeof (*tile_group));
  tile_group->num_tiles = parser->state.tile_cols * parser->state.tile_rows;
  start_bitpos = gst_bit_reader_get_pos (br);
  tile_group->tile_start_and_end_present_flag = 0;

  if (tile_group->num_tiles > 1) {
    tile_group->tile_start_and_end_present_flag =
        AV1_READ_BIT_CHECKED (br, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }
  if (tile_group->num_tiles == 1
      || !tile_group->tile_start_and_end_present_flag) {
    tile_group->tg_start = 0;
    tile_group->tg_end = tile_group->num_tiles - 1;
  } else {
    gint tileBits = parser->state.tile_cols_log2 + parser->state.tile_rows_log2;
    tile_group->tg_start = AV1_READ_BITS_CHECKED (br, tileBits, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;

    tile_group->tg_end = AV1_READ_BITS_CHECKED (br, tileBits, &retval);
    if (retval != GST_AV1_PARSER_OK)
      goto error;
  }

  if (tile_group->tg_end < tile_group->tg_start) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  if (!gst_bit_reader_skip_to_byte (br)) {
    retval = GST_AV1_PARSER_NO_MORE_DATA;
    goto error;
  }

  end_bit_pos = gst_bit_reader_get_pos (br);
  header_bytes = (end_bit_pos - start_bitpos) / 8;
  sz -= header_bytes;

  for (tile_num = tile_group->tg_start; tile_num <= tile_group->tg_end;
      tile_num++) {
    tile_row = tile_num / parser->state.tile_cols;
    tile_col = tile_num % parser->state.tile_cols;
    /* if last tile */
    if (tile_num == tile_group->tg_end) {
      tile_size = sz;
    } else {
      gint tile_size_minus_1 = av1_bitstreamfn_le (br,
          parser->state.tile_size_bytes, &retval);
      if (retval != GST_AV1_PARSER_OK)
        goto error;
      tile_size = tile_size_minus_1 + 1;
      sz -= tile_size - parser->state.tile_size_bytes;
    }

    tile_group->entry[tile_num].tile_size = tile_size;
    tile_group->entry[tile_num].tile_offset = gst_bit_reader_get_pos (br) / 8;
    tile_group->entry[tile_num].tile_row = tile_row;
    tile_group->entry[tile_num].tile_col = tile_col;

    tile_group->entry[tile_num].mi_row_start =
        parser->state.mi_row_starts[tile_row];
    tile_group->entry[tile_num].mi_row_end =
        parser->state.mi_row_starts[tile_row + 1];
    tile_group->entry[tile_num].mi_col_start =
        parser->state.mi_col_starts[tile_col];
    tile_group->entry[tile_num].mi_col_end =
        parser->state.mi_col_starts[tile_col + 1];
    /* Not implement here, the real decoder process
       init_symbol( tileSize )
       decode_tile( )
       exit_symbol( )
     */

    /* Skip the real data to the next one */
    if (tile_num < tile_group->tg_end &&
        !gst_bit_reader_skip (br, tile_size * 8)) {
      retval = GST_AV1_PARSER_NO_MORE_DATA;
      goto error;
    }
  }

  if (tile_group->tg_end == tile_group->num_tiles - 1) {
    /* Not implement here, the real decoder process
       if ( !disable_frame_end_update_cdf ) {
       frame_end_update_cdf( )
       }
       decode_frame_wrapup( )
     */
    parser->state.seen_frame_header = 0;
  }

  return GST_AV1_PARSER_OK;

error:
  GST_WARNING ("parse tile group error %d", retval);
  return retval;
}

/**
 * gst_av1_parser_parse_tile_group_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @tile_group: a #GstAV1TileGroupOBU to store the parsed result.
 *
 * Parse one tile group @obu based on the @parser context, store the result
 * in the @tile_group.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_tile_group_obu (GstAV1Parser * parser, GstAV1OBU * obu,
    GstAV1TileGroupOBU * tile_group)
{
  GstAV1ParserResult ret;
  GstBitReader bit_reader;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_TILE_GROUP,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (tile_group != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  if (!parser->state.seen_frame_header) {
    GST_WARNING ("Missing OBU Reference: frame_header");
    return GST_AV1_PARSER_MISSING_OBU_REFERENCE;
  }

  gst_bit_reader_init (&bit_reader, obu->data, obu->obu_size);
  ret = gst_av1_parse_tile_group (parser, &bit_reader, tile_group);
  return ret;
}

static GstAV1ParserResult
gst_av1_parse_frame_header (GstAV1Parser * parser, GstAV1OBU * obu,
    GstBitReader * bit_reader, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult ret;
  guint i;

  memset (frame_header, 0, sizeof (*frame_header));
  frame_header->frame_is_intra = 1;
  frame_header->last_frame_idx = -1;
  frame_header->gold_frame_idx = -1;
  for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++)
    frame_header->ref_frame_idx[i] = -1;

  ret = gst_av1_parse_uncompressed_frame_header (parser, obu, bit_reader,
      frame_header);
  if (ret != GST_AV1_PARSER_OK)
    return ret;

  if (frame_header->show_existing_frame) {
    parser->state.seen_frame_header = 0;
  } else {
    parser->state.seen_frame_header = 1;
  }

  return GST_AV1_PARSER_OK;
}

/**
 * gst_av1_parser_parse_frame_header_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @frame_header: a #GstAV1FrameHeaderOBU to store the parsed result.
 *
 * Parse one frame header @obu based on the @parser context, store the result
 * in the @frame.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_frame_header_obu (GstAV1Parser * parser,
    GstAV1OBU * obu, GstAV1FrameHeaderOBU * frame_header)
{
  GstAV1ParserResult ret;
  GstBitReader bit_reader;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_FRAME_HEADER ||
      obu->obu_type == GST_AV1_OBU_REDUNDANT_FRAME_HEADER,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (frame_header != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  if (obu->obu_type == GST_AV1_OBU_REDUNDANT_FRAME_HEADER
      && !parser->state.seen_frame_header) {
    GST_WARNING ("no seen of frame header while get redundant frame header");
    return GST_AV1_PARSER_BITSTREAM_ERROR;
  }

  if (obu->obu_type == GST_AV1_OBU_FRAME_HEADER
      && parser->state.seen_frame_header) {
    GST_WARNING ("already seen a frame header");
    return GST_AV1_PARSER_BITSTREAM_ERROR;
  }

  gst_bit_reader_init (&bit_reader, obu->data, obu->obu_size);
  ret = gst_av1_parse_frame_header (parser, obu, &bit_reader, frame_header);
  if (ret != GST_AV1_PARSER_OK)
    return ret;

  ret = av1_skip_trailing_bits (parser, &bit_reader, obu);
  return ret;
}

/**
 * gst_av1_parser_parse_frame_obu:
 * @parser: the #GstAV1Parser
 * @obu: a #GstAV1OBU to be parsed
 * @frame: a #GstAV1FrameOBU to store the parsed result.
 *
 * Parse one frame @obu based on the @parser context, store the result
 * in the @frame.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.18
 */
GstAV1ParserResult
gst_av1_parser_parse_frame_obu (GstAV1Parser * parser, GstAV1OBU * obu,
    GstAV1FrameOBU * frame)
{
  GstAV1ParserResult retval;
  GstBitReader bit_reader;

  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (obu->obu_type == GST_AV1_OBU_FRAME,
      GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (frame != NULL, GST_AV1_PARSER_INVALID_OPERATION);

  if (parser->state.seen_frame_header) {
    GST_WARNING ("already seen a frame header");
    return GST_AV1_PARSER_BITSTREAM_ERROR;
  }

  gst_bit_reader_init (&bit_reader, obu->data, obu->obu_size);
  retval = gst_av1_parse_frame_header (parser, obu, &bit_reader,
      &(frame->frame_header));
  if (retval != GST_AV1_PARSER_OK)
    return retval;

  if (!gst_bit_reader_skip_to_byte (&bit_reader))
    return GST_AV1_PARSER_NO_MORE_DATA;

  retval = gst_av1_parse_tile_group (parser, &bit_reader, &(frame->tile_group));
  return retval;
}

/**
 * gst_av1_parser_set_operating_point:
 * @parser: the #GstAV1Parser
 * @operating_point: the operating point to set
 *
 * Set the operating point to filter OBUs.
 *
 * Returns: The #GstAV1ParserResult.
 *
 * Since: 1.20
 */
GstAV1ParserResult
gst_av1_parser_set_operating_point (GstAV1Parser * parser,
    gint32 operating_point)
{
  g_return_val_if_fail (parser != NULL, GST_AV1_PARSER_INVALID_OPERATION);
  g_return_val_if_fail (operating_point >= 0, GST_AV1_PARSER_INVALID_OPERATION);

  if (parser->seq_header &&
      operating_point > parser->seq_header->operating_points_cnt_minus_1)
    return GST_AV1_PARSER_INVALID_OPERATION;

  /* Decide whether it is valid when sequence comes. */
  parser->state.operating_point = operating_point;
  return GST_AV1_PARSER_OK;
}

/**
 * gst_av1_parser_new:
 *
 * Allocates a new #GstAV1Parser,
 *
 * Returns: (transfer full): a newly-allocated  #GstAV1Parser
 *
 * Since: 1.18
 */
GstAV1Parser *
gst_av1_parser_new (void)
{
  return g_slice_new0 (GstAV1Parser);
}

/**
 * gst_av1_parser_free:
 * @parser: the #GstAV1Parser to free
 *
 * If parser is not %NULL, frees its allocated memory.
 *
 * It cannot be used afterwards.
 *
 * Since: 1.18
 */
void
gst_av1_parser_free (GstAV1Parser * parser)
{
  g_return_if_fail (parser != NULL);

  if (parser->seq_header)
    g_slice_free (GstAV1SequenceHeaderOBU, parser->seq_header);
  g_slice_free (GstAV1Parser, parser);
}
