diff --git a/gst-libs/gst/codecparsers/gstav1parser.c b/gst-libs/gst/codecparsers/gstav1parser.c new file mode 100644 index 0000000000..6f6b74125c --- /dev/null +++ b/gst-libs/gst/codecparsers/gstav1parser.c @@ -0,0 +1,4502 @@ +/* gstav1parser.c + * + * Copyright (C) 2018 Georg Ottinger + * Copyright (C) 2019-2020 Intel Corporation + * Author: Georg Ottinger + * Author: Junyan He + * Author: Victor Jaquez + * + * 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 + +#include +#include + +#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); +} + +/************************************* + * * + * 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 guint8 +av1_bitstreamfn_ns (GstBitReader * br, guint8 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.seen_frame_header = 0; + 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); + + if (parser->annex_b) { + g_assert (parser->temporal_unit_consumed <= parser->temporal_unit_size); + 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); + + g_assert (parser->frame_unit_consumed <= parser->frame_unit_size); + 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; + parser->annex_b = annex_b; + + gst_av1_parse_reset_state (parser, TRUE); +} + +/* 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; + + g_assert (*consumed <= size); + if (*consumed == size) { + ret = GST_AV1_PARSER_NO_MORE_DATA; + goto error; + } + gst_bit_reader_init (&br, data + *consumed, size - *consumed); + + g_assert (parser->temporal_unit_consumed <= parser->temporal_unit_size); + 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; + } + } + + g_assert (parser->frame_unit_consumed <= parser->frame_unit_size); + 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; + } + } + + g_assert (*consumed <= size); + 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) { + obu->obu_size = av1_bitstreamfn_leb128 (&br, &ret); + if (ret != GST_AV1_PARSER_OK) + goto error; + + if (obu_length + && obu_length - 1 - obu->header.obu_extention_flag != 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_4_0) { + 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, move it later + 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_INFO ("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) { + 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_BIT_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); + 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, 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 */ ; + gint min_inner_tile_width = G_MAXINT /* min width of non-rightmost tile */ ; + + 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; + if (parser->state.tile_cols > 1) + min_inner_tile_width = tile_width_sb << sb_size; + + 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; + } 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; + if (i > 0 && ((size_sb << sb_size) < min_inner_tile_width)) + min_inner_tile_width = size_sb << sb_size; + } + 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_BIT_CHECKED (br, &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; + } + + if (min_inner_tile_width < (64 << (parser->state.upscaled_width != + parser->state.frame_width))) { + GST_INFO ("Minimum tile width requirement not satisfied"); + retval = GST_AV1_PARSER_BITSTREAM_ERROR; + goto error; + } + + 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_delta_enabled = 0; + lf_params->loop_filter_delta_update = 0; + lf_params->loop_filter_sharpness = 0; + lf_params->loop_filter_level[0] = 0; + lf_params->loop_filter_level[1] = 0; + lf_params->loop_filter_level[2] = 0; + lf_params->loop_filter_level[3] = 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; + } + + lf_params->loop_filter_delta_enabled = 0; + lf_params->loop_filter_delta_update = 0; + lf_params->loop_filter_sharpness = 0; + lf_params->loop_filter_level[0] = 0; + lf_params->loop_filter_level[1] = 0; + lf_params->loop_filter_level[2] = 0; + lf_params->loop_filter_level[3] = 0; + if (frame_header->primary_ref_frame != GST_AV1_PRIMARY_REF_NONE) { + /* Copy it from prime_ref */ + GstAV1LoopFilterParams *ref_lf_params = + &parser->state.ref_info.entry[frame_header-> + ref_frame_idx[frame_header->primary_ref_frame]].ref_lf_params; + + g_assert (parser->state.ref_info. + entry[frame_header->ref_frame_idx[frame_header->primary_ref_frame]]. + ref_valid); + lf_params->loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_INTRA_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST2_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME] = + ref_lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME]; + lf_params->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++) + lf_params->loop_filter_mode_deltas[i] = + ref_lf_params->loop_filter_mode_deltas[i]; + } else { + /* Set default value */ + 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] = + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST3_FRAME] = + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_BWDREF_FRAME] = + lf_params->loop_filter_ref_deltas[GST_AV1_REF_LAST_FRAME]; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_GOLDEN_FRAME] = -1; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF2_FRAME] = -1; + lf_params->loop_filter_ref_deltas[GST_AV1_REF_ALTREF_FRAME] = -1; + for (i = 0; i < 2; i++) + lf_params->loop_filter_mode_deltas[i] = 0; + } + + 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; + } else + lf_params->loop_filter_ref_deltas[i] = 0; + } + 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; + } else + lf_params->loop_filter_mode_deltas[i] = 0; + } + } + } + +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) { + lr_params->frame_restoration_type[0] = GST_AV1_FRAME_RESTORE_NONE; + lr_params->frame_restoration_type[0] = GST_AV1_FRAME_RESTORE_NONE; + lr_params->frame_restoration_type[0] = 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; +} + +/* 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->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; + } + } + +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; + } + + /* @TODO: + if ( primary_ref_frame == PRIMARY_REF_NONE ) { + init_non_coeff_cdfs( ) + setup_past_independence( ) + } else { + load_cdfs( ref_frame_idx[primary_ref_frame] ) + load_previous( ) + } + */ + /* @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 (!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].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 (!gst_bit_reader_skip (br, tile_size)) { + retval = GST_AV1_PARSER_NO_MORE_DATA; + goto error; + } + } + + /* Not implement here, the real decoder process + if (tile_group->tg_end == tile_group->num_tiles - 1) { + if ( !disable_frame_end_update_cdf ) { + frame_end_update_cdf( ) + } + decode_frame_wrapup( ) + } + */ + + 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; + + memset (frame_header, 0, sizeof (*frame_header)); + frame_header->frame_is_intra = 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)); + parser->state.seen_frame_header = 0; + return retval; +} + +/** + * 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); +} diff --git a/gst-libs/gst/codecparsers/gstav1parser.h b/gst-libs/gst/codecparsers/gstav1parser.h new file mode 100644 index 0000000000..bdbe3e11a3 --- /dev/null +++ b/gst-libs/gst/codecparsers/gstav1parser.h @@ -0,0 +1,1806 @@ +/* + * gstav1parser.h + * + * Copyright (C) 2018 Georg Ottinger + * Copyright (C) 2019-2020 Intel Corporation + * Author: Georg Ottinger + * Author: Junyan He + * Author: Victor Jaquez + * + * 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. + */ + +#ifndef __GST_AV1_PARSER_H__ +#define __GST_AV1_PARSER_H__ + +#ifndef GST_USE_UNSTABLE_API +#warning "The AV1 parsing library is unstable API and may change in future." +#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GST_AV1_MAX_NUM_TEMPORAL_LAYERS 8 +#define GST_AV1_MAX_NUM_SPATIAL_LAYERS 4 +#define GST_AV1_MAX_TILE_WIDTH 4096 +#define GST_AV1_MAX_TILE_AREA (4096 * 2304) +#define GST_AV1_TOTAL_REFS_PER_FRAME 8 +#define GST_AV1_MAX_SEGMENTS 8 +#define GST_AV1_SEG_LVL_MAX 8 +#define GST_AV1_MAX_TILE_COLS 64 +#define GST_AV1_MAX_TILE_ROWS 64 + +#define GST_AV1_REFS_PER_FRAME 7 +#define GST_AV1_PRIMARY_REF_NONE 7 +#define GST_AV1_SUPERRES_NUM 8 +#define GST_AV1_SUPERRES_DENOM_MIN 9 +#define GST_AV1_SUPERRES_DENOM_BITS 3 +#define GST_AV1_MAX_LOOP_FILTER 63 +#define GST_AV1_GM_ABS_ALPHA_BITS 12 +#define GST_AV1_GM_ABS_TRANS_BITS 12 +#define GST_AV1_GM_ABS_TRANS_ONLY_BITS 9 +#define GST_AV1_GM_ABS_ALPHA_BITS 12 +#define GST_AV1_GM_ALPHA_PREC_BITS 15 +#define GST_AV1_GM_TRANS_PREC_BITS 6 +#define GST_AV1_GM_TRANS_ONLY_PREC_BITS 3 +#define GST_AV1_WARPEDMODEL_PREC_BITS 16 +#define GST_AV1_SELECT_SCREEN_CONTENT_TOOLS 2 +#define GST_AV1_SELECT_INTEGER_MV 2 +#define GST_AV1_RESTORATION_TILESIZE_MAX 256 +#define GST_AV1_SEG_LVL_ALT_Q 0 +#define GST_AV1_SEG_LVL_REF_FRAME 5 +/* Following defines are derived from the spec, but not mentioned by + * this particular name in the spec */ +#define GST_AV1_CDEF_MAX (1 << 3) +#define GST_AV1_MAX_TILE_COUNT 512 +#define GST_AV1_MAX_OPERATING_POINTS \ + (GST_AV1_MAX_NUM_TEMPORAL_LAYERS * GST_AV1_MAX_NUM_SPATIAL_LAYERS) +#define GST_AV1_MAX_SPATIAL_LAYERS 2 /* correct? */ +#define GST_AV1_MAX_TEMPORAL_GROUP_SIZE 8 /* correct? */ +#define GST_AV1_MAX_TEMPORAL_GROUP_REFERENCES 8 /* correct? */ +#define GST_AV1_MAX_NUM_Y_POINTS 16 +#define GST_AV1_MAX_NUM_CB_POINTS 16 +#define GST_AV1_MAX_NUM_CR_POINTS 16 +#define GST_AV1_MAX_NUM_POS_LUMA 25 +#define GST_AV1_MAX_NUM_PLANES 3 + +typedef struct _GstAV1Parser GstAV1Parser; + +typedef struct _GstAV1OBUHeader GstAV1OBUHeader; +typedef struct _GstAV1OBU GstAV1OBU; + +typedef struct _GstAV1SequenceHeaderOBU GstAV1SequenceHeaderOBU; +typedef struct _GstAV1MetadataOBU GstAV1MetadataOBU; +typedef struct _GstAV1FrameHeaderOBU GstAV1FrameHeaderOBU; +typedef struct _GstAV1TileListOBU GstAV1TileListOBU; +typedef struct _GstAV1TileGroupOBU GstAV1TileGroupOBU; +typedef struct _GstAV1FrameOBU GstAV1FrameOBU; + +typedef struct _GstAV1OperatingPoint GstAV1OperatingPoint; +typedef struct _GstAV1DecoderModelInfo GstAV1DecoderModelInfo; +typedef struct _GstAV1TimingInfo GstAV1TimingInfo; +typedef struct _GstAV1ColorConfig GstAV1ColorConfig; +typedef struct _GstAV1MetadataITUT_T35 GstAV1MetadataITUT_T35; +typedef struct _GstAV1MetadataHdrCll GstAV1MetadataHdrCll; +typedef struct _GstAV1MetadataHdrMdcv GstAV1MetadataHdrMdcv; +typedef struct _GstAV1MetadataScalability GstAV1MetadataScalability; +typedef struct _GstAV1MetadataTimecode GstAV1MetadataTimecode; +typedef struct _GstAV1LoopFilterParams GstAV1LoopFilterParams; +typedef struct _GstAV1QuantizationParams GstAV1QuantizationParams; +typedef struct _GstAV1SegmenationParams GstAV1SegmenationParams; +typedef struct _GstAV1TileInfo GstAV1TileInfo; +typedef struct _GstAV1CDEFParams GstAV1CDEFParams; +typedef struct _GstAV1LoopRestorationParams GstAV1LoopRestorationParams; +typedef struct _GstAV1GlobalMotionParams GstAV1GlobalMotionParams; +typedef struct _GstAV1FilmGrainParams GstAV1FilmGrainParams; + +typedef struct _GstAV1ReferenceFrameInfo GstAV1ReferenceFrameInfo; + +/** + * GstAV1ParserResult: + * @GST_AV1_PARSER_OK: successful return + * @GST_AV1_PARSER_NO_MORE_DATA: the parser needs more data for one OBU + * @GST_AV1_PARSER_DROP: no need to handle this OBU, skip it + * @GST_AV1_PARSER_BITSTREAM_ERROR: stream error, for example, include invalid bits + * @GST_AV1_PARSER_MISSING_OBU_REFERENCE: no reference, for example, no sequence found + * @GST_AV1_PARSER_INVALID_OPERATION: something like invalid parameters + * + * Defines the result of parser process + */ +typedef enum { + GST_AV1_PARSER_OK = 0, + GST_AV1_PARSER_NO_MORE_DATA = 1, + GST_AV1_PARSER_DROP = 2, + GST_AV1_PARSER_BITSTREAM_ERROR = 3, + GST_AV1_PARSER_MISSING_OBU_REFERENCE = 4, + GST_AV1_PARSER_INVALID_OPERATION = 5, +} GstAV1ParserResult; + +/** + * GstAV1Profile: + * @GST_AV1_PROFILE_0: 8-bit and 10-bit 4:2:0 and 4:0:0 only. + * @GST_AV1_PROFILE_1: 8-bit and 10-bit 4:4:4. + * @GST_AV1_PROFILE_2: 8-bit and 10-bit 4:2:2, 12-bit 4:0:0 4:2:2 and 4:4:4 + * + * Defines the AV1 profiles + */ +typedef enum { + GST_AV1_PROFILE_0 = 0, + GST_AV1_PROFILE_1 = 1, + GST_AV1_PROFILE_2 = 2, +} GstAV1Profile; + +/** + * GstAV1OBUType: + * @GST_AV1_OBU_RESERVED_0: Reserved 0 + * @GST_AV1_OBU_SEQUENCE_HEADER: Sequence Header OBU + * @GST_AV1_OBU_TEMPORAL_DELIMITER: Temporal Delimiter OBU + * @GST_AV1_OBU_FRAME_HEADER: Frame Header OBU + * @GST_AV1_OBU_TILE_GROUP: Tile Group OBU + * @GST_AV1_OBU_METADATA: Metadata OBU + * @GST_AV1_OBU_FRAME: Frame OBU (includes Frame Header and one Tile Group) + * @GST_AV1_OBU_REDUNDANT_FRAME_HEADER: Redundant Frame Header OBU + * @GST_AV1_OBU_TILE_LIST: Tile LIst OBU + * @GST_AV1_OBU_RESERVED_9: Reserved 9 + * @GST_AV1_OBU_RESERVED_10: Reserved 10 + * @GST_AV1_OBU_RESERVED_11: Reserved 11 + * @GST_AV1_OBU_RESERVED_12: Reserved 12 + * @GST_AV1_OBU_RESERVED_13: Reserved 13 + * @GST_AV1_OBU_RESERVED_14: Reserved 14 + * @GST_AV1_OBU_PADDING: Padding + * + * Defines all the possible OBU types + */ +typedef enum { + GST_AV1_OBU_RESERVED_0 = 0, + GST_AV1_OBU_SEQUENCE_HEADER = 1, + GST_AV1_OBU_TEMPORAL_DELIMITER = 2, + GST_AV1_OBU_FRAME_HEADER = 3, + GST_AV1_OBU_TILE_GROUP = 4, + GST_AV1_OBU_METADATA = 5, + GST_AV1_OBU_FRAME = 6, + GST_AV1_OBU_REDUNDANT_FRAME_HEADER = 7, + GST_AV1_OBU_TILE_LIST = 8, + GST_AV1_OBU_RESERVED_9 = 9, + GST_AV1_OBU_RESERVED_10 = 10, + GST_AV1_OBU_RESERVED_11 = 11, + GST_AV1_OBU_RESERVED_12 = 12, + GST_AV1_OBU_RESERVED_13 = 13, + GST_AV1_OBU_RESERVED_14 = 14, + GST_AV1_OBU_PADDING = 15, +} GstAV1OBUType; + +/** + * GstAV1SeqLevels: + * @GST_AV1_SEQ_LEVEL_2_0: Level 2.0 + * @GST_AV1_SEQ_LEVEL_2_1: Level 2.1 + * @GST_AV1_SEQ_LEVEL_2_2: Level 2.2 + * @GST_AV1_SEQ_LEVEL_2_3: Level 2.3 + * @GST_AV1_SEQ_LEVEL_3_0: Level 3.0 + * @GST_AV1_SEQ_LEVEL_3_1: Level 3.1 + * @GST_AV1_SEQ_LEVEL_3_2: Level 3.2 + * @GST_AV1_SEQ_LEVEL_3_3: Level 3.3 + * @GST_AV1_SEQ_LEVEL_4_0: Level 4.0 + * @GST_AV1_SEQ_LEVEL_4_1: Level 4.1 + * @GST_AV1_SEQ_LEVEL_4_2: Level 4.2 + * @GST_AV1_SEQ_LEVEL_4_3: Level 4.3 + * @GST_AV1_SEQ_LEVEL_5_0: Level 5.0 + * @GST_AV1_SEQ_LEVEL_5_1: Level 5.1 + * @GST_AV1_SEQ_LEVEL_5_2: Level 5.2 + * @GST_AV1_SEQ_LEVEL_5_3: Level 5.3 + * @GST_AV1_SEQ_LEVEL_6_0: Level 6.0 + * @GST_AV1_SEQ_LEVEL_6_1: Level 6.1 + * @GST_AV1_SEQ_LEVEL_6_2: Level 6.2 + * @GST_AV1_SEQ_LEVEL_6_3: Level 6.3 + * @GST_AV1_SEQ_LEVEL_7_0: Level 7.0 + * @GST_AV1_SEQ_LEVEL_7_1: Level 7.1 + * @GST_AV1_SEQ_LEVEL_7_2: Level 7.2 + * @GST_AV1_SEQ_LEVEL_7_3: Level 7.3 + * @GST_AV1_SEQ_LEVELS: all valid levels + * @GST_AV1_SEQ_LEVEL_MAX: Maximum parameters + * + * Defines all the possible OBU types + */ +typedef enum { + GST_AV1_SEQ_LEVEL_2_0 = 0, + GST_AV1_SEQ_LEVEL_2_1 = 1, + GST_AV1_SEQ_LEVEL_2_2 = 2, + GST_AV1_SEQ_LEVEL_2_3 = 3, + GST_AV1_SEQ_LEVEL_3_0 = 4, + GST_AV1_SEQ_LEVEL_3_1 = 5, + GST_AV1_SEQ_LEVEL_3_2 = 6, + GST_AV1_SEQ_LEVEL_3_3 = 7, + GST_AV1_SEQ_LEVEL_4_0 = 8, + GST_AV1_SEQ_LEVEL_4_1 = 9, + GST_AV1_SEQ_LEVEL_4_2 = 10, + GST_AV1_SEQ_LEVEL_4_3 = 11, + GST_AV1_SEQ_LEVEL_5_0 = 12, + GST_AV1_SEQ_LEVEL_5_1 = 13, + GST_AV1_SEQ_LEVEL_5_2 = 14, + GST_AV1_SEQ_LEVEL_5_3 = 15, + GST_AV1_SEQ_LEVEL_6_0 = 16, + GST_AV1_SEQ_LEVEL_6_1 = 17, + GST_AV1_SEQ_LEVEL_6_2 = 18, + GST_AV1_SEQ_LEVEL_6_3 = 19, + GST_AV1_SEQ_LEVEL_7_0 = 20, + GST_AV1_SEQ_LEVEL_7_1 = 21, + GST_AV1_SEQ_LEVEL_7_2 = 22, + GST_AV1_SEQ_LEVEL_7_3 = 23, + GST_AV1_SEQ_LEVELS, + GST_AV1_SEQ_LEVEL_MAX = 31 +} GstAV1SeqLevels; + +/** + * GstAV1MetadataType: + * @GST_AV1_METADATA_TYPE_RESERVED_0: Reserved 0 + * @GST_AV1_METADATA_TYPE_HDR_CLL: Metadata high dynamic range content + * light level semantics + * @GST_AV1_METADATA_TYPE_HDR_MDCV: Metadata high dynamic range mastering + * display color volume semantics + * @GST_AV1_METADATA_TYPE_SCALABILITY: Metadata scalability semantics + * @GST_AV1_METADATA_TYPE_ITUT_T35: Metadata ITUT T35 semantics + * @GST_AV1_METADATA_TYPE_TIMECODE: Timecode semantics + */ +typedef enum { + GST_AV1_METADATA_TYPE_RESERVED_0 = 0, + GST_AV1_METADATA_TYPE_HDR_CLL = 1, + GST_AV1_METADATA_TYPE_HDR_MDCV = 2, + GST_AV1_METADATA_TYPE_SCALABILITY = 3, + GST_AV1_METADATA_TYPE_ITUT_T35 = 4, + GST_AV1_METADATA_TYPE_TIMECODE = 5, +} GstAV1MetadataType; + +/** + * GstAV1ScalabilityModes: + * @GST_AV1_SCALABILITY_L1T2: 1 spatial layer, 2 temporal layers + * @GST_AV1_SCALABILITY_L1T3: 1 spatial layer, 3 temporal layers + * @GST_AV1_SCALABILITY_L2T1: 2 spatial layer (ratio 2:1), 1 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_L2T2: 2 spatial layer (ratio 2:1), 2 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_L2T3: 2 spatial layer (ratio 2:1), 3 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_S2T1: 2 spatial layer (ratio 2:1), 1 temporal layer + * @GST_AV1_SCALABILITY_S2T2: 2 spatial layer (ratio 2:1), 2 temporal layer + * @GST_AV1_SCALABILITY_S2T3: 2 spatial layer (ratio 2:1), 3 temporal layer + * @GST_AV1_SCALABILITY_L2T1h: 2 spatial layer (ratio 1.5:1), 1 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_L2T2h: 2 spatial layer (ratio 1.5:1), 2 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_L2T3h: 2 spatial layer (ratio 1.5:1), 3 temporal layer, + * inter-layer dependency + * @GST_AV1_SCALABILITY_S2T1h: 2 spatial layer (ratio 1.5:1), 1 temporal layer + * @GST_AV1_SCALABILITY_S2T2h: 2 spatial layer (ratio 1.5:1), 2 temporal layer + * @GST_AV1_SCALABILITY_S2T3h: 2 spatial layer (ratio 1.5:1), 3 temporal layer + * @GST_AV1_SCALABILITY_SS: Use scalability structure #GstAV1MetadataScalability + */ +typedef enum { + GST_AV1_SCALABILITY_L1T2 = 0, + GST_AV1_SCALABILITY_L1T3 = 1, + GST_AV1_SCALABILITY_L2T1 = 2, + GST_AV1_SCALABILITY_L2T2 = 3, + GST_AV1_SCALABILITY_L2T3 = 4, + GST_AV1_SCALABILITY_S2T1 = 5, + GST_AV1_SCALABILITY_S2T2 = 6, + GST_AV1_SCALABILITY_S2T3 = 7, + GST_AV1_SCALABILITY_L2T1h = 8, + GST_AV1_SCALABILITY_L2T2h = 9, + GST_AV1_SCALABILITY_L2T3h = 10, + GST_AV1_SCALABILITY_S2T1h = 11, + GST_AV1_SCALABILITY_S2T2h = 12, + GST_AV1_SCALABILITY_S2T3h = 13, + GST_AV1_SCALABILITY_SS = 14, +} GstAV1ScalabilityModes; + +/** + * GstAV1ColorPrimaries: + * @GST_AV1_CP_BT_709: BT.709 + * @GST_AV1_CP_UNSPECIFIED: Unspecified + * @GST_AV1_CP_BT_470_M: BT.470 System M (historical) + * @GST_AV1_CP_BT_470_B_G:BT.470 System B, G (historical), + * @GST_AV1_CP_BT_601: BT.601 + * @GST_AV1_CP_SMPTE_240: SMPTE 240 + * @GST_AV1_CP_GENERIC_FILM: Generic film (color filters using illuminant C, + * @GST_AV1_CP_BT_2020: BT.2020, BT.2100, + * @GST_AV1_CP_XYZ: SMPTE 428 (CIE 1921 XYZ), + * @GST_AV1_CP_SMPTE_431: SMPTE RP 431-2 + * @GST_AV1_CP_SMPTE_432: SMPTE EG 432-1 + * @GST_AV1_CP_EBU_3213: EBU Tech. 3213-E + */ +typedef enum { + GST_AV1_CP_BT_709 = 1, + GST_AV1_CP_UNSPECIFIED = 2, + GST_AV1_CP_BT_470_M = 4, + GST_AV1_CP_BT_470_B_G = 5, + GST_AV1_CP_BT_601 = 6, + GST_AV1_CP_SMPTE_240 = 7, + GST_AV1_CP_GENERIC_FILM = 8, + GST_AV1_CP_BT_2020 = 9, + GST_AV1_CP_XYZ = 10, + GST_AV1_CP_SMPTE_431 = 11, + GST_AV1_CP_SMPTE_432 = 12, + GST_AV1_CP_EBU_3213 = 22, +} GstAV1ColorPrimaries; + +/** + * GstAV1TransferCharacteristics: + * @GST_AV1_TC_RESERVED_0: For future use + * @GST_AV1_TC_BT_709: BT.709 + * @GST_AV1_TC_UNSPECIFIED: Unspecified + * @GST_AV1_TC_RESERVED_3: For future use + * @GST_AV1_TC_BT_470_M: BT.470 System M (historical) + * @GST_AV1_TC_BT_470_B_G: BT.470 System B, G (historical) + * @GST_AV1_TC_BT_601: BT.601 + * @GST_AV1_TC_SMPTE_240: SMPTE 240 M + * @GST_AV1_TC_LINEAR: Linear + * @GST_AV1_TC_LOG_100: Logarithmic (100 : 1 range) + * @GST_AV1_TC_LOG_100_SQRT10: Logarithmic (100 * Sqrt(10) : 1 range) + * @GST_AV1_TC_IEC_61966: IEC 61966-2-4 + * @GST_AV1_TC_BT_1361: BT.1361 + * @GST_AV1_TC_SRGB: sRGB or sYCC + * @GST_AV1_TC_BT_2020_10_BIT: BT.2020 10-bit systems + * @GST_AV1_TC_BT_2020_12_BIT: BT.2020 12-bit systems + * @GST_AV1_TC_SMPTE_2084: SMPTE ST 2084, ITU BT.2100 PQ + * @GST_AV1_TC_SMPTE_428: SMPTE ST 428 + * @GST_AV1_TC_HLG: BT.2100 HLG, ARIB STD-B67 + */ +typedef enum { + GST_AV1_TC_RESERVED_0 = 0, + GST_AV1_TC_BT_709 = 1, + GST_AV1_TC_UNSPECIFIED = 2, + GST_AV1_TC_RESERVED_3 = 3, + GST_AV1_TC_BT_470_M = 4, + GST_AV1_TC_BT_470_B_G = 5, + GST_AV1_TC_BT_601 = 6, + GST_AV1_TC_SMPTE_240 = 7, + GST_AV1_TC_LINEAR = 8, + GST_AV1_TC_LOG_100 = 9, + GST_AV1_TC_LOG_100_SQRT10 = 10, + GST_AV1_TC_IEC_61966 = 11, + GST_AV1_TC_BT_1361 = 12, + GST_AV1_TC_SRGB = 13, + GST_AV1_TC_BT_2020_10_BIT = 14, + GST_AV1_TC_BT_2020_12_BIT = 15, + GST_AV1_TC_SMPTE_2084 = 16, + GST_AV1_TC_SMPTE_428 = 17, + GST_AV1_TC_HLG = 18, +} GstAV1TransferCharacteristics; + +/** + * GstAV1MatrixCoefficients: + * @GST_AV1_MC_IDENTITY: Identity matrix + * @GST_AV1_MC_BT_709: BT.709 + * @GST_AV1_MC_UNSPECIFIED: Unspecified + * @GST_AV1_MC_RESERVED_3: For future use + * @GST_AV1_MC_FCC: US FCC 73.628 + * @GST_AV1_MC_BT_470_B_G: BT.470 System B, G (historical) + * @GST_AV1_MC_BT_601: BT.601 + * @GST_AV1_MC_SMPTE_240: SMPTE 240 M + * @GST_AV1_MC_SMPTE_YCGCO: YCgCo + * @GST_AV1_MC_BT_2020_NCL: BT.2020 non-constant luminance, BT.2100 YCbCr + * @GST_AV1_MC_BT_2020_CL: BT.2020 constant luminance + * @GST_AV1_MC_SMPTE_2085: SMPTE ST 2085 YDzDx + * @GST_AV1_MC_CHROMAT_NCL: Chromaticity-derived non-constant luminance + * @GST_AV1_MC_CHROMAT_CL: Chromaticity-derived constant luminancw + * @GST_AV1_MC_ICTCP: BT.2100 ICtCp + */ +typedef enum { + GST_AV1_MC_IDENTITY = 0, + GST_AV1_MC_BT_709 = 1, + GST_AV1_MC_UNSPECIFIED = 2, + GST_AV1_MC_RESERVED_3 = 3, + GST_AV1_MC_FCC = 4, + GST_AV1_MC_BT_470_B_G = 5, + GST_AV1_MC_BT_601 = 6, + GST_AV1_MC_SMPTE_240 = 7, + GST_AV1_MC_SMPTE_YCGCO = 8, + GST_AV1_MC_BT_2020_NCL = 9, + GST_AV1_MC_BT_2020_CL = 10, + GST_AV1_MC_SMPTE_2085 = 11, + GST_AV1_MC_CHROMAT_NCL = 12, + GST_AV1_MC_CHROMAT_CL = 13, + GST_AV1_MC_ICTCP = 14, +} GstAV1MatrixCoefficients; + +/** + * GstAV1ChromaSamplePositions: + * @GST_AV1_CSP_UNKNOWN: Unknown (in this case the source video transfer + * function must be signaled outside the AV1 bitstream). + * @GST_AV1_CSP_VERTICAL: Horizontally co-located with (0, 0) luma sample, + * vertical position in the middle between two luma samples. + * @GST_AV1_CSP_COLOCATED: co-located with (0, 0) luma sample. + * @GST_AV1_CSP_RESERVED: For future use. + */ +typedef enum { + GST_AV1_CSP_UNKNOWN = 0, + GST_AV1_CSP_VERTICAL = 1, + GST_AV1_CSP_COLOCATED = 2, + GST_AV1_CSP_RESERVED = 3, +} GstAV1ChromaSamplePositions; + +/** + * GstAV1FrameType: + * @GST_AV1_KEY_FRAME: Key Frame + * @GST_AV1_INTER_FRAME: InterFrame + * @GST_AV1_INTRA_ONLY_FRAME: Intra-Only Frame + * @GST_AV1_SWITCH_FRAME: Switch Frame + */ +typedef enum { + GST_AV1_KEY_FRAME = 0, + GST_AV1_INTER_FRAME = 1, + GST_AV1_INTRA_ONLY_FRAME = 2, + GST_AV1_SWITCH_FRAME = 3, +} GstAV1FrameType; + +/** + * GstAV1InterpolationFilter: + * @GST_AV1_INTERPOLATION_FILTER_EIGHTTAP: Eighttap + * @GST_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH: Eighttap Smooth + * @GST_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP: Eighttap Sharp + * @GST_AV1_INTERPOLATION_FILTER_BILINEAR: Bilinear + * @GST_AV1_INTERPOLATION_FILTER_SWITCHABLE: Filter is swichtable + */ +typedef enum { + GST_AV1_INTERPOLATION_FILTER_EIGHTTAP = 0, + GST_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH = 1, + GST_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP = 2, + GST_AV1_INTERPOLATION_FILTER_BILINEAR = 3, + GST_AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, +} GstAV1InterpolationFilter; + +/** + * GstAV1TXModes: + * @GST_AV1_TX_MODE_ONLY_4x4: the inverse transform will use only 4x4 transforms. + * @GST_AV1_TX_MODE_LARGEST: the inverse transform will use the largest transform + * size that fits inside the block. + * @GST_AV1_TX_MODE_SELECT: the choice of transform size is specified explicitly + * for each block. + */ +typedef enum { + GST_AV1_TX_MODE_ONLY_4x4 = 0, + GST_AV1_TX_MODE_LARGEST = 1, + GST_AV1_TX_MODE_SELECT = 2, +} GstAV1TXModes; + +/** + * GstAV1FrameRestorationType: + * @GST_AV1_FRAME_RESTORE_NONE: no filtering is applied + * @GST_AV1_FRAME_RESTORE_WIENER: Wiener filter process is invoked + * @GST_AV1_FRAME_RESTORE_SGRPROJ: self guided filter proces is invoked + * @GST_AV1_FRAME_RESTORE_SWITCHABLE: restoration filter is swichtable + */ +typedef enum { + GST_AV1_FRAME_RESTORE_NONE = 0, + GST_AV1_FRAME_RESTORE_WIENER = 1, + GST_AV1_FRAME_RESTORE_SGRPROJ = 2, + GST_AV1_FRAME_RESTORE_SWITCHABLE = 3, +} GstAV1FrameRestorationType; + +/** + * GstAV1ReferenceFrame: + * @GST_AV1_REF_INTRA_FRAME: Intra Frame Reference + * @GST_AV1_REF_LAST_FRAME: Last Reference Frame + * @GST_AV1_REF_LAST2_FRAME: Last2 Reference Frame + * @GST_AV1_REF_LAST3_FRAME: Last3 Reference Frame + * @GST_AV1_REF_GOLDEN_FRAME: Golden Reference Frame + * @GST_AV1_REF_BWDREF_FRAME: BWD Reference Frame + * @GST_AV1_REF_ALTREF2_FRAME: Alternative2 Reference Frame + * @GST_AV1_REF_ALTREF_FRAME: Alternative Reference Frame + * @GST_AV1_NUM_REF_FRAMES: Total Reference Frame Number + */ +typedef enum { + GST_AV1_REF_INTRA_FRAME = 0, + GST_AV1_REF_LAST_FRAME = 1, + GST_AV1_REF_LAST2_FRAME = 2, + GST_AV1_REF_LAST3_FRAME = 3, + GST_AV1_REF_GOLDEN_FRAME = 4, + GST_AV1_REF_BWDREF_FRAME = 5, + GST_AV1_REF_ALTREF2_FRAME = 6, + GST_AV1_REF_ALTREF_FRAME = 7, + GST_AV1_NUM_REF_FRAMES +} GstAV1ReferenceFrame; + +/** + * GstAV1WarpModelType: + * @GST_AV1_WARP_MODEL_IDENTITY: Warp model is just an identity transform + * @GST_AV1_WARP_MODEL_TRANSLATION: Warp model is a pure translation + * @GST_AV1_WARP_MODEL_ROTZOOM: Warp model is a rotation + symmetric zoom + * + translation + * @GST_AV1_WARP_MODEL_AFFINE: Warp model is a general affine transform + */ +typedef enum { + GST_AV1_WARP_MODEL_IDENTITY = 0, + GST_AV1_WARP_MODEL_TRANSLATION = 1, + GST_AV1_WARP_MODEL_ROTZOOM = 2, + GST_AV1_WARP_MODEL_AFFINE = 3, +} GstAV1WarpModelType; + +/** + * GstAV1OBUHeader: + * @obu_type: the type of data structure contained in the OBU payload. + * @obu_extention_flag: indicates if OBU header extention is present. + * @obu_has_size_field: equal to 1 indicates that the obu_size syntax element will be + * present. @obu_has_size_field equal to 0 indicates that the @obu_size syntax element + * will not be present. + * @obu_temporal_id: specifies the temporal level of the data contained in the OBU. + * @obu_spatial_id: specifies the spatial level of the data contained in the OBU. + * + * Collect info for OBU header and OBU extension header if + * obu_extension_flag == 1. + */ +struct _GstAV1OBUHeader { + GstAV1OBUType obu_type; + gboolean obu_extention_flag; + gboolean obu_has_size_field; + guint8 obu_temporal_id; + guint8 obu_spatial_id; +}; + +/** + * GstAV1OBU: + * @header: a #GstAV1OBUHeader OBU Header + * @obu_type: the type of data structure contained in the OBU payload. + * @data: references the current data chunk that holds the OBU + * @obu_size: size of the OBU, not include header size + * + * It is the general representation of AV1 OBU (Open Bitstream + * Unit). One OBU include its header and payload. + */ +struct _GstAV1OBU { + GstAV1OBUHeader header; + GstAV1OBUType obu_type; + guint8 *data; + guint32 obu_size; +}; + +/** + * GstAV1OperatingPoint: + * @seq_level_idx: specifies the level that the coded video sequence conforms to. + * @seq_tier: specifies the tier that the coded video sequence conforms to. + * @idc: contains a bitmask that indicates which spatial and temporal layers should be + * decoded. Bit k is equal to 1 if temporal layer k should be decoded (for k between + * 0 and 7). Bit j+8 is equal to 1 if spatial layer j should be decoded (for j between + * 0 and 3). + * @decoder_model_present_for_this_op: equal to one indicates that there is a decoder model + * associated with this operating point. @decoder_model_present_for_this_op equal to zero + * indicates that there is not a decoder model associated. + * @decoder_buffer_delay: specifies the time interval between the arrival of the first bit + * in the smoothing buffer and the subsequent removal of the data that belongs to the + * first coded frame for operating point op, measured in units of 1/90000 seconds. The + * length of @decoder_buffer_delay is specified by @buffer_delay_length_minus_1 + 1, in bits. + * @encoder_buffer_delay: specifies, in combination with @decoder_buffer_delay syntax element, + * the first bit arrival time of frames to be decoded to the smoothing buffer. + * @encoder_buffer_delay is measured in units of 1/90000 seconds. For a video sequence that + * includes one or more random access points the sum of @decoder_buffer_delay and + * @encoder_buffer_delay shall be kept constant. + * @low_delay_mode_flag: equal to 1 indicates that the smoothing buffer operates in low-delay + * mode for operating point op. In low-delay mode late decode times and buffer underflow + * are both permitted. @low_delay_mode_flag equal to 0 indicates that the smoothing buffer + * operates in strict mode, where buffer underflow is not allowed. + * @initial_display_delay_present_for_this_op: equal to 1 indicates that + * @initial_display_delay_minus_1 is specified for this operating. 0 indicates that + * @initial_display_delay_minus_1 is not specified for this operating point. + * @initial_display_delay_minus_1: plus 1 specifies, for operating point i, the number of + * decoded frames that should be present in the buffer pool before the first presentable + * frame is displayed. This will ensure that all presentable frames in the sequence can + * be decoded at or before the time that they are scheduled for display. + */ +struct _GstAV1OperatingPoint { + guint8 seq_level_idx; + guint8 seq_tier; + guint16 idc; + gboolean decoder_model_present_for_this_op; + guint8 decoder_buffer_delay; + guint8 encoder_buffer_delay; + gboolean low_delay_mode_flag; + gboolean initial_display_delay_present_for_this_op; + guint8 initial_display_delay_minus_1; +}; + +/** + * GstAV1DecoderModelInfo: + * @buffer_delay_length_minus_1: plus 1 specifies the length of the + * @decoder_buffer_delay and the @encoder_buffer_delay syntax elements, + * in bits. + * @num_units_in_decoding_tick: is the number of time units of a decoding clock + * operating at the frequency @time_scale Hz that corresponds to one increment + * of a clock tick counter. + * @buffer_removal_time_length_minus_1: plus 1 specifies the length of the + * @buffer_removal_time syntax element, in bits. + * @frame_presentation_time_length_minus_1: plus 1 specifies the length of the + * @frame_presentation_time syntax element, in bits. + */ +struct _GstAV1DecoderModelInfo { + guint8 buffer_delay_length_minus_1; + guint32 num_units_in_decoding_tick; + guint8 buffer_removal_time_length_minus_1; + guint8 frame_presentation_time_length_minus_1; +}; + +/** + * GstAV1TimingInfo: + * @num_units_in_display_tick: is the number of time units of a clock operating at the + * frequency @time_scale Hz that corresponds to one increment of a clock tick counter. + * A clock tick, in seconds, is equal to num_units_in_display_tick divided by time_scale. + * It is a requirement of bitstream conformance that num_units_in_display_tick is greater + * than 0. + * @time_scale: is the number of time units that pass in one second. It is a requirement of + * bitstream conformance that @time_scale is greater than 0. + * @equal_picture_interval: equal to 1 indicates that pictures should be displayed according + * to their output order with the number of ticks between two consecutive pictures (without + * dropping frames) specified by @num_ticks_per_picture_minus_1 + 1. @equal_picture_interval + * equal to 0 indicates that the interval between two consecutive pictures is not specified. + * @num_ticks_per_picture_minus_1: plus 1 specifies the number of clock ticks corresponding + * to output time between two consecutive pictures in the output order. It is a requirement + * of bitstream conformance that the value of @num_ticks_per_picture_minus_1 shall be in the + * range of 0 to (1 << 32) - 2, inclusive. + */ +struct _GstAV1TimingInfo { + guint32 num_units_in_display_tick; + guint32 time_scale; + gboolean equal_picture_interval; + guint32 num_ticks_per_picture_minus_1; +}; + +/** + * GstAV1ColorConfig: + * @high_bitdepth: syntax element which, together with @seq_profile, determine the bit depth. + * @twelve_bit: is syntax elements which, together with @seq_profile and @high_bitdepth, + * determines the bit depth. + * @mono_chrome: equal to 1 indicates that the video does not contain U and V color planes. + * @mono_chrome equal to 0 indicates that the video contains Y, U, and V color planes. + * @color_description_present_flag: equal to 1 specifies that color_primaries, + * @transfer_characteristics, and @matrix_coefficients are present. + * @color_description_present_flag equal to 0 specifies that @color_primaries, + * @transfer_characteristics and @matrix_coefficients are not present. + * @color_primaries: is an integer that is defined by the "Color primaries" section of + * ISO/IEC 23091-4/ITU-T H.273. + * @transfer_characteristics: is an integer that is defined by the "Transfer characteristics" + * section of ISO/IEC 23091-4/ITU-T H.273. + * @matrix_coefficients: is an integer that is defined by the "Matrix coefficients" section + * of ISO/IEC 23091-4/ITU-T H.273. + * @color_range: is a binary value that is associated with the VideoFullRangeFlag variable + * specified in ISO/IEC 23091-4/ITU-T H.273. color range equal to 0 shall be referred to + * as the studio swing representation and color range equal to 1 shall be referred to as + * the full swing representation for all intents relating to this specification. + * @subsampling_x, @subsampling_y: specify the chroma subsampling format. If + * @matrix_coefficients is equal to GST_AV1_MC_IDENTITY, it is a requirement of bitstream + * conformance that @subsampling_x is equal to 0 and @subsampling_y is equal to 0. + * @chroma_sample_position specifies the sample position for subsampled streams: + * @separate_uv_delta_q: equal to 1 indicates that the U and V planes may have separate + * delta quantizer values. @separate_uv_delta_q equal to 0 indicates that the U and V + * planes will share the same delta quantizer value. + */ +struct _GstAV1ColorConfig { + gboolean high_bitdepth; + gboolean twelve_bit; + gboolean mono_chrome; + gboolean color_description_present_flag; + GstAV1ColorPrimaries color_primaries; + GstAV1TransferCharacteristics transfer_characteristics; + GstAV1MatrixCoefficients matrix_coefficients; + gboolean color_range; + guint8 subsampling_x; + guint8 subsampling_y; + GstAV1ChromaSamplePositions chroma_sample_position; + gboolean separate_uv_delta_q; +}; + +/** + * GstAV1SequenceHeaderOBU: + * @seq_profile: specifies the features that can be used in the coded video sequence + * @still_picture: equal to 1 specifies that the bitstream contains only one coded frame. + * @reduced_still_picture_header: specifies that the syntax elements not needed by a still + * picture are omitted. + * @frame_width_bits_minus_1: specifies the number of bits minus 1 used for transmitting + * the frame width syntax elements. + * @frame_height_bits_minus_1: specifies the number of bits minus 1 used for transmitting + * the frame height syntax elements. + * @max_frame_width_minus_1: specifies the maximum frame width minus 1 for the frames + * represented by this sequenceheader. + * @max_frame_height_minus_1: specifies the maximum frame height minus 1 for the frames + * represented by this sequenceheader. + * @frame_id_numbers_present_flag: specifies whether frame id numbers are present in the bitstream. + * @delta_frame_id_length_minus_2: specifies the number of bits minus 2 used to encode + * delta_frame_id syntax elements. + * @additional_frame_id_length_minus_1: is used to calculate the number of bits used to + * encode the frame_id syntax element. + * @use_128x128_superblock: when equal to 1, indicates that superblocks contain 128x128 luma + * samples. When equal to 0, it indicates that superblocks contain 64x64 luma samples. + * (The number of contained chroma samples depends on @subsampling_x and @subsampling_y). + * @enable_filter_intra: equal to 1 specifies that the @use_filter_intra syntax element may + * be present. @enable_filter_intra equal to 0 specifies that the @use_filter_intra syntax + * element will not be present. + * @enable_intra_edge_filter: specifies whether the intra edge filtering process should be enabled. + * @enable_interintra_compound: equal to 1 specifies that the mode info for inter blocks may + * contain the syntax element interintra. @enable_interintra_compound equal to 0 specifies + * that the syntax element interintra will not be present. + * @enable_masked_compound: equal to 1 specifies that the mode info for inter blocks may + * contain the syntax element @compound_type. @enable_masked_compound equal to 0 specifies + * that the syntax element @compound_type will not be present. + * @enable_warped_motion: equal to 1 indicates that the allow_warped_motion syntax element + * may be present. @enable_warped_motion equal to 0 indicates that the @allow_warped_motion + * syntax element will not be present. + * @enable_order_hint: equal to 1 indicates that tools based on the values of order hints + * may be used. @enable_order_hint equal to 0 indicates that tools based on order hints + * are disabled. + * @enable_dual_filter: equal to 1 indicates that the inter prediction filter type may be + * specified independently in the horizontal and vertical directions. If the flag is equal + * to 0, only one filter type may be specified, which is then used in both directions. + * @enable_jnt_comp: equal to 1 indicates that the distance weights process may be used + * for inter prediction. + * @enable_ref_frame_mvs: equal to 1 indicates that the @use_ref_frame_mvs syntax element + * may be present. @enable_ref_frame_mvs equal to 0 indicates that the @use_ref_frame_mvs + * syntax element will not be present. + * @seq_choose_screen_content_tools: equal to 0 indicates that the @seq_force_screen_content_tools + * syntax element will be present. @seq_choose_screen_content_tools equal to 1 indicates + * that @seq_force_screen_content_tools should be set equal to SELECT_SCREEN_CONTENT_TOOLS. + * @seq_force_screen_content_tools: equal to SELECT_SCREEN_CONTENT_TOOLS indicates that the + * @allow_screen_content_tools syntax element will be present in the frame header. Otherwise, + * @seq_force_screen_content_tools contains the value for @allow_screen_content_tools. + * @seq_choose_integer_mv: equal to 0 indicates that the seq_force_integer_mv syntax element + * will be present. @seq_choose_integer_mv equal to 1 indicates that @seq_force_integer_mv + * should be set equal to SELECT_INTEGER_MV. + * @seq_force_integer_mv: equal to SELECT_INTEGER_MV indicates that the @force_integer_mv + * syntax element will be present in the frame header (providing allow_screen_content_tools + * is equal to 1). Otherwise, @seq_force_integer_mv contains the value for @force_integer_mv. + * @order_hint_bits_minus_1: is used to compute OrderHintBits. + * @enable_superres: equal to 1 specifies that the use_superres syntax element will be present + * in the uncompressed header. enable_superres equal to 0 specifies that the use_superres + * syntax element will not be present (instead use_superres will be set to 0 in the + * uncompressed header without being read). + * @enable_cdef: equal to 1 specifies that cdef filtering may be enabled. enable_cdef equal + * to 0 specifies that cdef filtering is disabled. + * @enable_restoration: equal to 1 specifies that loop restoration filtering may be enabled. + * enable_restoration equal to 0 specifies that loop restoration filtering is disabled. + * @film_grain_params_present: specifies whether film grain parameters are present in the bitstream. + * @operating_points_cnt_minus_1: indicates the number of operating points minus 1 present + * in this bitstream. + * @operating_points: specifies the corresponding operating point for a set of operating + * parameters. + * @decoder_model_info_present_flag: specifies whether the decoder model info is present in + * the bitstream. + * @decoder_model_info: holds information about the decoder model. + * @initial_display_delay_present_flag: specifies whether initial display delay information + * is present in the bitstream or not. + * @timing_info_present_flag: specifies whether timing info is present in the bitstream. + * @timing_info: holds the timing information. + * @color_config: hold the color configuration. + * @order_hint_bits: specifies the number of bits used for the order_hint syntax element. + * @bit_depth: the bit depth of the stream. + * @num_planes: the YUV plane number. + */ +struct _GstAV1SequenceHeaderOBU { + GstAV1Profile seq_profile; + gboolean still_picture; + guint8 reduced_still_picture_header; + + guint8 frame_width_bits_minus_1; + guint8 frame_height_bits_minus_1; + guint16 max_frame_width_minus_1; + guint16 max_frame_height_minus_1; + + gboolean frame_id_numbers_present_flag; + guint8 delta_frame_id_length_minus_2; + guint8 additional_frame_id_length_minus_1; + + gboolean use_128x128_superblock; + gboolean enable_filter_intra; + gboolean enable_intra_edge_filter; + gboolean enable_interintra_compound; + gboolean enable_masked_compound; + gboolean enable_warped_motion; + gboolean enable_order_hint; + gboolean enable_dual_filter; + gboolean enable_jnt_comp; + gboolean enable_ref_frame_mvs; + gboolean seq_choose_screen_content_tools; + guint8 seq_force_screen_content_tools; + gboolean seq_choose_integer_mv; + guint8 seq_force_integer_mv; + gint8 order_hint_bits_minus_1; + + gboolean enable_superres; + gboolean enable_cdef; + gboolean enable_restoration; + + guint8 film_grain_params_present; + + guint8 operating_points_cnt_minus_1; + GstAV1OperatingPoint operating_points[GST_AV1_MAX_OPERATING_POINTS]; + + gboolean decoder_model_info_present_flag; + GstAV1DecoderModelInfo decoder_model_info; + guint8 initial_display_delay_present_flag; + + gboolean timing_info_present_flag; + GstAV1TimingInfo timing_info; + + GstAV1ColorConfig color_config; + + /* Global var calculated by sequence */ + guint8 order_hint_bits; /* OrderHintBits */ + guint8 bit_depth; /* BitDepth */ + guint8 num_planes; /* NumPlanes */ +}; + +/** + * GstAV1MetadataITUT_T35: + * @itu_t_t35_country_code: shall be a byte having a value specified as a country code by + * Annex A of Recommendation ITU-T T.35. + * @itu_t_t35_country_code_extension_byte: shall be a byte having a value specified as a + * country code by Annex B of Recommendation ITU-T T.35. + * @itu_t_t35_payload_bytes: shall be bytes containing data registered as specified in + * Recommendation ITU-T T.35. + */ +struct _GstAV1MetadataITUT_T35 { + guint8 itu_t_t35_country_code; + guint8 itu_t_t35_country_code_extention_byte; + /* itu_t_t35_payload_bytes - not specified at this spec */ + guint8 *itu_t_t35_payload_bytes; +}; + +/** + * GstAV1MetadataHdrCll: + * @max_cll: specifies the maximum content light level as specified in CEA-861.3, Appendix A. + * @max_fall: specifies the maximum frame-average light level as specified in CEA-861.3, Appendix A. + * + * High Dynamic Range content light level syntax metadata. + */ +struct _GstAV1MetadataHdrCll { + guint16 max_cll; + guint16 max_fall; +}; + +/** + * GstAV1MetadataHdrMdcv: + * @primary_chromaticity_x: specifies a 0.16 fixed-point X chromaticity coordinate as + * defined by CIE 1931, where i = 0,1,2 specifies Red, Green, Blue respectively. + * @primary_chromaticity_y: specifies a 0.16 fixed-point Y chromaticity coordinate as + * defined by CIE 1931, where i = 0,1,2 specifies Red, Green, Blue respectively. + * @white_point_chromaticity_x: specifies a 0.16 fixed-point white X chromaticity coordinate + * as defined by CIE 1931. + * @white_point_chromaticity_y: specifies a 0.16 fixed-point white Y chromaticity coordinate + * as defined by CIE 1931. + * @luminance_max: is a 24.8 fixed-point maximum luminance, represented in candelas per + * square meter. + * @luminance_min: is a 18.14 fixed-point minimum luminance, represented in candelas per + * square meter. + * + * High Dynamic Range mastering display color volume metadata. + */ +struct _GstAV1MetadataHdrMdcv { + guint16 primary_chromaticity_x[3]; + guint16 primary_chromaticity_y[3]; + guint16 white_point_chromaticity_x; + guint16 white_point_chromaticity_y; + guint32 luminance_max; + guint32 luminance_min; +}; + +/** + * GstAV1MetadataScalability: + * @scalability_mode_idc: indicates the picture prediction structure of the bitstream. + * @spatial_layers_cnt_minus_1: indicates the number of spatial layers present in the video + * sequence minus one. + * @spatial_layer_description_present_flag: indicates when set to 1 that the + * spatial_layer_ref_id is present for each of the (@spatial_layers_cnt_minus_1 + 1) layers, + * or that it is not present when set to 0. + * @spatial_layer_dimensions_present_flag: indicates when set to 1 that the + * @spatial_layer_max_width and @spatial_layer_max_height parameters are present for each of + * the (@spatial_layers_cnt_minus_1 + 1) layers, or that it they are not present when set to 0. + * @temporal_group_description_present_flag: indicates when set to 1 that the temporal + * dependency information is present, or that it is not when set to 0. + * @spatial_layer_max_width: specifies the maximum frame width for the frames with + * @spatial_id equal to i. This number must not be larger than @max_frame_width_minus_1 + 1. + * @spatial_layer_max_height: specifies the maximum frame height for the frames with + * @spatial_id equal to i. This number must not be larger than @max_frame_height_minus_1 + 1. + * @spatial_layer_ref_id: specifies the @spatial_id value of the frame within the current + * temporal unit that the frame of layer i uses for reference. If no frame within the + * current temporal unit is used for reference the value must be equal to 255. + * @temporal_group_size: indicates the number of pictures in a temporal picture group. If the + * @temporal_group_size is greater than 0, then the scalability structure data allows the + * inter-picture temporal dependency structure of the video sequence to be specified. If the + * @temporal_group_size is greater than 0, then for @temporal_group_size pictures in the + * temporal group, each picture's temporal layer id (@temporal_id), switch up points + * (@temporal_group_temporal_switching_up_point_flag and + * @temporal_group_spatial_switching_up_point_flag), and the reference picture indices + * (@temporal_group_ref_pic_diff) are specified. The first picture specified in a temporal + * group must have @temporal_id equal to 0. If the parameter @temporal_group_size is not + * present or set to 0, then either there is only one temporal layer or there is no fixed + * inter-picture temporal dependency present going forward in the video sequence. Note that + * for a given picture, all frames follow the same inter-picture temporal dependency + * structure. However, the frame rate of each layer can be different from each other. The + * specified dependency structure in the scalability structure data must be for the highest + * frame rate layer. + * @temporal_group_temporal_id: specifies the temporal_id value for the i-th picture in + * the temporal group. + * @temporal_group_temporal_switching_up_point_flag: is set to 1 if subsequent (in decoding + * order) pictures with a @temporal_id higher than @temporal_group_temporal_id[i] do not + * depend on any picture preceding the current picture (in coding order) with @temporal_id + * higher than @temporal_group_temporal_id[ i ]. + * @temporal_group_spatial_switching_up_point_flag: is set to 1 if spatial layers of the + * current picture in the temporal group (i.e., pictures with a spatial_id higher than zero) + * do not depend on any picture preceding the current picture in the temporal group. + * @temporal_group_ref_cnt: indicates the number of reference pictures used by the i-th + * picture in the temporal group. + * @temporal_group_ref_pic_diff: indicates, for the i-th picture in the temporal group, + * the temporal distance between the i-th picture and the j-th reference picture used by + * the i-th picture. The temporal distance is measured in frames, counting only frames of + * identical @spatial_id values. + * + * The scalability metadata OBU is intended for use by intermediate + * processing entities that may perform selective layer elimination. + */ +struct _GstAV1MetadataScalability { + GstAV1ScalabilityModes scalability_mode_idc; + guint8 spatial_layers_cnt_minus_1; + gboolean spatial_layer_dimensions_present_flag; + gboolean spatial_layer_description_present_flag; + gboolean temporal_group_description_present_flag; + guint16 spatial_layer_max_width[GST_AV1_MAX_SPATIAL_LAYERS]; + guint16 spatial_layer_max_height[GST_AV1_MAX_SPATIAL_LAYERS]; + guint8 spatial_layer_ref_id[GST_AV1_MAX_SPATIAL_LAYERS]; + guint8 temporal_group_size; + + guint8 temporal_group_temporal_id[GST_AV1_MAX_TEMPORAL_GROUP_SIZE]; + guint8 temporal_group_temporal_switching_up_point_flag[GST_AV1_MAX_TEMPORAL_GROUP_SIZE]; + guint8 temporal_group_spatial_switching_up_point_flag[GST_AV1_MAX_TEMPORAL_GROUP_SIZE]; + guint8 temporal_group_ref_cnt[GST_AV1_MAX_TEMPORAL_GROUP_SIZE]; + guint8 temporal_group_ref_pic_diff[GST_AV1_MAX_TEMPORAL_GROUP_SIZE] + [GST_AV1_MAX_TEMPORAL_GROUP_REFERENCES]; +}; + +/** + * GstAV1MetadataTimecode: + * @counting_type: specifies the method of dropping values of the n_frames syntax element as + * specified in AV1 Spec 6.1.1. @counting_type should be the same for all pictures in the + * coded video sequence. + * @full_timestamp_flag: equal to 1 indicates that the the @seconds_value, @minutes_value, + * @hours_value syntax elements will be present. @full_timestamp_flag equal to 0 indicates + * that there are flags to control the presence of these syntax elements. + * @discontinuity_flag: equal to 0 indicates that the difference between the current value + * of clockTimestamp and the value of clockTimestamp computed from the previous set of + * timestamp syntax elements in output order can be interpreted as the time difference + * between the times of origin or capture of the associated frames or fields. + * @discontinuity_flag equal to 1 indicates that the difference between the current value of + * clockTimestamp and the value of clockTimestamp computed from the previous set of clock + * timestamp syntax elements in output order should not be interpreted as the time difference + * between the times of origin or capture of the associated frames or fields. + * @cnt_dropped_flag: specifies the skipping of one or more values of @n_frames using the + * counting method specified by counting_type. + * @n_frames: is used to compute clockTimestamp. When @timing_info_present_flag is equal to 1, + * @n_frames shall be less than maxFps, where maxFps is specified by + * maxFps = ceil( time_scale / ( 2 * @num_units_in_display_tick ) ). + * @seconds_flag: equal to 1 specifies that @seconds_value and @minutes_flag are present when + * @full_timestamp_flag is equal to 0. @seconds_flag equal to 0 specifies that @seconds_value + * and @minutes_flag are not present. + * @seconds_value: is used to compute clockTimestamp and shall be in the range of 0 to 59. + * When @seconds_value is not present, its value is inferred to be equal to the value of + * @seconds_value for the previous set of clock timestamp syntax elements in decoding order, + * and it is required that such a previous @seconds_value shall have been present. + * @minutes_flag: equal to 1 specifies that @minutes_value and @hours_flag are present when + * @full_timestamp_flag is equal to 0 and @seconds_flag is equal to 1. @minutes_flag equal to 0 + * specifies that @minutes_value and @hours_flag are not present. + * @minutes_value: specifies the value of mm used to compute clockTimestamp and shall be in + * the range of 0 to 59, inclusive. When minutes_value is not present, its value is inferred + * to be equal to the value of @minutes_value for the previous set of clock timestamp syntax + * elements in decoding order, and it is required that such a previous @minutes_value shall + * have been present. + * @hours_flag: equal to 1 specifies that @hours_value is present when @full_timestamp_flag is + * equal to 0 and @seconds_flag is equal to 1 and @minutes_flag is equal to 1. + * @hours_value: is used to compute clockTimestamp and shall be in the range of 0 to 23, + * inclusive. When @hours_value is not present, its value is inferred to be equal to the + * value of @hours_value for the previous set of clock timestamp syntax elements in decoding + * order, and it is required that such a previous @hours_value shall have been present. + * @time_offset_length: greater than 0 specifies the length in bits of the @time_offset_value + * syntax element. @time_offset_length equal to 0 specifies that the @time_offset_value syntax + * element is not present. @time_offset_length should be the same for all pictures in the + * coded video sequence. + * @time_offset_value: is used to compute clockTimestamp. The number of bits used to represent + * @time_offset_value is equal to @time_offset_length. When @time_offset_value is not present, + * its value is inferred to be equal to 0. + */ +struct _GstAV1MetadataTimecode { + guint8 counting_type; /* candidate for sperate Type GstAV1TimecodeCountingType */ + gboolean full_timestamp_flag; + gboolean discontinuity_flag; + gboolean cnt_dropped_flag; + guint8 n_frames; + gboolean seconds_flag; + guint8 seconds_value; + gboolean minutes_flag; + guint8 minutes_value; + gboolean hours_flag; + guint8 hours_value; + guint8 time_offset_length; + guint32 time_offset_value; +}; + +/** + * GstAV1MetadataOBU: + * @metadata_type: type of metadata + * @itut_t35: ITUT T35 metadata + * @hdrcll: high dynamic range content light level metadata + * @hdrcmdcv: high dynamic range mastering display color volume metadata_type + * @scalability: Scalability metadata + * @timecode: Timecode metadata + */ +struct _GstAV1MetadataOBU { + GstAV1MetadataType metadata_type; + union { + GstAV1MetadataITUT_T35 itut_t35; + GstAV1MetadataHdrCll hdr_cll; + GstAV1MetadataHdrMdcv hdr_mdcv; + GstAV1MetadataScalability scalability; + GstAV1MetadataTimecode timecode; + }; +}; + +/** + * GstAV1LoopFilterParams: + * @loop_filter_level: is an array containing loop filter strength values. Different loop + * filter strength values from the array are used depending on the image plane being + * filtered, and the edge direction (vertical or horizontal) being filtered. + * @loop_filter_sharpness: indicates the sharpness level. The @loop_filter_level and + * @loop_filter_sharpness together determine when a block edge is filtered, and by how much + * the filtering can change the sample values. The loop filter process is described in AV1 + * Bitstream Spec. section 7.14. + * @loop_filter_delta_enabled: equal to 1 means that the filter level depends on the mode and + * reference frame used to predict a block. @loop_filter_delta_enabled equal to 0 means that + * the filter level does not depend on the mode and reference frame. + * @loop_filter_delta_update: equal to 1 means that the bitstream contains additional syntax + * elements that specify which mode and reference frame deltas are to be updated. + * @loop_filter_delta_update equal to 0 means that these syntax elements are not present. + * @loop_filter_ref_deltas: contains the adjustment needed for the filter level based on + * the chosen reference frame. If this syntax element is not present in the bitstream, + * it maintains its previous value. + * @loop_filter_mode_deltas: contains the adjustment needed for the filter level based on + * the chosen mode. If this syntax element is not present in the bitstream, it maintains + * its previous value. + * @delta_lf_present: specifies whether loop filter delta values are present in the bitstream. + * @delta_lf_res: specifies the left shift which should be applied to decoded loop filter + * delta values. + * @delta_lf_multi: equal to 1 specifies that separate loop filter deltas are sent for + * horizontal luma edges, vertical luma edges, the U edges, and the V edges. @delta_lf_multi + * equal to 0 specifies that the same loop filter delta is used for all edges. + */ +struct _GstAV1LoopFilterParams { + guint8 loop_filter_level[4]; + guint8 loop_filter_sharpness; + gboolean loop_filter_delta_enabled; + gboolean loop_filter_delta_update; + + guint8 loop_filter_ref_deltas[GST_AV1_TOTAL_REFS_PER_FRAME]; + guint8 loop_filter_mode_deltas[2]; + + gboolean delta_lf_present; + guint8 delta_lf_res; + guint8 delta_lf_multi; +}; + +/** + * GstAV1QuantizationParams: + * @base_q_idx: indicates the base frame qindex. This is used for Y AC coefficients and as + * the base value for the other quantizers. + * @diff_uv_delta: equal to 1 indicates that the U and V delta quantizer values are coded + * separately. @diff_uv_delta equal to 0 indicates that the U and V delta quantizer values + * share a common value. + * @using_qmatrix: specifies that the quantizer matrix will be used to compute quantizers. + * @qm_y: specifies the level in the quantizer matrix that should be used for luma plane decoding. + * @qm_u: specifies the level in the quantizer matrix that should be used for chroma U plane decoding. + * @qm_v: specifies the level in the quantizer matrix that should be used for chroma V plane decoding. + * @delta_q_present: specifies whether quantizer index delta values are present in the bitstream. + * @delta_q_res: specifies the left shift which should be applied to decoded quantizer index + * delta values. + * @delta_q_y_dc: indicates the Y DC quantizer relative to base_q_idx. + * @delta_q_u_dc: indicates the U DC quantizer relative to base_q_idx. + * @delta_q_u_ac: indicates the U AC quantizer relative to base_q_idx. + * @delta_q_v_dc: indicates the V DC quantizer relative to base_q_idx. + * @delta_q_v_ac: indicates the V AC quantizer relative to base_q_idx. + */ +struct _GstAV1QuantizationParams { + guint8 base_q_idx; + gboolean diff_uv_delta; + gboolean using_qmatrix; + guint8 qm_y; + guint8 qm_u; + guint8 qm_v; + + gboolean delta_q_present; + guint8 delta_q_res; + + gint8 delta_q_y_dc; /* DeltaQYDc */ + gint8 delta_q_u_dc; /* DeltaQUDc */ + gint8 delta_q_u_ac; /* DeltaQUAc */ + gint8 delta_q_v_dc; /* DeltaQVDc */ + gint8 delta_q_v_ac; /* DeltaQVAc */ +}; + +/** + * GstAV1SegmenationParams: + * @segmentation_enabled: equal to 1 indicates that this frame makes use of the segmentation + * tool; @segmentation_enabled equal to 0 indicates that the frame does not use segmentation. + * @segmentation_update_map: equal to 1 indicates that the segmentation map are updated during + * the decoding of this frame. @segmentation_update_map equal to 0 means that the segmentation + * map from the previous frame is used. + * @segmentation_temporal_update: equal to 1 indicates that the updates to the segmentation map + * are coded relative to the existing segmentation map. @segmentation_temporal_update equal to + * 0 indicates that the new segmentation map is coded without reference to the existing + * segmentation map. + * @segmentation_update_data: equal to 1 indicates that new parameters are about to be + * specified for each segment. @segmentation_update_data equal to 0 indicates that the + * segmentation parameters should keep their existing values. + * @feature_enabled: set to 1 when the feature of segmentation is enabled. + * @feature_data: the value of according segmentation feature. + * @seg_id_pre_skip: equal to 1 indicates that the segment id will be read before the skip + * syntax element. @seg_id_pre_skip equal to 0 indicates that the skip syntax element will be + * read first. + * @last_active_seg_id: indicates the highest numbered segment id that has some enabled feature. + * This is used when decoding the segment id to only decode choices corresponding to used + * segments. + */ +struct _GstAV1SegmenationParams { + gboolean segmentation_enabled; + guint8 segmentation_update_map; + guint8 segmentation_temporal_update; + guint8 segmentation_update_data; + + gint8 feature_enabled[GST_AV1_MAX_SEGMENTS][GST_AV1_SEG_LVL_MAX]; /* FeatureEnabled */ + gint16 feature_data[GST_AV1_MAX_SEGMENTS][GST_AV1_SEG_LVL_MAX]; /* FeatureData */ + guint8 seg_id_pre_skip; /* SegIdPreSkip */ + guint8 last_active_seg_id; /* LastActiveSegId */ +}; + +/** + * GstAV1TileInfo: + * @uniform_tile_spacing_flag: equal to 1 means that the tiles are uniformly spaced across the + * frame. (In other words, all tiles are the same size except for the ones at the right and + * bottom edge which can be smaller.) @uniform_tile_spacing_flag equal to 0 means that the + * tile sizes are coded. + * @increment_tile_rows_log2: is used to compute @tile_rows_log2. + * @width_in_sbs_minus_1: specifies the width of a tile minus 1 in units of superblocks. + * @height_in_sbs_minus_1: specifies the height of a tile minus 1 in units of superblocks. + * @tile_size_bytes_minus_1: is used to compute @tile_size_bytes + * @context_update_tile_id: specifies which tile to use for the CDF update. + * @mi_col_starts: is an array specifying the start column (in units of 4x4 luma samples) for + * each tile across the image. + * @mi_row_starts: is an array specifying the start row (in units of 4x4 luma samples) for + * each tile down the image. + * @tile_cols_log2: specifies the base 2 logarithm of the desired number of tiles across the frame. + * @tile_cols: specifies the number of tiles across the frame. It is a requirement of bitstream + * conformance that @tile_cols is less than or equal to GST_AV1_MAX_TILE_COLS. + * @tile_rows_log2: specifies the base 2 logarithm of the desired number of tiles down the frame. + * @tile_rows: specifies the number of tiles down the frame. It is a requirement of bitstream + * conformance that @tile_rows is less than or equal to GST_AV1_MAX_TILE_ROWS. + * @tile_size_bytes: specifies the number of bytes needed to code each tile size. + */ +struct _GstAV1TileInfo { + guint8 uniform_tile_spacing_flag; + gint increment_tile_rows_log2; + gint width_in_sbs_minus_1[GST_AV1_MAX_TILE_COLS]; + gint height_in_sbs_minus_1[GST_AV1_MAX_TILE_ROWS]; + gint tile_size_bytes_minus_1; + guint8 context_update_tile_id; + + guint32 mi_col_starts[GST_AV1_MAX_TILE_COLS + 1]; /* MiColStarts */ + guint32 mi_row_starts[GST_AV1_MAX_TILE_ROWS + 1]; /* MiRowStarts */ + guint8 tile_cols_log2; /* TileColsLog2 */ + guint8 tile_cols; /* TileCols */ + guint8 tile_rows_log2; /* TileRowsLog2 */ + guint8 tile_rows; /* TileRows */ + guint8 tile_size_bytes; /* TileSizeBytes */ +}; + +/** + * GstAV1CDEFParams: + * @cdef_damping: controls the amount of damping in the deringing filter. + * @cdef_bits: specifies the number of bits needed to specify which CDEF filter to apply. + * @cdef_y_pri_strength: specify the strength of the primary filter (Y component) + * @cdef_uv_pri_strength: specify the strength of the primary filter (UV components). + * @cdef_y_sec_strength: specify the strength of the secondary filter (Y component). + * @cdef_uv_sec_strength: specify the strength of the secondary filter (UV components). + * + * Parameters of Constrained Directional Enhancement Filter (CDEF). + */ +struct _GstAV1CDEFParams { + guint8 cdef_damping; + guint8 cdef_bits; + guint8 cdef_y_pri_strength[GST_AV1_CDEF_MAX]; + guint8 cdef_y_sec_strength[GST_AV1_CDEF_MAX]; + guint8 cdef_uv_pri_strength[GST_AV1_CDEF_MAX]; + guint8 cdef_uv_sec_strength[GST_AV1_CDEF_MAX]; +}; + +/** + * GstAV1LoopRestorationParams: + * @lr_unit_shift: specifies if the luma restoration size should be halved. + * @lr_uv_shift: is only present for 4:2:0 formats and specifies if the chroma size should be + * half the luma size. + * @frame_restoration_type: specifies the type of restoration used for each plane. + * @loop_restoration_size: specifies the size of loop restoration units in units of samples in + * the current plane. + * @uses_lr: indicates if any plane uses loop restoration. + */ +struct _GstAV1LoopRestorationParams { + guint8 lr_unit_shift; + gboolean lr_uv_shift; + + GstAV1FrameRestorationType frame_restoration_type[GST_AV1_MAX_NUM_PLANES]; /* FrameRestorationType */ + guint32 loop_restoration_size[GST_AV1_MAX_NUM_PLANES]; /* LoopRestorationSize */ + guint8 uses_lr; /* UsesLr */ +}; + +/** + * GstAV1GlobalMotionParams: + * @is_global: specifies whether global motion parameters are present for a particular + * reference frame. + * @is_rot_zoom: specifies whether a particular reference frame uses rotation and zoom + * global motion. + * @is_translation: specifies whether a particular reference frame uses translation + * global motion. + * @gm_params: is set equal to SavedGmParams[ frame_to_show_map_idx ][ ref ][ j ] for + * ref = LAST_FRAME..ALTREF_FRAME, for j = 0..5. + * @gm_type: specifying the type of global motion. + */ +struct _GstAV1GlobalMotionParams { + gboolean is_global[GST_AV1_NUM_REF_FRAMES]; + gboolean is_rot_zoom[GST_AV1_NUM_REF_FRAMES]; + gboolean is_translation[GST_AV1_NUM_REF_FRAMES]; + gint32 gm_params[GST_AV1_NUM_REF_FRAMES][6]; + + GstAV1WarpModelType gm_type[GST_AV1_NUM_REF_FRAMES]; /* GmType */ +}; + +/** + * GstAV1FilmGrainParams: + * @apply_grain: equal to 1 specifies that film grain should be added to this frame. + * apply_grain equal to 0 specifies that film grain should not be added. + * @grain_seed: specifies the starting value for the pseudo-random numbers used during film + * grain synthesis. + * @update_grain: equal to 1 means that a new set of parameters should be sent. @update_grain + * equal to 0 means that the previous set of parameters should be used. + * @film_grain_params_ref_idx: indicates which reference frame contains the film grain + * parameters to be used for this frame. + * @num_y_points: specifies the number of points for the piece-wise linear scaling function + * of the luma component. It is a requirement of bitstream conformance that @num_y_points is + * less than or equal to 14. + * @point_y_value: represents the x (luma value) coordinate for the i-th point of the + * piecewise linear scaling function for luma component. The values are signaled on the + * scale of 0..255. (In case of 10 bit video, these values correspond to luma values divided + * by 4. In case of 12 bit video, these values correspond to luma values divided by 16.) + * If i is greater than 0, it is a r equirement of bitstream conformance that + * @point_y_value[ i ] is greater than @point_y_value[ i - 1 ] (this ensures the x coordinates + * are specified in increasing order). + * @point_y_scaling: represents the scaling (output) value for the i-th point of the + * piecewise linear scaling function for luma component. + * @chroma_scaling_from_luma: specifies that the chroma scaling is inferred from the luma scaling. + * @num_cb_points: specifies the number of points for the piece-wise linear scaling function + * of the cb component. It is a requirement of bitstream conformance that @num_cb_points is + * less than or equal to 10. + * @point_cb_value: represents the x coordinate for the i-th point of the piece-wise linear + * scaling function for cb component. The values are signaled on the scale of 0..255. If i + * is greater than 0, it is a requirement of bitstream conformance that point_cb_value[ i ] + * is greater than point_cb_value[ i - 1 ]. + * @point_cb_scaling: represents the scaling (output) value for the i-th point of the + * piecewise linear scaling function for cb component. + * @num_cr_points: specifies represents the number of points for the piece-wise linear scaling + * function of the cr component. It is a requirement of bitstream conformance that + * num_cr_points is less than or equal to 10. If subsampling_x is equal to 1 and + * @subsampling_y is equal to 1 and num_cb_points is equal to 0, it is a requirement of + * bitstream conformance that num_cr_points is equal to 0. If @subsampling_x is equal to 1 + * and @subsampling_y is equal to 1 and @num_cb_points is not equal to 0, it is a requirement + * of bitstream conformance that @num_cr_points is not equal to 0. + * @point_cr_value: represents the x coordinate for the i-th point of the piece-wise linear + * scaling function for cr component. The values are signaled on the scale of 0..255. If i + * is greater than 0, it is a requirement of bitstream conformance that @point_cr_value[ i ] + * is greater than @point_cr_value[ i - 1 ]. + * @point_cr_scaling: represents the scaling (output) value for the i-th point of the + * piecewise linear scaling function for cr component. + * @grain_scaling_minus_8: represents the shift - 8 applied to the values of the chroma + * component. The @grain_scaling_minus_8 can take values of 0..3 and determines the range and + * quantization step of the standard deviation of film grain. + * @ar_coeff_lag: specifies the number of auto-regressive coefficients for luma and chroma. + * @ar_coeffs_y_plus_128: specifies auto-regressive coefficients used for the Y plane. + * @ar_coeffs_cb_plus_128: specifies auto-regressive coefficients used for the U plane. + * @ar_coeffs_cr_plus_128: specifies auto-regressive coefficients used for the V plane. + * @ar_coeff_shift_minus_6: specifies the range of the auto-regressive coefficients. Values + * of 0, 1, 2, and 3 correspond to the ranges for auto-regressive coefficients of [-2, 2), + * [-1, 1), [-0.5, 0.5) and [-0.25, 0.25) respectively. + * @grain_scale_shift: specifies how much the Gaussian random numbers should be scaled down + * during the grain synthesis process. + * @cb_mult: represents a multiplier for the cb component used in derivation of the input + * index to the cb component scaling function. + * @cb_luma_mult: represents a multiplier for the average luma component used in derivation + * of the input index to the cb component scaling function. + * @cb_offset: represents an offset used in derivation of the input index to the cb component + * scaling function. + * @cr_mult: represents a multiplier for the cr component used in derivation of the input + * index to the cr component scaling function. + * @cr_luma_mult: represents a multiplier for the average luma component used in derivation + * of the input index to the cr component scaling function. + * @cr_offset: represents an offset used in derivation of the input index to the cr component + * scaling function. + * @overlap_flag: equal to 1 indicates that the overlap between film grain blocks shall be + * applied. overlap_flag equal to 0 indicates that the overlap between film grain blocks + * shall not be applied. + * @clip_to_restricted_range: equal to 1 indicates that clipping to the restricted (studio) + * range shall be applied to the sample values after adding the film grain (see the + * semantics for color_range for an explanation of studio swing). clip_to_restricted_range + * equal to 0 indicates that clipping to the full range shall be applied to the sample + * values after adding the film grain. + */ +struct _GstAV1FilmGrainParams { + gboolean apply_grain; + guint16 grain_seed; + gboolean update_grain; + guint8 film_grain_params_ref_idx; + guint8 num_y_points; + guint8 point_y_value[GST_AV1_MAX_NUM_Y_POINTS]; + guint8 point_y_scaling[GST_AV1_MAX_NUM_Y_POINTS]; + guint8 chroma_scaling_from_luma; + guint8 num_cb_points; + guint8 point_cb_value[GST_AV1_MAX_NUM_CB_POINTS]; + guint8 point_cb_scaling[GST_AV1_MAX_NUM_CB_POINTS]; + guint8 num_cr_points; + guint8 point_cr_value[GST_AV1_MAX_NUM_CR_POINTS]; + guint8 point_cr_scaling[GST_AV1_MAX_NUM_CR_POINTS]; + guint8 grain_scaling_minus_8; + guint8 ar_coeff_lag; + guint8 ar_coeffs_y_plus_128[GST_AV1_MAX_NUM_POS_LUMA]; + guint8 ar_coeffs_cb_plus_128[GST_AV1_MAX_NUM_POS_LUMA]; + guint8 ar_coeffs_cr_plus_128[GST_AV1_MAX_NUM_POS_LUMA]; + guint8 ar_coeff_shift_minus_6; + guint8 grain_scale_shift; + guint8 cb_mult; + guint8 cb_luma_mult; + guint8 cb_offset; + guint8 cr_mult; + guint8 cr_luma_mult; + guint8 cr_offset; + gboolean overlap_flag; + gboolean clip_to_restricted_range; +}; + +/** + * GstAV1FrameHeaderOBU: + * @show_existing_frame: equal to 1, indicates the frame indexed by @frame_to_show_map_idx is + * to be output; @show_existing_frame equal to 0 indicates that further processing is required. + * If @obu_type is equal to #GST_AV1_OBU_FRAME, it is a requirement of bitstream conformance that + * @show_existing_frame is equal to 0. + * @frame_to_show_map_idx: specifies the frame to be output. It is only available if + * @show_existing_frame is 1. + * @frame_presentation_time: specifies the presentation time of the frame in clock ticks + * DispCT counted from the removal time of the last frame with frame_type equal to KEY_FRAME + * for the operating point that is being decoded. The syntax element is signaled as a fixed + * length unsigned integer with a length in bits given by + * @frame_presentation_time_length_minus_1 + 1. The @frame_presentation_time is the remainder + * of a modulo 1 << (@frame_presentation_time_length_minus_1 + 1) counter. + * @tu_presentation_delay: is a syntax element used by the decoder model. It does not affect + * the decoding process. + * @display_frame_id: provides the frame id number for the frame to output. It is a requirement + * of bitstream conformance that whenever @display_frame_id is read, the value matches + * @ref_frame_id[ @frame_to_show_map_idx ] (the value of @current_frame_id at the time that the + * frame indexed by @frame_to_show_map_idx was stored), and that + * @ref_valid[ @frame_to_show_map_idx ] is equjal to 1. It is a requirement of bitstream + * conformance that the number of bits needed to read @display_frame_id does not exceed 16. + * This is equivalent to the constraint that idLen <= 16 + * @frame_type: specifies the type of the frame. + * @show_frame: equal to 1 specifies that this frame should be immediately output once decoded. + * show_frame equal to 0 specifies that this frame should not be immediately output. (It may + * be output later if a later uncompressed header uses @show_existing_frame equal to 1). + * @showable_frame: equal to 1 specifies that the frame may be output using the + * @show_existing_frame mechanism. showable_frame equal to 0 specifies that this frame will + * not be output using the @show_existing_frame mechanism. It is a requirement of bitstream + * conformance that when @show_existing_frame is used to show a previous frame, that the + * value of @showable_frame for the previous frame was equal to 1. It is a requirement of + * bitstream conformance that a particular showable frame is output via the + * @show_existing_frame mechanism at most once. + * @error_resilient_mode: equal to 1 indicates that error resilient mode is enabled; + * @error_resilient_mode equal to 0 indicates that error resilient mode is disabled. + * @disable_cdf_update: specifies whether the CDF update in the symbol decoding process should + * be disabled. + * @allow_screen_content_tools: equal to 1 indicates that intra blocks may use palette encoding; + * @allow_screen_content_tools equal to 0 indicates that palette encoding is never used. + * @force_integer_mv: equal to 1 specifies that motion vectors will always be integers. + * @force_integer_mv equal to 0 specifies that motion vectors can contain fractional bits. + * @current_frame_id: specifies the frame id number for the current frame. Frame id numbers + * are additional information that do not affect the decoding process, but provide decoders + * with a way of detecting missing reference frames so that appropriate action can be taken. + * @frame_size_override_flag: equal to 0 specifies that the frame size is equal to the size in + * the sequence header. @frame_size_override_flag equal to 1 specifies that the frame size + * will either be specified as the size of one of the reference frames, or computed from the + * @frame_width_minus_1 and @frame_height_minus_1 syntax elements. + * @order_hint: is used to compute order_hint. + * @primary_ref_frame: specifies which reference frame contains the CDF values and other state + * that should be loaded at the start of the frame. + * @buffer_removal_time_present_flag: equal to 1 specifies that @buffer_removal_time is present + * in the bitstream. @buffer_removal_time_present_flag equal to 0 specifies that + * @buffer_removal_time is not present in the bitstream. + * @buffer_removal_time: specifies the frame removal time in units of DecCT clock ticks + * counted from the removal time of the last frame with frame_type equal to KEY_FRAME for + * operating point opNum. @buffer_removal_time is signaled as a fixed length unsigned integer + * with a length in bits given by @buffer_removal_time_length_minus_1 + 1. @buffer_removal_time + * is the remainder of a modulo 1 << ( @buffer_removal_time_length_minus_1 + 1 ) counter. + * @refresh_frame_flags: contains a bitmask that specifies which reference frame slots will be + * updated with the current frame after it is decoded. If @frame_type is equal to + * #GST_AV1_INTRA_ONLY_FRAME, it is a requirement of bitstream conformance that + * @refresh_frame_flags is not equal to 0xff. + * @ref_order_hint: specifies the expected output order hint for each reference buffer. + * @allow_intrabc: equal to 1 indicates that intra block copy may be used in this frame. + * allow_intrabc equal to 0 indicates that intra block copy is not allowed in this frame. + * @frame_refs_short_signaling: equal to 1 indicates that only two reference frames are + * explicitly signaled. frame_refs_short_signaling equal to 0 indicates that all reference + * frames are explicitly signaled. + * @last_frame_idx: specifies the reference frame to use for LAST_FRAME. + * @gold_frame_idx: specifies the reference frame to use for GOLDEN_FRAME. + * @ref_frame_idx[i]: specifies which reference frames are used by inter frames. + * @delta_frame_id_minus_1 is used to calculate @delta_frame_id. + * @allow_high_precision_mv: equal to 0 specifies that motion vectors are specified to quarter + * pel precision; @allow_high_precision_mv equal to 1 specifies that motion vectors are + * specified to eighth pel precision. + * @is_motion_mode_switchable: equal to 0 specifies that only the SIMPLE motion mode will be used. + * @use_ref_frame_mvs: equal to 1 specifies that motion vector information from a previous + * frame can be used when decoding the current frame. @use_ref_frame_mvs equal to 0 specifies + * that this information will not be used. + * @disable_frame_end_update_cdf: equal to 1 indicates that the end of frame CDF update is + * disabled; @disable_frame_end_update_cdf equal to 0 indicates that the end of frame CDF + * update is enabled. + * @allow_warped_motion: equal to 1 indicates that the syntax element @motion_mode may be + * present. @allow_warped_motion equal to 0 indicates that the syntax element motion_mode + * will not be present (this means that LOCALWARP cannot be signaled if @allow_warped_motion + * is equal to 0). + * @reduced_tx_set: equal to 1 specifies that the frame is restricted to a reduced subset of + * the full set of transform types. + * @render_and_frame_size_different: equal to 0 means that the render width and height are + * inferred from the frame width and height. @render_and_frame_size_different equal to 1 + * means that the render width and height are explicitly coded in the bitstream. + * @use_superres: equal to 0 indicates that no upscaling is needed. @use_superres equal to 1 + * indicates that upscaling is needed. + * @is_filter_switchable: equal to 1 indicates that the filter selection is signaled at the + * block level; @is_filter_switchable equal to 0 indicates that the filter selection is + * signaled at the frame level. + * @interpolation_filter: a #GstAV1InterpolationFilter that specifies the filter selection used + * for performing inter prediction. + * @loop_filter_params: a #GstAV1LoopFilterParams holding the loop filter parameters. + * @quantization_params: a #GstAV1QuantizationParams holding the quantization parameters. + * @segmentation_params: a #GstAV1SegmenationParams holding the segementation parameters. + * @tile_info: a #GstAV1TileInfo holding the tile info. + * @cdef_params: a #GstAV1CDEFParams holding the CDEF paramters. + * @loop_restoration_params: a #GstAV1LoopRestorationParams holding the loop restoration parameters. + * @tx_mode_select: is used to compute TxMode. + * @skip_mode_present: equal to 1 specifies that the syntax element @skip_mode will be coded + * in the bitstream. @skip_mode_present equal to 0 specifies that @skip_mode will not be used + * for this frame. + * @reference_select: equal to 1 specifies that the mode info for inter blocks contains the + * syntax element comp_mode that indicates whether to use single or compound reference + * prediction. Reference_select equal to 0 specifies that all interblocks will use single + * prediction. + * @global_motion_params: a #GstAV1GlobalMotionParams holding the global motion parameters. + * @film_grain_params: a #GstAV1FilmGrainParams holding the Film Grain parameters. + * @superres_denom: is the denominator of a fraction that specifies the ratio between the + * superblock width before and after upscaling. + * @frame_is_intra: if equal to 0 indicating that this frame may use inter prediction. + * @order_hints: specifies the expected output order for each reference frame. + * @ref_frame_sign_bias: specifies the intended direction of the motion vector in time for + * each reference frame. + * @coded_lossless: is a variable that is equal to 1 when all segments use lossless encoding. + * @all_lossless: is a variable that is equal to 1 when @coded_lossless is equal to 1 and + * @frame_width is equal to @upscaled_width. This indicates that the frame is fully lossless + * at the upscaled resolution. + * @lossless_array: whether the segmentation is lossless. + * @seg_qm_Level: the segmentation's qm level. + * @upscaled_width: the upscaled width. + * @frame_width: the frame width. + * @frame_height: the frame height. + * @render_width: the frame width to be rendered. + * @render_height: the frame height to be rendered. + * @tx_mode: specifies how the transform size is determined. + * @skip_mode_frame: specifies the frames to use for compound prediction when @skip_mode is 1. + */ +struct _GstAV1FrameHeaderOBU { + gboolean show_existing_frame; + guint8 frame_to_show_map_idx; + guint32 frame_presentation_time; + guint32 tu_presentation_delay; + guint32 display_frame_id; + GstAV1FrameType frame_type; + gboolean show_frame; + gboolean showable_frame; + gboolean error_resilient_mode; + gboolean disable_cdf_update; + guint8 allow_screen_content_tools; + gboolean force_integer_mv; + guint32 current_frame_id; + gboolean frame_size_override_flag; + guint32 order_hint; + guint8 primary_ref_frame; + gboolean buffer_removal_time_present_flag; + guint32 buffer_removal_time[GST_AV1_MAX_OPERATING_POINTS]; + guint8 refresh_frame_flags; + guint32 ref_order_hint[GST_AV1_NUM_REF_FRAMES]; + gboolean allow_intrabc; + gboolean frame_refs_short_signaling; + guint8 last_frame_idx; + guint8 gold_frame_idx; + guint8 ref_frame_idx[GST_AV1_REFS_PER_FRAME]; + gboolean allow_high_precision_mv; + gboolean is_motion_mode_switchable; + gboolean use_ref_frame_mvs; + gboolean disable_frame_end_update_cdf; + gboolean allow_warped_motion; + gboolean reduced_tx_set; + gboolean render_and_frame_size_different; + gboolean use_superres; + gboolean is_filter_switchable; + GstAV1InterpolationFilter interpolation_filter; + GstAV1LoopFilterParams loop_filter_params; + GstAV1QuantizationParams quantization_params; + GstAV1SegmenationParams segmentation_params; + GstAV1TileInfo tile_info; + GstAV1CDEFParams cdef_params; + GstAV1LoopRestorationParams loop_restoration_params; + gboolean tx_mode_select; + gboolean skip_mode_present; + gboolean reference_select; + GstAV1GlobalMotionParams global_motion_params; + GstAV1FilmGrainParams film_grain_params; + + /* Global vars set by frame header */ + guint32 superres_denom; /* SuperresDenom */ + guint8 frame_is_intra; /* FrameIsIntra */ + guint32 order_hints[GST_AV1_NUM_REF_FRAMES]; /* OrderHints */ + guint32 ref_frame_sign_bias[GST_AV1_NUM_REF_FRAMES]; /* RefFrameSignBias */ + + guint8 coded_lossless; /* CodedLossless */ + guint8 all_lossless; /* AllLossless */ + guint8 lossless_array[GST_AV1_MAX_SEGMENTS]; /* LosslessArray */ + guint8 seg_qm_Level[3][GST_AV1_MAX_SEGMENTS]; /* SegQMLevel */ + + guint32 upscaled_width; /* UpscaledWidth */ + guint32 frame_width; /* FrameWidth */ + guint32 frame_height; /* FrameHeight */ + guint32 render_width; /* RenderWidth */ + guint32 render_height; /* RenderHeight */ + + GstAV1TXModes tx_mode; /* TxMode */ + + guint8 skip_mode_frame[2]; /* SkipModeFrame */ +}; + +/** + * GstAV1ReferenceFrameInfo: + * + * All the info related to a reference frames. + */ +struct _GstAV1ReferenceFrameInfo { + struct { + gboolean ref_valid; /* RefValid */ + guint32 ref_frame_id; /* RefFrameId */ + guint32 ref_upscaled_width; /* RefUpscaledWidth */ + guint32 ref_frame_width; /* RefFrameWidth */ + guint32 ref_frame_height; /* RefFrameHeight */ + guint32 ref_render_width; /* RefRenderWidth */ + guint32 ref_render_height; /* RefRenderHeight */ + guint32 ref_mi_cols; /* RefMiCols */ + guint32 ref_mi_rows; /* RefMiRows */ + GstAV1FrameType ref_frame_type; /* RefFrameType */ + guint8 ref_subsampling_x; /* RefSubsamplingX */ + guint8 ref_subsampling_y; /* RefSubsamplingY */ + guint8 ref_bit_depth; /* RefBitDepth */ + guint32 ref_order_hint; /* RefOrderHint */ + GstAV1SegmenationParams ref_segmentation_params; + GstAV1GlobalMotionParams ref_global_motion_params; + GstAV1LoopFilterParams ref_lf_params; + GstAV1FilmGrainParams ref_film_grain_params; + GstAV1TileInfo ref_tile_info; + } entry[GST_AV1_NUM_REF_FRAMES]; +}; + +/** + * GstAV1TileListOBU: + * @output_frame_width_in_tiles_minus_1: plus one is the width of the output frame, in tile units. + * @output_frame_height_in_tiles_minus_1: plus one is the height of the output frame, in tile units. + * @tile_count_minus_1: plus one is the number of @tile_list_entry in the list. It is a requirement + * of bitstream conformance that @tile_count_minus_1 is less than or equal to 511. + * @anchor_frame_idx: is the index into an array AnchorFrames of the frames that the tile uses + * for prediction. The AnchorFrames array is provided by external means and may change for + * each tile list OBU. The process for creating the AnchorFrames array is outside of the + * scope of this specification. It is a requirement of bitstream conformance that + * @anchor_frame_idx is less than or equal to 127. + * @anchor_tile_row: the row coordinate of the tile in the frame that it belongs, in tile + * units. It is a requirement of bitstream conformance that @anchor_tile_row is less than @tile_rows. + * @anchor_tile_col: is the column coordinate of the tile in the frame that it belongs, in tile + * units. It is a requirement of bitstream conformance that @anchor_tile_col is less than @tile_cols. + * @tile_data_size_minus_1: plus one is the size of the coded tile data, @coded_tile_data, in bytes. + * @coded_tile_data: are the @tile_data_size_minus_1 + 1 bytes of the coded tile. + */ +struct _GstAV1TileListOBU { + guint8 output_frame_width_in_tiles_minus_1; + guint8 output_frame_height_in_tiles_minus_1; + guint16 tile_count_minus_1; + struct { + guint8 anchor_frame_idx; + guint8 anchor_tile_row; + guint8 anchor_tile_col; + guint16 tile_data_size_minus_1; + /* Just refer to obu's data, invalid after OBU data released */ + guint8 *coded_tile_data; + } entry[GST_AV1_MAX_TILE_COUNT]; +}; + +/** + * GstAV1TileListOBU: + * @tile_start_and_end_present_flag: specifies whether @tg_start and @tg_end are present + * in the bitstream. If @tg_start and @tg_end are not present in the bitstream, this + * tile group covers the entire frame. If @obu_type is equal to #GST_AV1_OBU_FRAME, it is a + * requirement of bitstream conformance that the value of @tile_start_and_end_present_flag + * is equal to 0. + * @tg_start: specifies the zero-based index of the first tile in the current tile group. + * It is a requirement of bitstream conformance that the value of @tg_start is equal to + * the value of TileNum at the point that tile_group_obu is invoked. + * @tg_end: specifies the zero-based index of the last tile in the current tile group. + * It is a requirement of bitstream conformance that the value of tg_end is greater + * than or equal to tg_start. It is a requirement of bitstream conformance that the + * value of tg_end for the last tile group in each frame is equal to num_tiles-1. + * @mi_row_start: start position in mi rows + * @mi_row_end: end position in mi rows + * @mi_col_start: start position in mi cols + * @mi_col_end: end position in mi cols + * @num_tiles: specifies the total number of tiles in the frame. + */ +struct _GstAV1TileGroupOBU { + gboolean tile_start_and_end_present_flag; + guint8 tg_start; + guint8 tg_end; + struct { + /* global varialbes */ + guint32 mi_row_start; /* MiRowStart */ + guint32 mi_row_end; /* MiRowEnd */ + guint32 mi_col_start; /* MiColStart */ + guint32 mi_col_end; /* MiColEnd */ + } entry[GST_AV1_MAX_TILE_COUNT]; + + guint32 num_tiles; /* NumTiles */ +}; + +/** + * GstAV1FrameOBU: + * @frame_header: a #GstAV1FrameHeaderOBU holding frame_header data. + * @tile_group: a #GstAV1TileGroupOBU holding tile_group data. + */ +struct _GstAV1FrameOBU { + GstAV1TileGroupOBU tile_group; + GstAV1FrameHeaderOBU frame_header; +}; + +/** + * GstAV1Parser: + * + * #GstAV1Parser opaque structure + * + * Instantiante it with gst_av1_parser_new() and destroy it with + * gst_av1_parser_free() + */ +struct _GstAV1Parser +{ + /*< private >*/ + struct + { + guint32 operating_point; /* Set by choose_operating_point() */ + guint8 seen_frame_header; /* SeenFrameHeader */ + guint32 operating_point_idc; /* OperatingPointIdc */ + gboolean sequence_changed; /* Received a new sequence */ + gboolean begin_first_frame; /* already find the first frame */ + + /* frame */ + guint32 upscaled_width; /* UpscaledWidth */ + guint32 frame_width; /* FrameWidth */ + guint32 frame_height; /* FrameHeight */ + guint32 mi_cols; /* MiCols */ + guint32 mi_rows; /* MiRows */ + guint32 render_width; /* RenderWidth */ + guint32 render_height; /* RenderHeight */ + guint32 prev_frame_id; /* PrevFrameID */ + guint32 current_frame_id; /* the current frame ID */ + GstAV1ReferenceFrameInfo ref_info; /* RefInfo */ + + guint32 mi_col_starts[GST_AV1_MAX_TILE_COLS + 1]; /* MiColStarts */ + guint32 mi_row_starts[GST_AV1_MAX_TILE_ROWS + 1]; /* MiRowStarts */ + guint8 tile_cols_log2; /* TileColsLog2 */ + guint8 tile_cols; /* TileCols */ + guint8 tile_rows_log2; /* TileRowsLog2 */ + guint8 tile_rows; /* TileRows */ + guint8 tile_size_bytes; /* TileSizeBytes */ + } state; + + gboolean annex_b; + guint32 temporal_unit_size; + /* consumed of this temporal unit */ + guint32 temporal_unit_consumed; + guint32 frame_unit_size; + /* consumed of this frame unit */ + guint32 frame_unit_consumed; + + GstAV1SequenceHeaderOBU *seq_header; +}; + +GST_CODEC_PARSERS_API +void +gst_av1_parser_reset (GstAV1Parser * parser, gboolean annex_b); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_identify_one_obu (GstAV1Parser * parser, const guint8 * data, + guint32 size, GstAV1OBU * obu, guint32 * consumed); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_sequence_header_obu (GstAV1Parser * parser, + GstAV1OBU * obu, GstAV1SequenceHeaderOBU * seq_header); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_temporal_delimiter_obu (GstAV1Parser * parser, + GstAV1OBU * obu); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_metadata_obu (GstAV1Parser * parser, GstAV1OBU * obu, + GstAV1MetadataOBU * metadata); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_tile_list_obu (GstAV1Parser * parser, GstAV1OBU * obu, + GstAV1TileListOBU * tile_list); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_tile_group_obu (GstAV1Parser * parser, GstAV1OBU * obu, + GstAV1TileGroupOBU * tile_group); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_frame_header_obu (GstAV1Parser * parser, GstAV1OBU * obu, + GstAV1FrameHeaderOBU * frame_header); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_parse_frame_obu (GstAV1Parser * parser, GstAV1OBU * obu, + GstAV1FrameOBU * frame); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_reference_frame_loading (GstAV1Parser * parser, + GstAV1FrameHeaderOBU * frame_header); + +GST_CODEC_PARSERS_API +GstAV1ParserResult +gst_av1_parser_reference_frame_update (GstAV1Parser * parser, + GstAV1FrameHeaderOBU * frame_header); + +GST_CODEC_PARSERS_API +GstAV1Parser * gst_av1_parser_new (void); + +GST_CODEC_PARSERS_API +void gst_av1_parser_free (GstAV1Parser * parser); + +G_END_DECLS + +#endif /* __GST_AV1_PARSER_H__ */ diff --git a/gst-libs/gst/codecparsers/meson.build b/gst-libs/gst/codecparsers/meson.build index 777b02db26..7b76f40010 100644 --- a/gst-libs/gst/codecparsers/meson.build +++ b/gst-libs/gst/codecparsers/meson.build @@ -15,6 +15,7 @@ codecparser_sources = files([ 'dboolhuff.c', 'vp8utils.c', 'gstmpegvideometa.c', + 'gstav1parser.c' ]) codecparser_headers = [ 'codecparsers-prelude.h', @@ -29,6 +30,7 @@ codecparser_headers = [ 'gstjpegparser.h', 'gstmpegvideometa.h', 'gstvp9parser.h', + 'gstav1parser.h' ] install_headers(codecparser_headers, subdir : 'gstreamer-1.0/gst/codecparsers') diff --git a/tests/check/libs/av1parser.c b/tests/check/libs/av1parser.c new file mode 100644 index 0000000000..c539bca2f8 --- /dev/null +++ b/tests/check/libs/av1parser.c @@ -0,0 +1,587 @@ +/* Gstreamer + * Copyright (C) 2018 Georg Ottinger + * Author: Georg Ottinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library 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. + */ + +#include +#include + +static const guint8 aom_testdata_av1_1_b8_01_size_16x16[] = { + 0x12, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x9f, 0xfb, 0xff, 0xf3, + 0x00, 0x80, 0x32, 0xa6, 0x01, 0x10, 0x00, 0x87, 0x80, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x9e, 0x86, 0x5b, 0xb2, 0x22, 0xb5, 0x58, 0x4d, + 0x68, 0xe6, 0x37, 0x54, 0x42, 0x7b, 0x84, 0xce, 0xdf, 0x9f, 0xec, 0xab, + 0x07, 0x4d, 0xf6, 0xe1, 0x5e, 0x9e, 0x27, 0xbf, 0x93, 0x2f, 0x47, 0x0d, + 0x7b, 0x7c, 0x45, 0x8d, 0xcf, 0x26, 0xf7, 0x6c, 0x06, 0xd7, 0x8c, 0x2e, + 0xf5, 0x2c, 0xb0, 0x8a, 0x31, 0xac, 0x69, 0xf5, 0xcd, 0xd8, 0x71, 0x5d, + 0xaf, 0xf8, 0x96, 0x43, 0x8c, 0x9c, 0x23, 0x6f, 0xab, 0xd0, 0x35, 0x43, + 0xdf, 0x81, 0x12, 0xe3, 0x7d, 0xec, 0x22, 0xb0, 0x30, 0x54, 0x32, 0x9f, + 0x90, 0xc0, 0x5d, 0x64, 0x9b, 0x0f, 0x75, 0x31, 0x84, 0x3a, 0x57, 0xd7, + 0x5f, 0x03, 0x6e, 0x7f, 0x43, 0x17, 0x6d, 0x08, 0xc3, 0x81, 0x8a, 0xae, + 0x73, 0x1c, 0xa8, 0xa7, 0xe4, 0x9c, 0xa9, 0x5b, 0x3f, 0xd1, 0xeb, 0x75, + 0x3a, 0x7f, 0x22, 0x77, 0x38, 0x64, 0x1c, 0x77, 0xdb, 0xcd, 0xef, 0xb7, + 0x08, 0x45, 0x8e, 0x7f, 0xea, 0xa3, 0xd0, 0x81, 0xc9, 0xc1, 0xbc, 0x93, + 0x9b, 0x41, 0xb1, 0xa1, 0x42, 0x17, 0x98, 0x3f, 0x1e, 0x95, 0xdf, 0x68, + 0x7c, 0xb7, 0x98, 0x12, 0x00, 0x32, 0x4b, 0x30, 0x03, 0xc3, 0x00, 0xa7, + 0x2e, 0x46, 0x8a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x50, 0xc0, 0x20, 0x00, + 0xf0, 0xb1, 0x2f, 0x43, 0xf3, 0xbb, 0xe6, 0x5c, 0xbe, 0xe6, 0x53, 0xbc, + 0xaa, 0x61, 0x7c, 0x7e, 0x0a, 0x04, 0x1b, 0xa2, 0x87, 0x81, 0xe8, 0xa6, + 0x85, 0xfe, 0xc2, 0x71, 0xb9, 0xf8, 0xc0, 0x78, 0x9f, 0x52, 0x4f, 0xa7, + 0x8f, 0x55, 0x96, 0x79, 0x90, 0xaa, 0x2b, 0x6d, 0x0a, 0xa7, 0x05, 0x2a, + 0xf8, 0xfc, 0xc9, 0x7d, 0x9d, 0x4a, 0x61, 0x16, 0xb1, 0x65 +}; + +/* testdata taken from aom testdata deecoded and reencoded with annexb */ +static const guint8 aom_testdata_av1_1_b8_01_size_16x16_reencoded_annexb[] = { + 0x8b, 0x02, 0x89, 0x02, 0x01, 0x10, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x01, + 0x9f, 0xfb, 0xff, 0xf3, 0x00, 0x80, 0xf9, 0x01, 0x30, 0x10, 0x01, 0x80, + 0x00, 0xef, 0x38, 0x58, 0x9e, 0x27, 0x8c, 0x26, 0xc4, 0x61, 0x19, 0x41, + 0xff, 0x4f, 0x8c, 0xc9, 0x24, 0x93, 0x38, 0x20, 0x61, 0x7a, 0xc9, 0x5c, + 0xb8, 0xa7, 0xf2, 0x90, 0x41, 0x9e, 0xac, 0x22, 0x39, 0x4c, 0xd5, 0xf9, + 0x9e, 0xa9, 0xb1, 0x84, 0x43, 0x76, 0xd1, 0x7f, 0x96, 0x7d, 0xff, 0x66, + 0x7e, 0x39, 0x61, 0xe4, 0xce, 0x20, 0x39, 0xf6, 0xb5, 0xc7, 0xe2, 0x32, + 0xc0, 0x5e, 0xa4, 0x0a, 0x9e, 0x6b, 0xc4, 0x1d, 0x50, 0x04, 0xc9, 0x93, + 0x9c, 0x4c, 0xbb, 0x26, 0xd7, 0xe4, 0x1b, 0xcb, 0xa7, 0x20, 0x08, 0xd4, + 0xeb, 0x7e, 0x50, 0x83, 0x48, 0x71, 0x50, 0x01, 0xd1, 0x6c, 0xe7, 0xc1, + 0x00, 0x21, 0x5e, 0x96, 0xc6, 0x2a, 0x25, 0x81, 0xa7, 0x7e, 0x59, 0x70, + 0x34, 0x12, 0x84, 0xc0, 0xb8, 0xdc, 0xcf, 0xa1, 0xaf, 0xb2, 0x62, 0x64, + 0x2e, 0x7b, 0x03, 0x31, 0x9d, 0x43, 0xba, 0xd2, 0xb5, 0x4c, 0xab, 0xf0, + 0x20, 0x45, 0xdf, 0xf9, 0xcb, 0xdb, 0xe3, 0xe0, 0x73, 0xef, 0x4d, 0x1d, + 0xd7, 0xeb, 0xd9, 0x1f, 0xba, 0x33, 0xd8, 0x98, 0xe7, 0xe4, 0x72, 0x2f, + 0x19, 0x7c, 0x0d, 0xc8, 0x6c, 0x30, 0xa5, 0xbb, 0xb5, 0xb5, 0x8c, 0x69, + 0x52, 0xd4, 0xe5, 0x95, 0x15, 0xd7, 0xe6, 0x74, 0x8b, 0xe4, 0x8f, 0x38, + 0x52, 0xbc, 0x52, 0xcc, 0x97, 0x4e, 0x77, 0xf8, 0xab, 0xcc, 0x40, 0x3a, + 0x0c, 0x73, 0x56, 0x86, 0x66, 0x5b, 0xc2, 0xa9, 0x90, 0xea, 0xc7, 0xf4, + 0x1e, 0xd3, 0x35, 0x79, 0xd6, 0x7e, 0xc9, 0xd0, 0x83, 0x44, 0x8f, 0x5f, + 0xef, 0x3e, 0x0c, 0x38, 0xfe, 0xff, 0x17, 0x28, 0xff, 0x98, 0xf8, 0x6b, + 0xf2, 0x31, 0xc6, 0x58, 0x9a, 0x4c, 0xc2, 0x6c, 0x4e, 0xa7, 0xf2, 0xeb, + 0x9f, 0xfb, 0xd7, 0xdc, 0x30, 0xfb, 0x01, 0xf9, 0x01, 0x01, 0x10, 0xf5, + 0x01, 0x30, 0x30, 0x03, 0xc3, 0x00, 0xa7, 0x2e, 0x47, 0x80, 0x01, 0x00, + 0xc1, 0xc9, 0x8b, 0x3d, 0xd7, 0x44, 0x93, 0x49, 0xf8, 0xad, 0x73, 0x89, + 0x29, 0x50, 0x60, 0x35, 0x87, 0x2d, 0xbe, 0xde, 0x00, 0x4e, 0xa2, 0x75, + 0x62, 0xd7, 0xda, 0x28, 0xc4, 0xec, 0x65, 0xed, 0xcd, 0xbd, 0xa3, 0xd1, + 0x71, 0x8d, 0x49, 0x4e, 0xa1, 0xcd, 0xf1, 0xd0, 0x20, 0xb6, 0xd2, 0xda, + 0xe3, 0xc5, 0xab, 0xd6, 0xff, 0xb0, 0xd0, 0xff, 0x1f, 0x86, 0x79, 0x2e, + 0x69, 0x89, 0xce, 0x07, 0x72, 0x4f, 0xe8, 0xff, 0x22, 0xca, 0x08, 0x32, + 0x29, 0xdb, 0xb5, 0xfb, 0x75, 0x52, 0x6e, 0xf3, 0x32, 0x3c, 0x55, 0x9f, + 0x97, 0x9e, 0x1e, 0x1a, 0x51, 0x1d, 0xf4, 0x15, 0x16, 0xa0, 0xea, 0xec, + 0x64, 0xd3, 0xff, 0xd9, 0x7a, 0xb7, 0x91, 0x10, 0x4b, 0xfd, 0x7a, 0x49, + 0x62, 0xae, 0x46, 0xa8, 0x4b, 0x53, 0x15, 0xba, 0x27, 0x6d, 0x5b, 0x72, + 0x5f, 0x7e, 0x63, 0xc6, 0x70, 0x79, 0x84, 0xe4, 0x2e, 0x3e, 0xfd, 0xdf, + 0xeb, 0xf1, 0x2a, 0xe5, 0xc7, 0x68, 0x8e, 0x65, 0xfe, 0x0d, 0x1e, 0xea, + 0xce, 0x0f, 0x83, 0x47, 0xfc, 0x11, 0x18, 0x0f, 0x2d, 0x29, 0x8e, 0xff, + 0xbc, 0x5e, 0x7b, 0x45, 0x2e, 0x51, 0xd1, 0xa8, 0xdb, 0xd7, 0xbe, 0x1a, + 0xf2, 0x59, 0xa3, 0x0b, 0x96, 0x5a, 0xc1, 0x81, 0x0e, 0xc9, 0xe9, 0x3d, + 0x1c, 0x75, 0x41, 0xbe, 0x46, 0xba, 0xb1, 0x55, 0x95, 0xe1, 0x1a, 0x89, + 0xce, 0x4f, 0xf4, 0x78, 0x9b, 0x71, 0x49, 0xe8, 0xf7, 0x58, 0x5b, 0xca, + 0xde, 0xc3, 0x8f, 0x41, 0x80, 0xdd, 0xcc, 0xf8, 0xb6, 0x50, 0x24, 0x0d, + 0x53, 0xa1, 0xcf, 0x5a, 0xc8, 0xc4, 0x81, 0x83, 0x2c, 0x2f, 0xfc, 0x37, + 0x82, 0x67, 0xb6, 0x8a, 0xdc, 0xe0 +}; + +/* hand crafted test case for metadata */ +static const guint8 metadata_obu[] = { + 0x2a, 0x05, 0x01, 0x12, 0x34, 0x56, 0x78 +}; + +/* hand crafted test case for tile list */ +static const guint8 tile_list_obu[] = { + 0x42, 0x0a, 0x01, 0x01, 0x00, 0x01, 0x11, 0x22, 0x33, 0x00, 0x01, 0xa5 +}; + +GST_START_TEST (test_av1_parse_aom_testdata_av1_1_b8_01_size_16x16) +{ + GstAV1Parser *parser; + GstAV1SequenceHeaderOBU seq_header; + GstAV1FrameOBU frame; + GstAV1OBU obu; + GstAV1ParserResult ret; + guint32 consumed = 0; + const guint8 *data_ptr = aom_testdata_av1_1_b8_01_size_16x16; + guint data_sz = sizeof (aom_testdata_av1_1_b8_01_size_16x16); + + parser = gst_av1_parser_new (); + gst_av1_parser_reset (parser, FALSE); + ret = gst_av1_parser_identify_one_obu (parser, data_ptr, data_sz, + &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data_ptr += consumed; + data_sz -= consumed; + + /* 1st OBU should be OBU_TEMPORAL_DELIMITER */ + assert_equals_int (obu.obu_type, GST_AV1_OBU_TEMPORAL_DELIMITER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 0); + ret = gst_av1_parser_parse_temporal_delimiter_obu (parser, &obu); + assert_equals_int (ret, GST_AV1_PARSER_OK); + + /* 2nd OBU should be OBU_SEQUENCE_HEADER */ + ret = gst_av1_parser_identify_one_obu (parser, data_ptr, data_sz, + &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data_ptr += consumed; + data_sz -= consumed; + + assert_equals_int (obu.obu_type, GST_AV1_OBU_SEQUENCE_HEADER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 10); + + ret = gst_av1_parser_parse_sequence_header_obu (parser, &obu, &seq_header); + assert_equals_int (ret, GST_AV1_PARSER_OK); + + assert_equals_int (seq_header.seq_profile, GST_AV1_PROFILE_0); + assert_equals_int (seq_header.still_picture, 0); + assert_equals_int (seq_header.reduced_still_picture_header, 0); + assert_equals_int (seq_header.timing_info_present_flag, 0); + assert_equals_int (seq_header.initial_display_delay_present_flag, 0); + assert_equals_int (seq_header.operating_points_cnt_minus_1, 0); + assert_equals_int (seq_header.operating_points[0].idc, 0); + assert_equals_int (seq_header.operating_points[0].seq_level_idx, 0); + assert_equals_int (seq_header.frame_width_bits_minus_1, 3); + assert_equals_int (seq_header.frame_height_bits_minus_1, 3); + assert_equals_int (seq_header.max_frame_width_minus_1, 15); + assert_equals_int (seq_header.max_frame_height_minus_1, 15); + assert_equals_int (seq_header.frame_id_numbers_present_flag, 0); + assert_equals_int (seq_header.use_128x128_superblock, 1); + assert_equals_int (seq_header.enable_filter_intra, 1); + assert_equals_int (seq_header.enable_intra_edge_filter, 1); + assert_equals_int (seq_header.enable_interintra_compound, 1); + assert_equals_int (seq_header.enable_masked_compound, 1); + assert_equals_int (seq_header.enable_warped_motion, 1); + assert_equals_int (seq_header.enable_dual_filter, 1); + assert_equals_int (seq_header.enable_order_hint, 1); + assert_equals_int (seq_header.enable_jnt_comp, 1); + assert_equals_int (seq_header.enable_ref_frame_mvs, 1); + assert_equals_int (seq_header.seq_choose_screen_content_tools, 1); + assert_equals_int (seq_header.seq_choose_integer_mv, 1); + assert_equals_int (seq_header.order_hint_bits_minus_1, 6); + assert_equals_int (seq_header.enable_superres, 0); + assert_equals_int (seq_header.enable_cdef, 1); + assert_equals_int (seq_header.enable_restoration, 1); + assert_equals_int (seq_header.color_config.high_bitdepth, 0); + assert_equals_int (seq_header.color_config.mono_chrome, 0); + assert_equals_int (seq_header.color_config.color_description_present_flag, 0); + assert_equals_int (seq_header.color_config.chroma_sample_position, + GST_AV1_CSP_UNKNOWN); + assert_equals_int (seq_header.color_config.separate_uv_delta_q, 0); + assert_equals_int (seq_header.film_grain_params_present, 0); + + /* 3rd OBU should be GST_AV1_OBU_FRAME */ + ret = gst_av1_parser_identify_one_obu (parser, data_ptr, data_sz, + &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data_ptr += consumed; + data_sz -= consumed; + + assert_equals_int (obu.obu_type, GST_AV1_OBU_FRAME); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 166); + + ret = gst_av1_parser_parse_frame_obu (parser, &obu, &frame); + assert_equals_int (ret, GST_AV1_PARSER_OK); + + assert_equals_int (frame.frame_header.show_existing_frame, 0); + assert_equals_int (frame.frame_header.frame_type, GST_AV1_KEY_FRAME); + assert_equals_int (frame.frame_header.show_frame, 1); + assert_equals_int (frame.frame_header.disable_cdf_update, 0); + assert_equals_int (frame.frame_header.allow_screen_content_tools, 0); + assert_equals_int (frame.frame_header.frame_size_override_flag, 0); + assert_equals_int (frame.frame_header.order_hint, 0); + assert_equals_int (frame.frame_header.render_and_frame_size_different, 0); + assert_equals_int (frame.frame_header.disable_frame_end_update_cdf, 0); + assert_equals_int (frame.frame_header.tile_info.uniform_tile_spacing_flag, 1); + assert_equals_int (frame.frame_header.quantization_params.base_q_idx, 15); + assert_equals_int (frame.frame_header.quantization_params.delta_q_y_dc, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_u_dc, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_u_ac, 0); + assert_equals_int (frame.frame_header.quantization_params.using_qmatrix, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_present, 0); + assert_equals_int (frame.frame_header.loop_filter_params.loop_filter_level[0], + 0); + assert_equals_int (frame.frame_header.loop_filter_params.loop_filter_level[1], + 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_sharpness, 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_delta_enabled, 1); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_delta_update, 1); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[0], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[1], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[2], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[3], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[4], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[5], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[6], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[7], 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_mode_deltas[0], 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_mode_deltas[1], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_damping, 3); + assert_equals_int (frame.frame_header.cdef_params.cdef_bits, 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_y_pri_strength[0], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_y_sec_strength[0], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_uv_pri_strength[0], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_uv_sec_strength[0], 1); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[0], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[1], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[2], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.tx_mode_select, 0); + assert_equals_int (frame.frame_header.reduced_tx_set, 0); + + /* 4th OBU should be OBU_TEMPORAL_DELIMITER */ + ret = gst_av1_parser_identify_one_obu (parser, data_ptr, data_sz, + &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data_ptr += consumed; + data_sz -= consumed; + + assert_equals_int (obu.obu_type, GST_AV1_OBU_TEMPORAL_DELIMITER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 0); + + ret = gst_av1_parser_parse_temporal_delimiter_obu (parser, &obu); + assert_equals_int (ret, GST_AV1_PARSER_OK); + + /* 5th OBU should be GST_AV1_OBU_FRAME */ + ret = gst_av1_parser_identify_one_obu (parser, data_ptr, data_sz, + &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data_ptr += consumed; + data_sz -= consumed; + + assert_equals_int (obu.obu_type, GST_AV1_OBU_FRAME); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 75); + + ret = gst_av1_parser_parse_frame_obu (parser, &obu, &frame); + assert_equals_int (ret, GST_AV1_PARSER_OK); + + assert_equals_int (frame.frame_header.show_existing_frame, 0); + assert_equals_int (frame.frame_header.frame_type, GST_AV1_INTER_FRAME); + assert_equals_int (frame.frame_header.show_frame, 1); + assert_equals_int (frame.frame_header.error_resilient_mode, 0); + assert_equals_int (frame.frame_header.disable_cdf_update, 0); + assert_equals_int (frame.frame_header.allow_screen_content_tools, 0); + assert_equals_int (frame.frame_header.frame_size_override_flag, 0); + assert_equals_int (frame.frame_header.order_hint, 1); + assert_equals_int (frame.frame_header.primary_ref_frame, 7); + assert_equals_int (frame.frame_header.refresh_frame_flags, 12); + assert_equals_int (frame.frame_header.frame_refs_short_signaling, 0); + assert_equals_int (frame.frame_header.ref_frame_idx[0], 0); + assert_equals_int (frame.frame_header.ref_frame_idx[1], 1); + assert_equals_int (frame.frame_header.ref_frame_idx[2], 2); + assert_equals_int (frame.frame_header.ref_frame_idx[3], 3); + assert_equals_int (frame.frame_header.ref_frame_idx[4], 4); + assert_equals_int (frame.frame_header.ref_frame_idx[5], 5); + assert_equals_int (frame.frame_header.ref_frame_idx[6], 6); + assert_equals_int (frame.frame_header.allow_high_precision_mv, 1); + assert_equals_int (frame.frame_header.is_filter_switchable, 0); + assert_equals_int (frame.frame_header.interpolation_filter, + GST_AV1_INTERPOLATION_FILTER_EIGHTTAP); + assert_equals_int (frame.frame_header.is_motion_mode_switchable, 1); + assert_equals_int (frame.frame_header.use_ref_frame_mvs, 1); + assert_equals_int (frame.frame_header.disable_frame_end_update_cdf, 0); + assert_equals_int (frame.frame_header.quantization_params.base_q_idx, 20); + assert_equals_int (frame.frame_header.quantization_params.delta_q_y_dc, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_u_dc, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_u_ac, 0); + assert_equals_int (frame.frame_header.quantization_params.using_qmatrix, 0); + assert_equals_int (frame.frame_header.segmentation_params. + segmentation_enabled, 0); + assert_equals_int (frame.frame_header.quantization_params.delta_q_present, 0); + assert_equals_int (frame.frame_header.loop_filter_params.loop_filter_level[0], + 0); + assert_equals_int (frame.frame_header.loop_filter_params.loop_filter_level[1], + 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_sharpness, 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_delta_enabled, 1); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_delta_update, 1); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[0], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[1], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[2], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[3], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[4], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[5], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[6], 0); + assert_equals_int (frame.frame_header. + loop_filter_params.loop_filter_ref_deltas[7], 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_mode_deltas[0], 0); + assert_equals_int (frame.frame_header.loop_filter_params. + loop_filter_mode_deltas[1], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_damping, 3); + assert_equals_int (frame.frame_header.cdef_params.cdef_bits, 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_y_pri_strength[0], 1); + assert_equals_int (frame.frame_header.cdef_params.cdef_y_sec_strength[0], 1); + assert_equals_int (frame.frame_header.cdef_params.cdef_uv_pri_strength[0], 0); + assert_equals_int (frame.frame_header.cdef_params.cdef_uv_sec_strength[0], 4); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[0], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[1], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.loop_restoration_params. + frame_restoration_type[2], GST_AV1_FRAME_RESTORE_NONE); + assert_equals_int (frame.frame_header.tx_mode_select, 0); + assert_equals_int (frame.frame_header.reference_select, 0); + assert_equals_int (frame.frame_header.allow_warped_motion, 1); + assert_equals_int (frame.frame_header.reduced_tx_set, 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[1], 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[2], 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[3], 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[4], 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[5], 0); + assert_equals_int (frame.frame_header.global_motion_params.is_global[6], 0); + + gst_av1_parser_free (parser); +} + +GST_END_TEST; + +GST_START_TEST + (test_av1_parse_aom_testdata_av1_1_b8_01_size_16x16_reencoded_annexb) { + GstAV1Parser *parser; + GstAV1OBU obu; + GstAV1SequenceHeaderOBU seq_header; + GstAV1FrameOBU frame; + gsize size; + guint32 consumed = 0; + const guint8 *data; + GstAV1ParserResult ret; + + parser = gst_av1_parser_new (); + + data = aom_testdata_av1_1_b8_01_size_16x16_reencoded_annexb; + size = sizeof (aom_testdata_av1_1_b8_01_size_16x16_reencoded_annexb); + + gst_av1_parser_reset (parser, TRUE); + + /* 1st OBU should be OBU_TEMPORAL_DELIMITER */ + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_TEMPORAL_DELIMITER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 0); + assert_equals_int (obu.obu_size, 0); + + gst_av1_parser_parse_temporal_delimiter_obu (parser, &obu); + + /* 2nd OBU should be OBU_SEQUENCE_HEADER */ + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_SEQUENCE_HEADER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 0); + assert_equals_int (obu.obu_size, 10); + + gst_av1_parser_parse_sequence_header_obu (parser, &obu, &seq_header); + assert_equals_int (seq_header.seq_profile, GST_AV1_PROFILE_0); + assert_equals_int (seq_header.frame_width_bits_minus_1, 3); + assert_equals_int (seq_header.frame_height_bits_minus_1, 3); + assert_equals_int (seq_header.max_frame_width_minus_1, 15); + assert_equals_int (seq_header.max_frame_height_minus_1, 15); + + /* 3rd OBU should be GST_AV1_OBU_FRAME */ + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_FRAME); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 0); + assert_equals_int (obu.obu_size, 248); + + gst_av1_parser_parse_frame_obu (parser, &obu, &frame); + assert_equals_int (frame.frame_header.show_existing_frame, 0); + assert_equals_int (frame.frame_header.frame_type, GST_AV1_KEY_FRAME); + assert_equals_int (frame.frame_header.show_frame, 1); + assert_equals_int (frame.frame_header.quantization_params.base_q_idx, 0); + + assert_equals_int (frame.tile_group.num_tiles, 1); + + /* 4th OBU should be OBU_TEMPORAL_DELIMITER */ + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_TEMPORAL_DELIMITER); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 0); + assert_equals_int (obu.obu_size, 0); + + gst_av1_parser_parse_temporal_delimiter_obu (parser, &obu); + + /* 5th OBU should be GST_AV1_OBU_FRAME */ + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_FRAME); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 0); + assert_equals_int (obu.obu_size, 244); + + gst_av1_parser_parse_frame_obu (parser, &obu, &frame); + assert_equals_int (frame.frame_header.show_existing_frame, 0); + assert_equals_int (frame.frame_header.frame_type, GST_AV1_INTER_FRAME); + assert_equals_int (frame.frame_header.show_frame, 1); + assert_equals_int (frame.frame_header.quantization_params.base_q_idx, 0); + + assert_equals_int (frame.tile_group.num_tiles, 1); + + gst_av1_parser_free (parser); +} + +GST_END_TEST; + +GST_START_TEST (test_metadata_obu) +{ + GstAV1Parser *parser; + GstAV1OBU obu; + GstAV1MetadataOBU metadata; + guint32 consumed = 0; + gsize size; + const guint8 *data; + GstAV1ParserResult ret; + + parser = gst_av1_parser_new (); + + data = metadata_obu; + size = sizeof (metadata_obu); + + gst_av1_parser_reset (parser, FALSE); + + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_METADATA); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 5); + + gst_av1_parser_parse_metadata_obu (parser, &obu, &metadata); + + assert_equals_int (metadata.metadata_type, GST_AV1_METADATA_TYPE_HDR_CLL); + assert_equals_int (metadata.hdr_cll.max_cll, 0x1234); + assert_equals_int (metadata.hdr_cll.max_fall, 0x5678); + + gst_av1_parser_free (parser); +} + +GST_END_TEST; + +GST_START_TEST (test_tile_list_obu) +{ + GstAV1Parser *parser; + GstAV1OBU obu; + GstAV1TileListOBU tile_list; + guint32 consumed = 0; + gsize size; + const guint8 *data; + GstAV1ParserResult ret; + + parser = gst_av1_parser_new (); + + data = tile_list_obu; + size = sizeof (tile_list_obu); + + gst_av1_parser_reset (parser, FALSE); + + ret = gst_av1_parser_identify_one_obu (parser, data, size, &obu, &consumed); + assert_equals_int (ret, GST_AV1_PARSER_OK); + data += consumed; + size -= consumed; + + assert_equals_int (obu.header.obu_type, GST_AV1_OBU_TILE_LIST); + assert_equals_int (obu.header.obu_extention_flag, 0); + assert_equals_int (obu.header.obu_has_size_field, 1); + assert_equals_int (obu.obu_size, 10); + + gst_av1_parser_parse_tile_list_obu (parser, &obu, &tile_list); + + assert_equals_int (tile_list.output_frame_width_in_tiles_minus_1, 1); + assert_equals_int (tile_list.output_frame_height_in_tiles_minus_1, 1); + assert_equals_int (tile_list.tile_count_minus_1, 1); + + assert_equals_int (tile_list.entry[0].anchor_frame_idx, 0x11); + assert_equals_int (tile_list.entry[0].anchor_tile_row, 0x22); + assert_equals_int (tile_list.entry[0].anchor_tile_col, 0x33); + assert_equals_int (tile_list.entry[0].tile_data_size_minus_1, 0x01); + assert_equals_int (tile_list.entry[0].coded_tile_data[0], 0xa5); + + gst_av1_parser_free (parser); +} + +GST_END_TEST; + +static Suite * +av1parsers_suite (void) +{ + Suite *s = suite_create ("AV1 Parser library"); + + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_av1_parse_aom_testdata_av1_1_b8_01_size_16x16); + tcase_add_test (tc_chain, + test_av1_parse_aom_testdata_av1_1_b8_01_size_16x16_reencoded_annexb); + tcase_add_test (tc_chain, test_metadata_obu); + tcase_add_test (tc_chain, test_tile_list_obu); + + return s; +} + +GST_CHECK_MAIN (av1parsers); diff --git a/tests/check/meson.build b/tests/check/meson.build index 0a222a0c06..5869ca459d 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -66,6 +66,7 @@ base_tests = [ [['libs/vc1parser.c'], false, [gstcodecparsers_dep]], [['libs/vp8parser.c'], false, [gstcodecparsers_dep]], [['libs/vp9parser.c'], false, [gstcodecparsers_dep]], + [['libs/av1parser.c'], false, [gstcodecparsers_dep]], [['libs/vkmemory.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['elements/vkcolorconvert.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['libs/vkwindow.c'], not gstvulkan_dep.found(), [gstvulkan_dep]],