From fc0c5ddf0d509b914ac0e63c32d54d4aba0ed825 Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Mon, 27 Aug 2018 17:54:42 -0700 Subject: [PATCH] Implemented AV1 bitstream parser Implemented according to bitstream spec at https://aomediacodec.github.io/av1-spec/. It will be used to do AV1 subsample encryption later. Issue #453. Change-Id: I84d8a2a780d95f2c9f430ee598838b97474cc0af --- packager/media/codecs/av1_parser.cc | 1856 ++++++++++++++++++ packager/media/codecs/av1_parser.h | 273 +++ packager/media/codecs/av1_parser_unittest.cc | 24 + packager/media/codecs/codecs.gyp | 3 + packager/media/test/data/av1-I-frame-320x240 | Bin 0 -> 1278 bytes 5 files changed, 2156 insertions(+) create mode 100644 packager/media/codecs/av1_parser.cc create mode 100644 packager/media/codecs/av1_parser.h create mode 100644 packager/media/codecs/av1_parser_unittest.cc create mode 100644 packager/media/test/data/av1-I-frame-320x240 diff --git a/packager/media/codecs/av1_parser.cc b/packager/media/codecs/av1_parser.cc new file mode 100644 index 00000000000..c7cb7a2f82f --- /dev/null +++ b/packager/media/codecs/av1_parser.cc @@ -0,0 +1,1856 @@ +// Copyright 2018 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/codecs/av1_parser.h" + +#include + +#include "packager/base/logging.h" +#include "packager/media/base/bit_reader.h" +#include "packager/media/base/rcheck.h" + +namespace shaka { +namespace media { +namespace { + +// 3. Symbols and abbreviated terms. +enum MotionType { + IDENTITY = 0, + TRANSLATION, + ROTZOOM, + AFFINE, +}; + +const int kSelectScreenContentTools = 2; +const int kSelectIntegerMv = 2; +const int kPrimaryRefNone = 7; +const int kNumRefFrames = 8; +const int kAllFrames = (1 << kNumRefFrames) - 1; + +// 6.2.2. OBU header semantics. +enum ObuType { + OBU_SEQUENCE_HEADER = 1, + OBU_TEMPORAL_DELIMITER, + OBU_FRAME_HEADER, + OBU_TILE_GROUP, + OBU_METADATA, + OBU_FRAME, + OBU_REDUNDENT_FRAME_HEADER, + OBU_TILE_LIST, + // Reserved types between OBU_TILE_LIST and OBU_PADDING. + OBU_PADDING = 15, +}; + +// 6.4.2. Color config semantics. +enum ColorPrimaries { + CP_BT_709 = 1, + CP_UNSPECIFIED = 2, + // We are not interested in the others. +}; +enum TransferCharacteristics { + TC_UNSPECIFIED = 2, + TC_SRGB = 13, + // We are not interested in the others. +}; +enum MatrixCoefficients { + MC_IDENTITY = 0, + MC_UNSPECIFIED = 2, + // We are not interested in the others. +}; +enum ChromaSamplePosition { + CSP_UNKNOWN = 0, + CSP_VERTICAL, + CSP_COLOCATED, + CSP_RESERVED, +}; + +// 6.8.2. Uncompressed header semantics. +enum FrameType { + KEY_FRAME = 0, + INTER_FRAME, + INTRA_ONLY_FRAME, + SWITCH_FRAME, +}; + +// 6.10.24. Ref frames semantics. +enum RefFrameName { + INTRA_FRAME = 0, + LAST_FRAME, + LAST2_FRAME, + LAST3_FRAME, + GOLDEN_FRAME, + BWDREF_FRAME, + ALTREF2_FRAME, + ALTREF_FRAME, +}; + +// 4.7. Mathematical functions. +int Clip3(int min_value, int max_value, int value) { + if (value < min_value) + return min_value; + if (value > max_value) + return max_value; + return value; +} + +// 4.7. Mathematical functions. The FloorLog2(x) function is defined to be the +// floor of the base 2 logarithm of the input x. +int FloorLog2(int x) { + int s = 0; + while (x != 0) { + x = x >> 1; + s++; + } + return s - 1; +} + +// 4.10.3. uvlc(). This is a modified form of Exponential-Golomb coding. +bool ReadUvlc(BitReader* reader, uint32_t* val) { + // Count the number of contiguous zero bits. + int leading_zeros = 0; + while (true) { + bool done = false; + RCHECK(reader->ReadBits(1, &done)); + if (done) + break; + leading_zeros++; + } + + if (leading_zeros >= 32) { + *val = (1ull << 32) - 1; + return true; + } + + int value = 0; + if (leading_zeros > 0) + RCHECK(reader->ReadBits(leading_zeros, &value)); + + *val = value + (1 << leading_zeros) - 1; + return true; +} + +// 4.10.4. le(n). Unsigned little-endian n-byte number appearing directly in the +// bitstream. +bool ReadLe(int n, BitReader* reader, size_t* val) { + size_t t = 0; + for (int i = 0; i < n; i++) { + size_t byte = 0; + RCHECK(reader->ReadBits(8, &byte)); + t += (byte << (i * 8)); + } + *val = t; + return true; +} + +// 4.10.5. leb128(). Unsigned integer represented by a variable number of +// little-endian bytes. +bool ReadLeb128(BitReader* reader, size_t* size) { + size_t value = 0; + for (int i = 0; i < 8; i++) { + size_t leb128_byte = 0; + RCHECK(reader->ReadBits(8, &leb128_byte)); + value |= (leb128_byte & 0x7f) << (i * 7); + if (!(leb128_byte & 0x80)) + break; + } + // It is a requirement of bitstream conformance that the value returned from + // the leb128 parsing process is less than or equal to (1<<32) - 1. + RCHECK(value <= ((1ull << 32) - 1)); + *size = value; + return true; +} + +// 4.10.6. su(n). Signed integer converted from an n bits unsigned integer in +// the bitstream. +bool ReadSu(int n, BitReader* reader, int* value) { + RCHECK(reader->ReadBits(n, value)); + int sign_mask = 1 << (n - 1); + if (*value & sign_mask) + *value = *value - 2 * sign_mask; + return true; +} + +// 4.10.7. ns(n). Unsigned encoded integer with maximum number of values in n +// (i.e. output in range 0..n-1). +bool ReadNs(int n, BitReader* reader, int* value) { + const int w = FloorLog2(n) + 1; + const int m = (1 << w) - n; + RCHECK(reader->ReadBits(w - 1, value)); + if (*value < m) + return true; + int extra_bit = 0; + RCHECK(reader->ReadBits(1, &extra_bit)); + *value = (*value << 1) - m + extra_bit; + return true; +} + +// 5.9.16. Tile size calculation function: returns the smallest value for k such +// that blk_size << k is greater than or equal to target. +int TileLog2(int blk_size, int target) { + int k = 0; + for (k = 0; (blk_size << k) < target; k++) + continue; + return k; +} + +// See 7.8. Set frame refs process. +int FindLatestBackward(int shifted_order_hints[], + bool used_frame[], + int cur_frame_hint) { + int ref = -1; + int latest_order_hint = 0; + for (int i = 0; i < kNumRefFrames; i++) { + const int hint = shifted_order_hints[i]; + if (!used_frame[i] && hint >= cur_frame_hint && + (ref < 0 || hint >= latest_order_hint)) { + ref = i; + latest_order_hint = hint; + } + } + return ref; +} + +// See 7.8. Set frame refs process. +int FindEarliestBackward(int shifted_order_hints[], + bool used_frame[], + int cur_frame_hint) { + int ref = -1; + int earliest_order_hint = 0; + for (int i = 0; i < kNumRefFrames; i++) { + const int 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; + } + } + return ref; +} + +// See 7.8. Set frame refs process. +int FindLatestForward(int shifted_order_hints[], + bool used_frame[], + int cur_frame_hint) { + int ref = -1; + int latest_order_hint = 0; + for (int i = 0; i < kNumRefFrames; i++) { + const int hint = shifted_order_hints[i]; + if (!used_frame[i] && hint < cur_frame_hint && + (ref < 0 || hint >= latest_order_hint)) { + ref = i; + latest_order_hint = hint; + } + } + return ref; +} + +} // namespace + +AV1Parser::AV1Parser() = default; +AV1Parser::~AV1Parser() = default; + +bool AV1Parser::Parse(const uint8_t* data, size_t data_size) { + BitReader reader(data, data_size); + while (reader.bits_available() > 0) { + if (!ParseOpenBitstreamUnit(&reader)) + return false; + } + return true; +} + +// 5.3.1. General OBU syntax. +bool AV1Parser::ParseOpenBitstreamUnit(BitReader* reader) { + ObuHeader obu_header; + RCHECK(ParseObuHeader(reader, &obu_header)); + + size_t obu_size = 0; + if (obu_header.obu_has_size_field) + RCHECK(ReadLeb128(reader, &obu_size)); + else + obu_size = reader->bits_available() / 8; + + VLOG(4) << "OBU " << obu_header.obu_type << " size " << obu_size; + + const size_t start_position = reader->bit_position(); + switch (obu_header.obu_type) { + case OBU_SEQUENCE_HEADER: + RCHECK(ParseSequenceHeaderObu(reader)); + break; + case OBU_FRAME_HEADER: + case OBU_REDUNDENT_FRAME_HEADER: + RCHECK(ParseFrameHeaderObu(obu_header, reader)); + break; + case OBU_TILE_GROUP: + RCHECK(ParseTileGroupObu(obu_size, reader)); + break; + case OBU_FRAME: + RCHECK(ParseFrameObu(obu_header, obu_size, reader)); + break; + default: + // Skip all OBUs we are not interested. + RCHECK(reader->SkipBits(obu_size * 8)); + break; + } + + const size_t current_position = reader->bit_position(); + const size_t payload_bits = current_position - start_position; + if (obu_header.obu_type == OBU_TILE_GROUP || + obu_header.obu_type == OBU_FRAME) { + RCHECK(payload_bits == obu_size * 8); + } else if (obu_size > 0) { + RCHECK(payload_bits <= obu_size * 8); + RCHECK(ParseTrailingBits(obu_size * 8 - payload_bits, reader)); + } + return true; +} + +// 5.3.2. OBU header syntax. +bool AV1Parser::ParseObuHeader(BitReader* reader, ObuHeader* obu_header) { + int obu_forbidden_bit = 0; + RCHECK(reader->ReadBits(1, &obu_forbidden_bit)); + RCHECK(obu_forbidden_bit == 0); + RCHECK(reader->ReadBits(4, &obu_header->obu_type)); + bool obu_extension_flag = false; + RCHECK(reader->ReadBits(1, &obu_extension_flag)); + RCHECK(reader->ReadBits(1, &obu_header->obu_has_size_field)); + RCHECK(reader->SkipBits(1)); // Skip obu_reserved_1bit. + + if (obu_extension_flag) + RCHECK(ParseObuExtensionHeader(reader, &obu_header->extension_header)); + + return true; +} + +// 5.3.3. OBU extension header syntax. +bool AV1Parser::ParseObuExtensionHeader( + BitReader* reader, + ObuExtensionHeader* obu_extension_header) { + RCHECK(reader->ReadBits(3, &obu_extension_header->temporal_id)); + RCHECK(reader->ReadBits(2, &obu_extension_header->spatial_id)); + RCHECK(reader->SkipBits(3)); // Skip extension_header_reserved_3bits. + return true; +} + +// 5.3.4. Trailing bits syntax. +bool AV1Parser::ParseTrailingBits(size_t nb_bits, BitReader* reader) { + int trailing_one_bit = 0; + RCHECK(reader->ReadBits(1, &trailing_one_bit)); + RCHECK(trailing_one_bit == 1); + nb_bits--; + while (nb_bits > 0) { + int trailing_zero_bit = 0; + RCHECK(reader->ReadBits(1, &trailing_zero_bit)); + RCHECK(trailing_zero_bit == 0); + nb_bits--; + } + return true; +} + +bool AV1Parser::ByteAlignment(BitReader* reader) { + while (reader->bit_position() & 7) { + int zero_bit = 0; + RCHECK(reader->ReadBits(1, &zero_bit)); + RCHECK(zero_bit == 0); + } + return true; +} + +// 5.5.1. General sequence header OBU syntax. +bool AV1Parser::ParseSequenceHeaderObu(BitReader* reader) { + RCHECK(reader->ReadBits(3, &sequence_header_.seq_profile)); + // Skip still_picture. + RCHECK(reader->SkipBits(1)); + + RCHECK(reader->ReadBits(1, &sequence_header_.reduced_still_picture_header)); + if (sequence_header_.reduced_still_picture_header) { + sequence_header_.decoder_model_info_present_flag = false; + sequence_header_.operating_points_cnt_minus_1 = 0; + sequence_header_.operating_point_idc[0] = 0; + // Skip seq_level_idx[0]. + RCHECK(reader->SkipBits(5)); + sequence_header_.decoder_model_present_for_this_op[0] = false; + } else { + bool timing_info_present_flag = false; + RCHECK(reader->ReadBits(1, &timing_info_present_flag)); + + bool decoder_model_info_present_flag = false; + if (timing_info_present_flag) { + RCHECK(ParseTimingInfo(reader)); + RCHECK(reader->ReadBits(1, &decoder_model_info_present_flag)); + if (decoder_model_info_present_flag) + RCHECK(ParseDecoderModelInfo(reader)); + } + sequence_header_.decoder_model_info_present_flag = + decoder_model_info_present_flag; + + bool initial_display_delay_present_flag = false; + RCHECK(reader->ReadBits(1, &initial_display_delay_present_flag)); + + RCHECK(reader->ReadBits(5, &sequence_header_.operating_points_cnt_minus_1)); + for (int i = 0; i <= sequence_header_.operating_points_cnt_minus_1; i++) { + RCHECK(reader->ReadBits(12, &sequence_header_.operating_point_idc[i])); + int seq_level_idx_i = 0; + RCHECK(reader->ReadBits(5, &seq_level_idx_i)); + if (seq_level_idx_i > 7) { + // Skip seq_tier[i]. + RCHECK(reader->SkipBits(1)); + } + + if (sequence_header_.decoder_model_info_present_flag) { + RCHECK(reader->ReadBits( + 1, &sequence_header_.decoder_model_present_for_this_op[i])); + if (sequence_header_.decoder_model_present_for_this_op[i]) { + RCHECK(SkipOperatingParametersInfo(reader)); + } + } else { + sequence_header_.decoder_model_present_for_this_op[i] = false; + } + + if (initial_display_delay_present_flag) { + // Skip initial_display_delay_present_for_this_op[i], + // initial_display_delay_minus_1[i]. + RCHECK(reader->SkipBitsConditional(true, 4)); + } + } + } + + RCHECK(reader->ReadBits(4, &sequence_header_.frame_width_bits_minus_1)); + RCHECK(reader->ReadBits(4, &sequence_header_.frame_height_bits_minus_1)); + RCHECK(reader->ReadBits(sequence_header_.frame_width_bits_minus_1 + 1, + &sequence_header_.max_frame_width_minus_1)); + RCHECK(reader->ReadBits(sequence_header_.frame_height_bits_minus_1 + 1, + &sequence_header_.max_frame_height_minus_1)); + + if (sequence_header_.reduced_still_picture_header) { + sequence_header_.frame_id_numbers_present_flag = false; + } else { + RCHECK( + reader->ReadBits(1, &sequence_header_.frame_id_numbers_present_flag)); + } + if (sequence_header_.frame_id_numbers_present_flag) { + RCHECK( + reader->ReadBits(4, &sequence_header_.delta_frame_id_length_minus_2)); + RCHECK(reader->ReadBits( + 3, &sequence_header_.additional_frame_id_length_minus_1)); + } + + RCHECK(reader->ReadBits(1, &sequence_header_.use_128x128_superblock)); + // Skip enable_filter_intra, enable_intra_edge_filter. + RCHECK(reader->SkipBits(1 + 1)); + + if (sequence_header_.reduced_still_picture_header) { + sequence_header_.enable_warped_motion = false; + sequence_header_.enable_order_hint = false; + sequence_header_.enable_ref_frame_mvs = false; + sequence_header_.order_hint_bits = 0; + sequence_header_.seq_force_screen_content_tools = kSelectScreenContentTools; + sequence_header_.seq_force_integer_mv = kSelectIntegerMv; + } else { + // Skip enable_interintra_compound, enable_masked_compound, + RCHECK(reader->SkipBits(1 + 1)); + + RCHECK(reader->ReadBits(1, &sequence_header_.enable_warped_motion)); + RCHECK(reader->SkipBits(1)); // Skip enable_dual_filter. + RCHECK(reader->ReadBits(1, &sequence_header_.enable_order_hint)); + if (sequence_header_.enable_order_hint) { + // Skip enable_jnt_comp. + RCHECK(reader->SkipBits(1)); + RCHECK(reader->ReadBits(1, &sequence_header_.enable_ref_frame_mvs)); + } else { + sequence_header_.enable_ref_frame_mvs = false; + } + + bool seq_choose_screen_content_tools = false; + RCHECK(reader->ReadBits(1, &seq_choose_screen_content_tools)); + + if (seq_choose_screen_content_tools) { + sequence_header_.seq_force_screen_content_tools = + kSelectScreenContentTools; + } else { + RCHECK(reader->ReadBits( + 1, &sequence_header_.seq_force_screen_content_tools)); + } + + if (sequence_header_.seq_force_screen_content_tools > 0) { + bool seq_choose_integer_mv = false; + RCHECK(reader->ReadBits(1, &seq_choose_integer_mv)); + if (seq_choose_integer_mv) + sequence_header_.seq_force_integer_mv = kSelectIntegerMv; + else + RCHECK(reader->ReadBits(1, &sequence_header_.seq_force_integer_mv)); + } else { + sequence_header_.seq_force_integer_mv = kSelectIntegerMv; + } + + if (sequence_header_.enable_order_hint) { + int order_hint_bits_minus_1 = 0; + RCHECK(reader->ReadBits(3, &order_hint_bits_minus_1)); + sequence_header_.order_hint_bits = order_hint_bits_minus_1 + 1; + } else { + sequence_header_.order_hint_bits = 0; + } + } + + RCHECK(reader->ReadBits(1, &sequence_header_.enable_superres)); + RCHECK(reader->ReadBits(1, &sequence_header_.enable_cdef)); + RCHECK(reader->ReadBits(1, &sequence_header_.enable_restoration)); + RCHECK(ParseColorConfig(reader)); + RCHECK(reader->ReadBits(1, &sequence_header_.film_grain_params_present)); + return true; +} + +// 5.5.2. Color config syntax. +bool AV1Parser::ParseColorConfig(BitReader* reader) { + ColorConfig& color_config = sequence_header_.color_config; + + bool high_bitdepth = false; + RCHECK(reader->ReadBits(1, &high_bitdepth)); + if (sequence_header_.seq_profile == 2 && high_bitdepth) { + bool twelve_bit = false; + RCHECK(reader->ReadBits(1, &twelve_bit)); + color_config.bit_depth = twelve_bit ? 12 : 10; + } else if (sequence_header_.seq_profile <= 2) { + color_config.bit_depth = high_bitdepth ? 10 : 8; + } + + if (sequence_header_.seq_profile == 1) + color_config.mono_chrome = 0; + else + RCHECK(reader->ReadBits(1, &color_config.mono_chrome)); + color_config.num_planes = color_config.mono_chrome ? 1 : 3; + + bool color_description_present_flag = false; + RCHECK(reader->ReadBits(1, &color_description_present_flag)); + + if (color_description_present_flag) { + RCHECK(reader->ReadBits(8, &color_config.color_primaries)); + RCHECK(reader->ReadBits(8, &color_config.transfer_chracteristics)); + RCHECK(reader->ReadBits(8, &color_config.matrix_coefficients)); + } else { + color_config.color_primaries = CP_UNSPECIFIED; + color_config.transfer_chracteristics = TC_UNSPECIFIED; + color_config.matrix_coefficients = MC_UNSPECIFIED; + } + + if (color_config.mono_chrome) { + RCHECK(reader->ReadBits(1, &color_config.color_range)); + color_config.subsampling_x = true; + color_config.subsampling_y = true; + color_config.chroma_sampling_position = CSP_UNKNOWN; + color_config.separate_uv_delta_q = false; + return true; + } else if (color_config.color_primaries == CP_BT_709 && + color_config.transfer_chracteristics == TC_SRGB && + color_config.matrix_coefficients == MC_IDENTITY) { + color_config.color_range = true; + color_config.subsampling_x = false; + color_config.subsampling_y = false; + } else { + RCHECK(reader->ReadBits(1, &color_config.color_range)); + if (sequence_header_.seq_profile == 0) { + color_config.subsampling_x = true; + color_config.subsampling_y = true; + } else if (sequence_header_.seq_profile == 1) { + color_config.subsampling_x = false; + color_config.subsampling_y = false; + } else { + if (color_config.bit_depth == 12) { + RCHECK(reader->ReadBits(1, &color_config.subsampling_x)); + if (color_config.subsampling_x) + RCHECK(reader->ReadBits(1, &color_config.subsampling_y)); + else + color_config.subsampling_y = false; + } else { + color_config.subsampling_x = true; + color_config.subsampling_y = false; + } + } + + if (color_config.subsampling_x && color_config.subsampling_y) + RCHECK(reader->ReadBits(2, &color_config.chroma_sampling_position)); + } + + RCHECK(reader->ReadBits(1, &color_config.separate_uv_delta_q)); + return true; +} + +// 5.5.3.Timing info syntax. +bool AV1Parser::ParseTimingInfo(BitReader* reader) { + // Skip num_units_in_display_tick, time_scale. + RCHECK(reader->SkipBits(32 + 32)); + bool equal_picture_interval = false; + RCHECK(reader->ReadBits(1, &equal_picture_interval)); + sequence_header_.timing_info.equal_picture_interval = equal_picture_interval; + if (equal_picture_interval) { + uint32_t num_ticks_per_picture_minus_1 = 0; + RCHECK(ReadUvlc(reader, &num_ticks_per_picture_minus_1)); + } + return true; +} + +// 5.5.4. Decoder model info syntax. +bool AV1Parser::ParseDecoderModelInfo(BitReader* reader) { + DecoderModelInfo& decoder_model_info = sequence_header_.decoder_model_info; + + RCHECK(reader->ReadBits(5, &decoder_model_info.buffer_delay_length_minus_1)); + // Skip num_units_in_decoding_tick. + RCHECK(reader->SkipBits(32)); + RCHECK(reader->ReadBits( + 5, &decoder_model_info.buffer_removal_time_length_minus_1)); + RCHECK(reader->ReadBits( + 5, &decoder_model_info.frame_presentation_time_length_minus_1)); + return true; +} + +// 5.5.5. Operating parameters info syntax. +bool AV1Parser::SkipOperatingParametersInfo(BitReader* reader) { + const int n = + sequence_header_.decoder_model_info.buffer_delay_length_minus_1 + 1; + // Skip decoder_buffer_delay[op], encoder_buffer_delay[op], + // low_delay_mode_flag[op]. + RCHECK(reader->SkipBits(n + n + 1)); + return true; +} + +// 5.9.1. General frame header OBU syntax. +bool AV1Parser::ParseFrameHeaderObu(const ObuHeader& obu_header, + BitReader* reader) { + if (frame_header_.seen_frame_header) + return true; + + frame_header_.seen_frame_header = true; + RCHECK(ParseUncompressedHeader(obu_header, reader)); + if (frame_header_.show_existing_frame) { + DecodeFrameWrapup(); + frame_header_.seen_frame_header = false; + } else { + frame_header_.seen_frame_header = true; + } + return true; +} + +// 5.9.2. Uncompressed header syntax. +bool AV1Parser::ParseUncompressedHeader(const ObuHeader& obu_header, + BitReader* reader) { + int id_len = 0; + if (sequence_header_.frame_id_numbers_present_flag) { + id_len = sequence_header_.additional_frame_id_length_minus_1 + 1 + + sequence_header_.delta_frame_id_length_minus_2 + 2; + } + + bool frame_is_intra = false; + bool show_frame = false; + bool showable_frame = false; + bool error_resilient_mode = false; + + if (sequence_header_.reduced_still_picture_header) { + frame_header_.show_existing_frame = false; + frame_header_.frame_type = KEY_FRAME; + frame_is_intra = true; + show_frame = true; + showable_frame = false; + } else { + RCHECK(reader->ReadBits(1, &frame_header_.show_existing_frame)); + if (frame_header_.show_existing_frame) { + RCHECK(reader->ReadBits(3, &frame_header_.frame_to_show_map_idx)); + if (sequence_header_.decoder_model_info_present_flag && + !sequence_header_.timing_info.equal_picture_interval) { + RCHECK(SkipTemporalPointInfo(reader)); + } + frame_header_.refresh_frame_flags = 0; + if (sequence_header_.frame_id_numbers_present_flag) { + // Skip display_frame_id. + RCHECK(reader->SkipBits(id_len)); + } + frame_header_.frame_type = + reference_frames_[frame_header_.frame_to_show_map_idx].frame_type; + if (frame_header_.frame_type == KEY_FRAME) { + frame_header_.refresh_frame_flags = kAllFrames; + } + return true; + } + + RCHECK(reader->ReadBits(2, &frame_header_.frame_type)); + frame_is_intra = frame_header_.frame_type == INTRA_ONLY_FRAME || + frame_header_.frame_type == KEY_FRAME; + RCHECK(reader->ReadBits(1, &show_frame)); + if (show_frame && sequence_header_.decoder_model_info_present_flag && + !sequence_header_.timing_info.equal_picture_interval) { + RCHECK(SkipTemporalPointInfo(reader)); + } + if (show_frame) + showable_frame = frame_header_.frame_type != KEY_FRAME; + else + RCHECK(reader->ReadBits(1, &showable_frame)); + + if (frame_header_.frame_type == SWITCH_FRAME || + (frame_header_.frame_type == KEY_FRAME && show_frame)) { + error_resilient_mode = true; + } else { + RCHECK(reader->ReadBits(1, &error_resilient_mode)); + } + } + + if (frame_header_.frame_type == KEY_FRAME && show_frame) { + for (int i = 0; i < kNumRefFrames; i++) { + reference_frames_[i].order_hint = 0; + } + } + + bool disable_cdf_update = false; + RCHECK(reader->ReadBits(1, &disable_cdf_update)); + + bool allow_screen_content_tools = false; + if (sequence_header_.seq_force_screen_content_tools == + kSelectScreenContentTools) { + RCHECK(reader->ReadBits(1, &allow_screen_content_tools)); + } else { + allow_screen_content_tools = + sequence_header_.seq_force_screen_content_tools != 0; + } + + int force_integer_mv = 0; + if (allow_screen_content_tools) { + if (sequence_header_.seq_force_integer_mv == kSelectIntegerMv) + RCHECK(reader->ReadBits(1, &force_integer_mv)); + else + force_integer_mv = sequence_header_.seq_force_integer_mv; + } + if (frame_is_intra) + force_integer_mv = 1; + + if (sequence_header_.frame_id_numbers_present_flag) { + // Skip current_frame_id. + RCHECK(reader->SkipBits(id_len)); + } + + bool frame_size_override_flag = false; + if (frame_header_.frame_type == SWITCH_FRAME) + frame_size_override_flag = true; + else if (sequence_header_.reduced_still_picture_header) + frame_size_override_flag = false; + else + RCHECK(reader->ReadBits(1, &frame_size_override_flag)); + + RCHECK(reader->ReadBits(sequence_header_.order_hint_bits, + &frame_header_.order_hint)); + int primary_ref_frame = 0; + if (frame_is_intra || error_resilient_mode) { + primary_ref_frame = kPrimaryRefNone; + } else { + RCHECK(reader->ReadBits(3, &primary_ref_frame)); + } + if (sequence_header_.decoder_model_info_present_flag) { + bool buffer_removal_time_present_flag = false; + RCHECK(reader->ReadBits(1, &buffer_removal_time_present_flag)); + if (buffer_removal_time_present_flag) { + for (int op_num = 0; + op_num <= sequence_header_.operating_points_cnt_minus_1; op_num++) { + if (sequence_header_.decoder_model_present_for_this_op[op_num]) { + const int op_pt_idc = sequence_header_.operating_point_idc[op_num]; + const int in_temporal_layer = + (op_pt_idc >> obu_header.extension_header.temporal_id) & 1; + const int in_spatial_layer = + (op_pt_idc >> (obu_header.extension_header.spatial_id + 8)) & 1; + if (op_pt_idc == 0 || (in_temporal_layer && in_spatial_layer)) { + // Skip buffer_removal_time[ opNum ]. + RCHECK(reader->SkipBits(sequence_header_.decoder_model_info + .buffer_removal_time_length_minus_1 + + 1)); + } + } + } + } + } + + bool allow_high_precision_mv = false; + bool allow_intrabc = false; + + if (frame_header_.frame_type == SWITCH_FRAME || + (frame_header_.frame_type == KEY_FRAME && show_frame)) { + frame_header_.refresh_frame_flags = kAllFrames; + } else { + RCHECK(reader->ReadBits(8, &frame_header_.refresh_frame_flags)); + } + if (!frame_is_intra || frame_header_.refresh_frame_flags != kAllFrames) { + if (error_resilient_mode && sequence_header_.enable_order_hint) { + for (int i = 0; i < kNumRefFrames; i++) { + // Skip ref_order_hint[ i ]. + RCHECK(reader->SkipBits(sequence_header_.order_hint_bits)); + } + } + } + + if (frame_is_intra) { + RCHECK(ParseFrameSize(frame_size_override_flag, reader)); + RCHECK(ParseRenderSize(reader)); + if (allow_screen_content_tools && + frame_header_.upscaled_width == frame_header_.frame_width) + RCHECK(reader->ReadBits(1, &allow_intrabc)); + } else { + bool frame_refs_short_signaling = false; + if (sequence_header_.enable_order_hint) { + RCHECK(reader->ReadBits(1, &frame_refs_short_signaling)); + if (frame_refs_short_signaling) { + int last_frame_idx = 0; + RCHECK(reader->ReadBits(3, &last_frame_idx)); + int gold_frame_idx = 0; + RCHECK(reader->ReadBits(3, &gold_frame_idx)); + RCHECK(SetFrameRefs(last_frame_idx, gold_frame_idx)); + } + } + for (int i = 0; i < kRefsPerFrame; i++) { + if (!frame_refs_short_signaling) + RCHECK(reader->ReadBits(3, &frame_header_.ref_frame_idx[i])); + if (sequence_header_.frame_id_numbers_present_flag) { + // Skip delta_frame_id_minus_1. + RCHECK(reader->SkipBits(sequence_header_.delta_frame_id_length_minus_2 + + 2)); + } + } + if (frame_size_override_flag && !error_resilient_mode) { + RCHECK(ParseFrameSizeWithRefs(frame_size_override_flag, reader)); + } else { + RCHECK(ParseFrameSize(frame_size_override_flag, reader)); + RCHECK(ParseRenderSize(reader)); + } + + if (force_integer_mv) + allow_high_precision_mv = false; + else + RCHECK(reader->ReadBits(1, &allow_high_precision_mv)); + + RCHECK(SkipInterpolationFilter(reader)); + // Skip is_motion_mode_switchable. + RCHECK(reader->SkipBits(1)); + if (!error_resilient_mode && sequence_header_.enable_ref_frame_mvs) { + // Skip use_ref_frame_mvs. + RCHECK(reader->SkipBits(1)); + } + } + + if (!sequence_header_.reduced_still_picture_header && !disable_cdf_update) { + // Skip disable_frame_end_update_cdf. + RCHECK(reader->SkipBits(1)); + } + + RCHECK(ParseTileInfo(reader)); + RCHECK(ParseQuantizationParams(reader)); + RCHECK(ParseSegmentationParams(primary_ref_frame, reader)); + + bool delta_q_present = false; + RCHECK(SkipDeltaQParams(reader, &delta_q_present)); + RCHECK(SkipDeltaLfParams(delta_q_present, allow_intrabc, reader)); + + const auto& quantization_params = frame_header_.quantization_params; + bool coded_lossless = true; + for (int segment_id = 0; segment_id < kMaxSegments; segment_id++) { + const int qindex = GetQIndex(true, segment_id); + const bool lossless = qindex == 0 && quantization_params.delta_qydc == 0 && + quantization_params.delta_quac == 0 && + quantization_params.delta_qudc == 0 && + quantization_params.delta_qvac == 0 && + quantization_params.delta_qvdc == 0; + if (!lossless) + coded_lossless = false; + } + const bool all_lossless = coded_lossless && (frame_header_.frame_width == + frame_header_.upscaled_width); + + RCHECK(ParseLoopFilterParams(coded_lossless, allow_intrabc, reader)); + RCHECK(ParseCdefParams(coded_lossless, allow_intrabc, reader)); + RCHECK(ParseLrParams(all_lossless, allow_intrabc, reader)); + RCHECK(SkipTxMode(coded_lossless, reader)); + bool reference_select = false; + RCHECK(ParseFrameReferenceMode(frame_is_intra, reader, &reference_select)); + RCHECK(SkipSkipModeParams(frame_is_intra, reference_select, reader)); + + bool allow_warped_motion = false; + if (frame_is_intra || error_resilient_mode || + !sequence_header_.enable_warped_motion) { + allow_warped_motion = false; + } else { + RCHECK(reader->ReadBits(1, &allow_warped_motion)); + } + // Skip reduced_tx_set. + RCHECK(reader->SkipBits(1)); + + RCHECK( + SkipGlobalMotionParams(frame_is_intra, allow_high_precision_mv, reader)); + RCHECK(SkipFilmGrainParams(show_frame, showable_frame, reader)); + return true; +} + +// 5.9.3. Get relative distance function. +int AV1Parser::GetRelativeDist(int a, int b) { + if (!sequence_header_.enable_order_hint) + return 0; + int diff = a - b; + const int m = 1 << (sequence_header_.order_hint_bits - 1); + diff = (diff & (m - 1)) - (diff & m); + return diff; +} + +// 5.9.5. Frame size syntax. +bool AV1Parser::ParseFrameSize(bool frame_size_override_flag, + BitReader* reader) { + if (frame_size_override_flag) { + int frame_width_minus_1 = 0; + RCHECK(reader->ReadBits(sequence_header_.frame_width_bits_minus_1 + 1, + &frame_width_minus_1)); + int frame_height_minus_1 = 0; + RCHECK(reader->ReadBits(sequence_header_.frame_height_bits_minus_1 + 1, + &frame_height_minus_1)); + frame_header_.frame_width = frame_width_minus_1 + 1; + frame_header_.frame_height = frame_height_minus_1 + 1; + } else { + frame_header_.frame_width = sequence_header_.max_frame_width_minus_1 + 1; + frame_header_.frame_height = sequence_header_.max_frame_height_minus_1 + 1; + } + RCHECK(ParseSuperresParams(reader)); + ComputeImageSize(); + return true; +} + +// 5.9.6. Render size syntax. +bool AV1Parser::ParseRenderSize(BitReader* reader) { + bool render_and_frame_size_different = false; + RCHECK(reader->ReadBits(1, &render_and_frame_size_different)); + if (render_and_frame_size_different) { + int render_width_minus_1 = 0; + RCHECK(reader->ReadBits(16, &render_width_minus_1)); + int render_height_minus_1 = 0; + RCHECK(reader->ReadBits(16, &render_height_minus_1)); + frame_header_.render_width = render_width_minus_1 + 1; + frame_header_.render_height = render_height_minus_1 + 1; + } else { + frame_header_.render_width = frame_header_.upscaled_width; + frame_header_.render_height = frame_header_.frame_height; + } + return true; +} + +// 5.9.7. Frame size with refs syntax. +bool AV1Parser::ParseFrameSizeWithRefs(bool frame_size_override_flag, + BitReader* reader) { + bool found_ref = false; + for (int i = 0; i < kRefsPerFrame; i++) { + RCHECK(reader->ReadBits(1, &found_ref)); + if (found_ref) { + const ReferenceFrame& reference_frame = + reference_frames_[frame_header_.ref_frame_idx[i]]; + frame_header_.upscaled_width = reference_frame.upscaled_width; + frame_header_.frame_width = frame_header_.upscaled_width; + frame_header_.frame_height = reference_frame.frame_height; + frame_header_.render_width = reference_frame.render_width; + frame_header_.render_height = reference_frame.render_height; + break; + } + } + if (!found_ref) { + RCHECK(ParseFrameSize(frame_size_override_flag, reader)); + RCHECK(ParseRenderSize(reader)); + } else { + RCHECK(ParseSuperresParams(reader)); + ComputeImageSize(); + } + return true; +} + +// 5.9.8. Superres params syntax. +bool AV1Parser::ParseSuperresParams(BitReader* reader) { + const int kSuperresNum = 8; + const int kSuperresDenomMin = 9; + const int kSuperresDenomBits = 3; + + bool use_superres = false; + if (sequence_header_.enable_superres) + RCHECK(reader->ReadBits(1, &use_superres)); + + int superres_denom = 0; + if (use_superres) { + int coded_denom = 0; + RCHECK(reader->ReadBits(kSuperresDenomBits, &coded_denom)); + superres_denom = coded_denom + kSuperresDenomMin; + } else { + superres_denom = kSuperresNum; + } + + const int upscaled_width = frame_header_.frame_width; + frame_header_.upscaled_width = + (upscaled_width * kSuperresNum + superres_denom / 2) / superres_denom; + return true; +} + +// 5.9.9. Compute image size function. +void AV1Parser::ComputeImageSize() { + frame_header_.mi_cols = 2 * ((frame_header_.frame_width + 7) >> 3); + frame_header_.mi_rows = 2 * ((frame_header_.frame_height + 7) >> 3); +} + +// 5.9.10. Interpolation filter syntax. +bool AV1Parser::SkipInterpolationFilter(BitReader* reader) { + // SKip is_filter_switchable, interpolation_filter. + RCHECK(reader->SkipBitsConditional(false, 2)); + return true; +} + +// 5.9.11. Loop filter parms syntax. +bool AV1Parser::ParseLoopFilterParams(bool coded_lossless, + bool allow_intrabc, + BitReader* reader) { + if (coded_lossless || allow_intrabc) + return true; + + int loop_filter_level[] = {0, 0}; + RCHECK(reader->ReadBits(6, &loop_filter_level[0])); + RCHECK(reader->ReadBits(6, &loop_filter_level[1])); + if (sequence_header_.color_config.num_planes > 1) { + if (loop_filter_level[0] || loop_filter_level[1]) { + // Skip loop_filter_level[2], loop_filter_level[3]. + RCHECK(reader->SkipBits(6 + 6)); + } + } + // Skip loop_filter_sharpness. + RCHECK(reader->SkipBits(3)); + bool loop_filter_delta_enabled = false; + RCHECK(reader->ReadBits(1, &loop_filter_delta_enabled)); + if (loop_filter_delta_enabled) { + bool loop_filter_delta_update = false; + RCHECK(reader->ReadBits(1, &loop_filter_delta_update)); + if (loop_filter_delta_update) { + const int kTotalRefsPerFrame = 8; + for (int i = 0; i < kTotalRefsPerFrame; i++) { + // Skip update_ref_delta, loop_filter_ref_delta[ i ]. + RCHECK(reader->SkipBitsConditional(true, 1 + 6)); + } + for (int i = 0; i < 2; i++) { + // Skip update_mode_delta, loop_filter_mode_delta[ i ]. + RCHECK(reader->SkipBitsConditional(true, 1 + 6)); + } + } + } + return true; +} + +// 5.9.12. Quantization params syntax. +bool AV1Parser::ParseQuantizationParams(BitReader* reader) { + QuantizationParams& quantization_params = frame_header_.quantization_params; + + RCHECK(reader->ReadBits(8, &quantization_params.base_q_idx)); + RCHECK(ReadDeltaQ(reader, &quantization_params.delta_qydc)); + + const ColorConfig& color_config = sequence_header_.color_config; + if (color_config.num_planes > 1) { + bool diff_uv_delta = false; + if (color_config.separate_uv_delta_q) + RCHECK(reader->ReadBits(1, &diff_uv_delta)); + RCHECK(ReadDeltaQ(reader, &quantization_params.delta_qudc)); + RCHECK(ReadDeltaQ(reader, &quantization_params.delta_quac)); + if (diff_uv_delta) { + RCHECK(ReadDeltaQ(reader, &quantization_params.delta_qvdc)); + RCHECK(ReadDeltaQ(reader, &quantization_params.delta_qvac)); + } else { + quantization_params.delta_qvdc = quantization_params.delta_qudc; + quantization_params.delta_qvac = quantization_params.delta_quac; + } + } else { + quantization_params.delta_qudc = 0; + quantization_params.delta_quac = 0; + quantization_params.delta_qvdc = 0; + quantization_params.delta_qvac = 0; + } + bool using_qmatrix = false; + RCHECK(reader->ReadBits(1, &using_qmatrix)); + if (using_qmatrix) { + // Skip qm_y, qm_u. + RCHECK(reader->SkipBits(4 + 4)); + if (color_config.separate_uv_delta_q) { + // Skip qm_v. + RCHECK(reader->SkipBits(4)); + } + } + return true; +} + +// 5.9.13. Delta quantizer syntax. +bool AV1Parser::ReadDeltaQ(BitReader* reader, int* delta_q) { + bool delta_coded = false; + RCHECK(reader->ReadBits(1, &delta_coded)); + if (delta_coded) + RCHECK(ReadSu(1 + 6, reader, delta_q)); + else + *delta_q = 0; + return true; +} + +// 5.9.14. Segmentation params syntax. +bool AV1Parser::ParseSegmentationParams(int primary_ref_frame, + BitReader* reader) { + SegmentationParams& segmentation_params = frame_header_.segmentation_params; + + RCHECK(reader->ReadBits(1, &segmentation_params.segmentation_enabled)); + if (segmentation_params.segmentation_enabled) { + bool segmentation_update_data = false; + if (primary_ref_frame == kPrimaryRefNone) { + segmentation_update_data = true; + } else { + // Skip segmentation_update_map, segmentation_temporal_update. + RCHECK(reader->SkipBitsConditional(true, 1)); + RCHECK(reader->ReadBits(1, &segmentation_update_data)); + } + if (segmentation_update_data) { + static const int kSegmentationFeatureBits[kSegLvlMax] = {8, 6, 6, 6, + 6, 3, 0, 0}; + static const int kSegmentationFeatureSigned[kSegLvlMax] = {1, 1, 1, 1, + 1, 0, 0, 0}; + const int kMaxLoopFilter = 63; + static const int kSegmentationFeatureMax[kSegLvlMax] = {255, + kMaxLoopFilter, + kMaxLoopFilter, + kMaxLoopFilter, + kMaxLoopFilter, + 7, + 0, + 0}; + + for (int i = 0; i < kMaxSegments; i++) { + for (int j = 0; j < kSegLvlMax; j++) { + bool feature_enabled = false; + RCHECK(reader->ReadBits(1, &feature_enabled)); + segmentation_params.feature_enabled[i][j] = feature_enabled; + int clipped_value = 0; + if (feature_enabled) { + const int bits_to_read = kSegmentationFeatureBits[j]; + const int limit = kSegmentationFeatureMax[j]; + if (kSegmentationFeatureSigned[j]) { + int feature_value = 0; + RCHECK(ReadSu(1 + bits_to_read, reader, &feature_value)); + clipped_value = Clip3(-limit, limit, feature_value); + } else { + int feature_value = 0; + RCHECK(reader->ReadBits(bits_to_read, &feature_value)); + clipped_value = Clip3(0, limit, feature_value); + } + } + segmentation_params.feature_data[i][j] = clipped_value; + } + } + } + } else { + for (int i = 0; i < kMaxSegments; i++) { + for (int j = 0; j < kSegLvlMax; j++) { + segmentation_params.feature_enabled[i][j] = false; + segmentation_params.feature_data[i][j] = 0; + } + } + } + return true; +} + +// 5.9.15. Tile info syntax. +bool AV1Parser::ParseTileInfo(BitReader* reader) { + const int kMaxTileWidth = 4096; + const int kMaxTileArea = 4096 * 2304; + const int kMaxTileRows = 64; + const int kMaxTileCols = 64; + + TileInfo& tile_info = frame_header_.tile_info; + + const int sb_cols = sequence_header_.use_128x128_superblock + ? ((frame_header_.mi_cols + 31) >> 5) + : ((frame_header_.mi_cols + 15) >> 4); + const int sb_rows = sequence_header_.use_128x128_superblock + ? ((frame_header_.mi_rows + 31) >> 5) + : ((frame_header_.mi_rows + 15) >> 4); + const int sb_shift = sequence_header_.use_128x128_superblock ? 5 : 4; + const int sb_size = sb_shift + 2; + const int max_tile_width_sb = kMaxTileWidth >> sb_size; + int max_tile_area_sb = kMaxTileArea >> (2 * sb_size); + const int min_log2_tile_cols = TileLog2(max_tile_width_sb, sb_cols); + const int max_log2_tile_cols = TileLog2(1, std::min(sb_cols, kMaxTileCols)); + const int max_log2_tile_rows = TileLog2(1, std::min(sb_rows, kMaxTileRows)); + const int min_log2_tiles = std::max( + min_log2_tile_cols, TileLog2(max_tile_area_sb, sb_rows * sb_cols)); + + bool uniform_tile_spacing_flag = false; + RCHECK(reader->ReadBits(1, &uniform_tile_spacing_flag)); + if (uniform_tile_spacing_flag) { + tile_info.tile_cols_log2 = min_log2_tile_cols; + while (tile_info.tile_cols_log2 < max_log2_tile_cols) { + bool increment_tile_cols_log2 = false; + RCHECK(reader->ReadBits(1, &increment_tile_cols_log2)); + if (increment_tile_cols_log2) + tile_info.tile_cols_log2++; + else + break; + } + const int tile_width_sb = (sb_cols + (1 << tile_info.tile_cols_log2) - 1) >> + tile_info.tile_cols_log2; + int i = 0; + for (int start_sb = 0; start_sb < sb_cols; start_sb += tile_width_sb) { + i += 1; + } + tile_info.tile_cols = i; + + const int min_log2_tile_rows = + std::max(min_log2_tiles - tile_info.tile_cols_log2, 0); + tile_info.tile_rows_log2 = min_log2_tile_rows; + while (tile_info.tile_rows_log2 < max_log2_tile_rows) { + bool increment_tile_rows_log2 = false; + RCHECK(reader->ReadBits(1, &increment_tile_rows_log2)); + if (increment_tile_rows_log2) + tile_info.tile_rows_log2++; + else + break; + } + const int tile_height_sb = + (sb_rows + (1 << tile_info.tile_rows_log2) - 1) >> + tile_info.tile_rows_log2; + i = 0; + for (int start_sb = 0; start_sb < sb_rows; start_sb += tile_height_sb) { + i += 1; + } + tile_info.tile_rows = i; + } else { + int widest_tile_sb = 0; + int start_sb = 0; + int i = 0; + for (; start_sb < sb_cols; i++) { + const int max_width = std::min(sb_cols - start_sb, max_tile_width_sb); + int width_in_sbs_minus_1 = 0; + RCHECK(ReadNs(max_width, reader, &width_in_sbs_minus_1)); + const int size_sb = width_in_sbs_minus_1 + 1; + widest_tile_sb = std::max(size_sb, widest_tile_sb); + start_sb += size_sb; + } + tile_info.tile_cols = i; + tile_info.tile_cols_log2 = TileLog2(1, tile_info.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; + const int max_tile_height_sb = + std::max(max_tile_area_sb / widest_tile_sb, 1); + + start_sb = 0; + i = 0; + for (; start_sb < sb_rows; i++) { + const int max_height = std::min(sb_rows - start_sb, max_tile_height_sb); + int height_in_sbs_minus_1 = 0; + RCHECK(ReadNs(max_height, reader, &height_in_sbs_minus_1)); + const int size_sb = height_in_sbs_minus_1 + 1; + start_sb += size_sb; + } + tile_info.tile_rows = i; + tile_info.tile_rows_log2 = TileLog2(1, tile_info.tile_rows); + } + if (tile_info.tile_cols_log2 > 0 || tile_info.tile_rows_log2 > 0) { + // Skip context_update_tile_id. + RCHECK( + reader->SkipBits(tile_info.tile_rows_log2 + tile_info.tile_cols_log2)); + int tile_size_bytes_minus_1 = 0; + RCHECK(reader->ReadBits(2, &tile_size_bytes_minus_1)); + tile_info.tile_size_bytes = tile_size_bytes_minus_1 + 1; + } + return true; +} + +// 5.9.17. Quantizer index delta parameters syntax. +bool AV1Parser::SkipDeltaQParams(BitReader* reader, bool* delta_q_present) { + *delta_q_present = false; + if (frame_header_.quantization_params.base_q_idx > 0) + RCHECK(reader->ReadBits(1, delta_q_present)); + if (*delta_q_present) { + // Skip delta_q_res. + RCHECK(reader->SkipBits(2)); + } + return true; +} + +// 5.9.18. Loop filter delta parameters syntax. +bool AV1Parser::SkipDeltaLfParams(bool delta_q_present, + bool allow_intrabc, + BitReader* reader) { + bool delta_lf_present = false; + if (delta_q_present) { + if (!allow_intrabc) + RCHECK(reader->ReadBits(1, &delta_lf_present)); + if (delta_lf_present) { + // Skip delta_lf_res, delta_lf_multi. + RCHECK(reader->SkipBits(2 + 1)); + } + } + return true; +} + +// 5.9.19. CDEF params syntax. +bool AV1Parser::ParseCdefParams(bool coded_lossless, + bool allow_intrabc, + BitReader* reader) { + if (coded_lossless || allow_intrabc || !sequence_header_.enable_cdef) + return true; + + // Skip cdef_damping_minus_3. + RCHECK(reader->SkipBits(2)); + int cdef_bits = 0; + RCHECK(reader->ReadBits(2, &cdef_bits)); + for (int i = 0; i < (1 << cdef_bits); i++) { + // Skip cdef_y_pri_strength[i], Skip cdef_y_sec_strength[i]. + RCHECK(reader->SkipBits(4 + 2)); + if (sequence_header_.color_config.num_planes > 1) { + // Skip cdef_uv_pri_strength[i], Skip cdef_uv_sec_strength[i]. + RCHECK(reader->SkipBits(4 + 2)); + } + } + return true; +} + +// 5.9.20. Loop restoration params syntax. +bool AV1Parser::ParseLrParams(bool all_lossless, + bool allow_intrabc, + BitReader* reader) { + if (all_lossless || allow_intrabc || !sequence_header_.enable_restoration) + return true; + + enum FrameRestorationType { + RESTORE_NONE = 0, + RESTORE_SWITCHABLE = 3, + RESTORE_WIENER = 1, + RESTORE_SGRPROJ = 2, + }; + static const int kRemapLrType[4] = {RESTORE_NONE, RESTORE_SWITCHABLE, + RESTORE_WIENER, RESTORE_SGRPROJ}; + bool uses_lr = false; + bool uses_chroma_lr = false; + for (int i = 0; i < sequence_header_.color_config.num_planes; i++) { + int lr_type = 0; + RCHECK(reader->ReadBits(2, &lr_type)); + const int frame_restoration_type = kRemapLrType[lr_type]; + if (frame_restoration_type != RESTORE_NONE) { + uses_lr = true; + if (i > 0) + uses_chroma_lr = true; + } + } + + if (uses_lr) { + if (sequence_header_.use_128x128_superblock) { + // Skip lr_unit_shift. + RCHECK(reader->SkipBits(1)); + } else { + // Skip lr_unit_shift, lr_unit_extra_shift. + RCHECK(reader->SkipBitsConditional(true, 1)); + } + if (sequence_header_.color_config.subsampling_x && + sequence_header_.color_config.subsampling_y && uses_chroma_lr) { + // Skip lr_uv_shift. + RCHECK(reader->SkipBits(1)); + } + } + return true; +} + +// 5.9.21. TX mode syntax. +bool AV1Parser::SkipTxMode(bool coded_lossless, BitReader* reader) { + if (!coded_lossless) { + // Skip tx_mode_select. + RCHECK(reader->SkipBits(1)); + } + return true; +} + +// 5.9.22. Skip mode params syntax. +bool AV1Parser::SkipSkipModeParams(bool frame_is_intra, + bool reference_select, + BitReader* reader) { + bool skip_mode_allowed = false; + if (frame_is_intra || !reference_select || + !sequence_header_.enable_order_hint) { + skip_mode_allowed = false; + } else { + int forward_idx = -1; + int forward_hint = 0; + int backward_idx = -1; + int backward_hint = 0; + for (int i = 0; i < kRefsPerFrame; i++) { + const int ref_hint = + reference_frames_[frame_header_.ref_frame_idx[i]].order_hint; + if (GetRelativeDist(ref_hint, frame_header_.order_hint) < 0) { + if (forward_idx < 0 || GetRelativeDist(ref_hint, forward_hint) > 0) { + forward_idx = i; + forward_hint = ref_hint; + } + } else if (GetRelativeDist(ref_hint, frame_header_.order_hint) > 0) { + if (backward_idx < 0 || GetRelativeDist(ref_hint, backward_hint) < 0) { + backward_idx = i; + backward_hint = ref_hint; + } + } + } + if (forward_idx < 0) { + skip_mode_allowed = false; + } else if (backward_idx >= 0) { + skip_mode_allowed = true; + } else { + int second_forward_idx = -1; + int second_forward_hint = 0; + for (int i = 0; i < kRefsPerFrame; i++) { + const int ref_hint = + reference_frames_[frame_header_.ref_frame_idx[i]].order_hint; + if (GetRelativeDist(ref_hint, forward_hint) < 0) { + if (second_forward_idx < 0 || + GetRelativeDist(ref_hint, second_forward_hint) > 0) { + second_forward_idx = i; + second_forward_hint = ref_hint; + } + } + } + skip_mode_allowed = second_forward_idx >= 0; + } + } + + if (skip_mode_allowed) { + // Skip skip_mode_present. + RCHECK(reader->SkipBits(1)); + } + return true; +} + +// 5.9.23. Frame reference mode syntax. +bool AV1Parser::ParseFrameReferenceMode(bool frame_is_intra, + BitReader* reader, + bool* reference_select) { + if (frame_is_intra) + *reference_select = false; + else + RCHECK(reader->ReadBits(1, reference_select)); + return true; +} + +// 5.9.24. Global motion params syntax. +bool AV1Parser::SkipGlobalMotionParams(bool frame_is_intra, + bool allow_high_precision_mv, + BitReader* reader) { + if (frame_is_intra) + return true; + + for (int ref = LAST_FRAME; ref <= ALTREF_FRAME; ref++) { + int type = 0; + + bool is_global = false; + RCHECK(reader->ReadBits(1, &is_global)); + if (is_global) { + bool is_rot_zoom = false; + RCHECK(reader->ReadBits(1, &is_rot_zoom)); + if (is_rot_zoom) { + type = ROTZOOM; + } else { + bool is_translation = false; + RCHECK(reader->ReadBits(1, &is_translation)); + type = is_translation ? TRANSLATION : AFFINE; + } + } else { + type = IDENTITY; + } + + if (type >= ROTZOOM) { + RCHECK(SkipGlobalParam(type, ref, 2, allow_high_precision_mv, reader)); + RCHECK(SkipGlobalParam(type, ref, 3, allow_high_precision_mv, reader)); + if (type == AFFINE) { + RCHECK(SkipGlobalParam(type, ref, 4, allow_high_precision_mv, reader)); + RCHECK(SkipGlobalParam(type, ref, 5, allow_high_precision_mv, reader)); + } + } + if (type >= TRANSLATION) { + RCHECK(SkipGlobalParam(type, ref, 0, allow_high_precision_mv, reader)); + RCHECK(SkipGlobalParam(type, ref, 1, allow_high_precision_mv, reader)); + } + } + return true; +} + +// 5.9.25. Global param syntax. +bool AV1Parser::SkipGlobalParam(int type, + int ref, + int idx, + bool allow_high_precision_mv, + BitReader* reader) { + const int kGmAbsTransBits = 12; + const int kGmAbsTransOnlyBits = 9; + const int kGmAbsAlphaBits = 12; + + int abs_bits = kGmAbsAlphaBits; + if (idx < 2) { + if (type == TRANSLATION) { + abs_bits = kGmAbsTransOnlyBits - (allow_high_precision_mv ? 0 : 1); + } else { + abs_bits = kGmAbsTransBits; + } + } + const int mx = 1 << abs_bits; + RCHECK(SkipDecodeSignedSubexpWithRef(-mx, mx + 1, reader)); + return true; +} + +// 5.9.26. Decode signed subexp with ref syntax. +bool AV1Parser::SkipDecodeSignedSubexpWithRef(int low, + int high, + BitReader* reader) { + RCHECK(SkipDecodeUnsignedSubexpWithRef(high - low, reader)); + return true; +} + +// 5.9.27. Decode unsigned subbexp with ref syntax. +bool AV1Parser::SkipDecodeUnsignedSubexpWithRef(int mx, BitReader* reader) { + RCHECK(SkipDecodeSubexp(mx, reader)); + return true; +} + +// 5.9.28. Decode subexp syntax. +bool AV1Parser::SkipDecodeSubexp(int num_syms, BitReader* reader) { + int i = 0; + int mk = 0; + int k = 3; + while (true) { + const int b2 = i ? (k + i - 1) : k; + const int a = 1 << b2; + if (num_syms <= mk + 3 * a) { + int subexp_final_bits = 0; + RCHECK(ReadNs(num_syms - mk, reader, &subexp_final_bits)); + return true; + } else { + bool subexp_more_bits = false; + RCHECK(reader->ReadBits(1, &subexp_more_bits)); + if (subexp_more_bits) { + i++; + mk += a; + } else { + // Skip subexp_bits. + RCHECK(reader->SkipBits(b2)); + return true; + } + } + } + return true; +} + +// 5.9.30. Film grain params syntax. +bool AV1Parser::SkipFilmGrainParams(bool show_frame, + bool showable_frame, + BitReader* reader) { + if (!sequence_header_.film_grain_params_present || + (!show_frame && !showable_frame)) { + return true; + } + + bool apply_grain = false; + RCHECK(reader->ReadBits(1, &apply_grain)); + if (!apply_grain) + return true; + + // Skip grain_seed. + RCHECK(reader->SkipBits(16)); + bool update_grain = true; + if (frame_header_.frame_type == INTER_FRAME) + RCHECK(reader->ReadBits(1, &update_grain)); + if (!update_grain) { + // Skip film_grain_params_ref_idx. + RCHECK(reader->SkipBits(3)); + return true; + } + + int num_y_points = 0; + RCHECK(reader->ReadBits(4, &num_y_points)); + // Skip point_y_value, point_y_scaling. + RCHECK(reader->SkipBits((8 + 8) * num_y_points)); + + const ColorConfig& color_config = sequence_header_.color_config; + bool chroma_scaling_from_luma = false; + if (!color_config.mono_chrome) + RCHECK(reader->ReadBits(1, &chroma_scaling_from_luma)); + int num_cb_points = 0; + int num_cr_points = 0; + if (color_config.mono_chrome || chroma_scaling_from_luma || + (color_config.subsampling_x && color_config.subsampling_y && + num_y_points == 0)) { + num_cb_points = 0; + num_cr_points = 0; + } else { + RCHECK(reader->ReadBits(4, &num_cb_points)); + // Skip point_cb_value, point_cb_scaling. + RCHECK(reader->SkipBits((8 + 8) * num_cb_points)); + RCHECK(reader->ReadBits(4, &num_cr_points)); + // Skip point_cr_value, point_cr_scaling. + RCHECK(reader->SkipBits((8 + 8) * num_cr_points)); + } + + // Skip grain_scaling_minus_8. + RCHECK(reader->SkipBits(2)); + int ar_coeff_lag = 0; + RCHECK(reader->ReadBits(2, &ar_coeff_lag)); + const int num_pos_luma = 2 * ar_coeff_lag * (ar_coeff_lag + 1); + int num_pos_chroma = num_pos_luma; + if (num_y_points) { + num_pos_chroma = num_pos_luma + 1; + // Skip ar_coeffs_y_plus_128. + RCHECK(reader->SkipBits(8 * num_pos_luma)); + } + if (chroma_scaling_from_luma || num_cb_points) { + // Skip ar_coeffs_cb_plus_128. + RCHECK(reader->SkipBits(8 * num_pos_chroma)); + } + if (chroma_scaling_from_luma || num_cr_points) { + // Skip ar_coeffs_cb_plus_128. + RCHECK(reader->SkipBits(8 * num_pos_chroma)); + } + + // Skip ar_coeff_shift_minus_6, grain_scale_shift. + RCHECK(reader->SkipBits(2 + 2)); + if (num_cb_points) { + // Skip cb_mult, cb_luma_mult, cb_offset. + RCHECK(reader->SkipBits(8 + 8 + 9)); + } + if (num_cr_points) { + // Skip cr_mult, cr_luma_mult, cr_offset. + RCHECK(reader->SkipBits(8 + 8 + 9)); + } + // Skip overlap_flag, clip_restricted_range. + RCHECK(reader->SkipBits(1 + 1)); + return true; +} + +// 5.9.31. Temporal point info syntax. +bool AV1Parser::SkipTemporalPointInfo(BitReader* reader) { + const int frame_presentation_time_length = + sequence_header_.decoder_model_info + .frame_presentation_time_length_minus_1 + + 1; + // Skip frame_presentation_time. + RCHECK(reader->SkipBits(frame_presentation_time_length)); + return true; +} + +// 5.10. Frame OBU syntax. +bool AV1Parser::ParseFrameObu(const ObuHeader& obu_header, + size_t size, + BitReader* reader) { + const size_t start_bit_pos = reader->bit_position(); + RCHECK(ParseFrameHeaderObu(obu_header, reader)); + RCHECK(ByteAlignment(reader)); + const size_t end_bit_pos = reader->bit_position(); + const size_t header_bytes = (end_bit_pos - start_bit_pos) / 8; + RCHECK(ParseTileGroupObu(size - header_bytes, reader)); + return true; +} + +// 5.11.1. General tile group OBU syntax. +bool AV1Parser::ParseTileGroupObu(size_t size, BitReader* reader) { + const TileInfo& tile_info = frame_header_.tile_info; + const size_t start_bit_pos = reader->bit_position(); + + const int num_tiles = tile_info.tile_cols * tile_info.tile_rows; + bool tile_start_and_end_present_flag = false; + if (num_tiles > 1) + RCHECK(reader->ReadBits(1, &tile_start_and_end_present_flag)); + + int tg_start = 0; + int tg_end = num_tiles - 1; + if (num_tiles > 1 && tile_start_and_end_present_flag) { + const int tile_bits = tile_info.tile_cols_log2 + tile_info.tile_rows_log2; + RCHECK(reader->ReadBits(tile_bits, &tg_start)); + RCHECK(reader->ReadBits(tile_bits, &tg_end)); + } + RCHECK(ByteAlignment(reader)); + + const size_t end_bit_pos = reader->bit_position(); + const size_t header_bytes = (end_bit_pos - start_bit_pos) / 8; + size -= header_bytes; + + for (int tile_num = tg_start; tile_num <= tg_end; tile_num++) { + const bool last_tile = tile_num == tg_end; + size_t tile_size = size; + if (!last_tile) { + size_t tile_size_minus_1 = 0; + RCHECK(ReadLe(tile_info.tile_size_bytes, reader, &tile_size_minus_1)); + tile_size = tile_size_minus_1 + 1; + size -= tile_size + tile_info.tile_size_bytes; + } + RCHECK(reader->SkipBits(tile_size * 8)); // Skip the tile. + } + + if (tg_end == num_tiles - 1) { + DecodeFrameWrapup(); + frame_header_.seen_frame_header = false; + } + return true; +} + +// 5.11.14. Segmentation feature active function. +bool AV1Parser::SegFeatureActiveIdx(int idx, int feature) { + const SegmentationParams& segmentation_params = + frame_header_.segmentation_params; + return segmentation_params.segmentation_enabled && + segmentation_params.feature_enabled[idx][feature]; +} + +// 7.4. Decode frame wrapup process. +void AV1Parser::DecodeFrameWrapup() { + const int refresh_frame_flags = frame_header_.refresh_frame_flags; + if (frame_header_.show_existing_frame && + frame_header_.frame_type == KEY_FRAME) { + // 7.21. Reference frame loading process. + const ReferenceFrame& reference_frame = + reference_frames_[frame_header_.frame_to_show_map_idx]; + + frame_header_.upscaled_width = reference_frame.upscaled_width; + frame_header_.frame_width = reference_frame.frame_width; + frame_header_.frame_height = reference_frame.frame_height; + frame_header_.render_width = reference_frame.render_width; + frame_header_.render_height = reference_frame.render_height; + frame_header_.mi_cols = reference_frame.mi_cols; + frame_header_.mi_rows = reference_frame.mi_rows; + + ColorConfig& color_config = sequence_header_.color_config; + color_config.subsampling_x = reference_frame.subsampling_x; + color_config.subsampling_y = reference_frame.subsampling_y; + color_config.bit_depth = reference_frame.bit_depth; + + frame_header_.order_hint = reference_frame.order_hint; + } + // 7.20. Reference frame update process. + for (int i = 0; i <= kNumRefFrames - 1; i++) { + if ((refresh_frame_flags >> i) & 1) { + ReferenceFrame& reference_frame = reference_frames_[i]; + + reference_frame.upscaled_width = frame_header_.upscaled_width; + reference_frame.frame_width = frame_header_.frame_width; + reference_frame.frame_height = frame_header_.frame_height; + reference_frame.render_width = frame_header_.render_width; + reference_frame.render_height = frame_header_.render_height; + reference_frame.mi_cols = frame_header_.mi_cols; + reference_frame.mi_rows = frame_header_.mi_rows; + reference_frame.frame_type = frame_header_.frame_type; + + const ColorConfig& color_config = sequence_header_.color_config; + reference_frame.subsampling_x = color_config.subsampling_x; + reference_frame.subsampling_y = color_config.subsampling_y; + reference_frame.bit_depth = color_config.bit_depth; + + reference_frame.order_hint = frame_header_.order_hint; + } + } +} + +// 7.8. Set frame refs process. +bool AV1Parser::SetFrameRefs(int last_frame_idx, int gold_frame_idx) { + for (int i = 0; i < kRefsPerFrame; i++) + frame_header_.ref_frame_idx[i] = -1; + frame_header_.ref_frame_idx[LAST_FRAME - LAST_FRAME] = last_frame_idx; + frame_header_.ref_frame_idx[GOLDEN_FRAME - LAST_FRAME] = gold_frame_idx; + + bool used_frame[kNumRefFrames] = {}; + used_frame[last_frame_idx] = true; + used_frame[gold_frame_idx] = true; + + const int cur_frame_hint = 1 << (sequence_header_.order_hint_bits - 1); + + // An array containing the expected output order shifted such that the + // current frame has hint equal to |cur_frame_hint| is prepared. + int shifted_order_hints[kNumRefFrames]; + for (int i = 0; i < kNumRefFrames; i++) { + shifted_order_hints[i] = + cur_frame_hint + GetRelativeDist(reference_frames_[i].order_hint, + frame_header_.order_hint); + } + + const int last_order_hint = shifted_order_hints[last_frame_idx]; + RCHECK(last_order_hint < cur_frame_hint); + const int gold_order_hint = shifted_order_hints[gold_frame_idx]; + RCHECK(gold_order_hint < cur_frame_hint); + + // The ALTREF_FRAME reference is set to be a backward reference to the frame + // with highest output order. + int ref = FindLatestBackward(shifted_order_hints, used_frame, cur_frame_hint); + if (ref >= 0) { + frame_header_.ref_frame_idx[ALTREF_FRAME - LAST_FRAME] = ref; + used_frame[ref] = true; + } + + // The BWDREF_FRAME reference is set to be a backward reference to the cloest + // frame. + ref = FindEarliestBackward(shifted_order_hints, used_frame, cur_frame_hint); + if (ref >= 0) { + frame_header_.ref_frame_idx[BWDREF_FRAME - LAST_FRAME] = ref; + used_frame[ref] = true; + } + + // The ALTREF2_FRAME reference is set to the next closest backward reference. + ref = FindEarliestBackward(shifted_order_hints, used_frame, cur_frame_hint); + if (ref >= 0) { + frame_header_.ref_frame_idx[ALTREF2_FRAME - LAST_FRAME] = ref; + used_frame[ref] = true; + } + + // The remaining references are set to be forward references in + // anti-chronological order. + static const int kRefFrameList[] = { + LAST2_FRAME, LAST3_FRAME, BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME, + }; + static_assert(arraysize(kRefFrameList) == kRefsPerFrame - 2, + "Unexpected kRefFrameList size."); + for (const int ref_frame : kRefFrameList) { + if (frame_header_.ref_frame_idx[ref_frame - LAST_FRAME] < 0) { + ref = FindLatestForward(shifted_order_hints, used_frame, cur_frame_hint); + if (ref >= 0) { + frame_header_.ref_frame_idx[ref_frame - LAST_FRAME] = ref; + used_frame[ref] = true; + } + } + } + + // Finally, any remaining references are set to the reference frame with + // smallest output order. + ref = -1; + int earliest_order_hint = 0; + for (int i = 0; i < kNumRefFrames; i++) { + const int hint = shifted_order_hints[i]; + if (ref < 0 || hint < earliest_order_hint) { + ref = i; + earliest_order_hint = hint; + } + } + for (int i = 0; i < kRefsPerFrame; i++) { + if (frame_header_.ref_frame_idx[i] < 0) { + frame_header_.ref_frame_idx[i] = ref; + } + } + + return true; +} + +// 7.12.2. Dequantization functions. The function returns the quantizer index +// for the current block. +int AV1Parser::GetQIndex(bool ignore_delta_q, int segment_id) { + // We do not have use case for ignore_delta_q false case. + CHECK(ignore_delta_q) << "ignoreDeltaQ equal to 0 is not supported."; + + const int base_q_idx = frame_header_.quantization_params.base_q_idx; + + const int kSegLvlAltQ = 0; + if (SegFeatureActiveIdx(segment_id, kSegLvlAltQ)) { + const int data = + frame_header_.segmentation_params.feature_data[segment_id][kSegLvlAltQ]; + const int qindex = base_q_idx + data; + return Clip3(0, 255, qindex); + } else { + return base_q_idx; + } +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/codecs/av1_parser.h b/packager/media/codecs/av1_parser.h new file mode 100644 index 00000000000..cd6e4812a83 --- /dev/null +++ b/packager/media/codecs/av1_parser.h @@ -0,0 +1,273 @@ +// Copyright 2018 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#ifndef PACKAGER_MEDIA_CODECS_AV1_PARSER_H_ +#define PACKAGER_MEDIA_CODECS_AV1_PARSER_H_ + +#include +#include + +namespace shaka { +namespace media { + +class BitReader; + +/// AV1 bitstream parser implemented according to av1 bitstream specification: +/// https://aomediacodec.github.io/av1-spec/. +class AV1Parser { + public: + AV1Parser(); + ~AV1Parser(); + + /// Parse an AV1 sample. Note that the sample data SHALL be a sequence of OBUs + /// forming a Temporal Unit, with each OBU SHALL follow the + /// open_bitstream_unit Low Overhead Bitstream Format syntax. See + /// https://aomediacodec.github.io/av1-isobmff/#sampleformat for details. + /// @return true on success, false otherwise. + bool Parse(const uint8_t* data, size_t data_size); + + private: + AV1Parser(const AV1Parser&) = delete; + AV1Parser& operator=(const AV1Parser&) = delete; + + // The structure names and the method names match the names in the spec but in + // CamelCase. + // Not all fields are populated. In particular, fields not referenced and not + // needed to parse other parts of the bitstream are not populated. + + struct ObuExtensionHeader { + int temporal_id = 0; + int spatial_id = 0; + }; + + struct ObuHeader { + int obu_type = 0; + bool obu_has_size_field = false; + ObuExtensionHeader extension_header; + }; + + struct ColorConfig { + int bit_depth = 0; + bool mono_chrome = false; + int num_planes = 0; + int color_primaries = 0; + int transfer_chracteristics = 0; + int matrix_coefficients = 0; + bool color_range = false; + bool subsampling_x = false; + bool subsampling_y = false; + int chroma_sampling_position = 0; + bool separate_uv_delta_q = false; + }; + + struct TimingInfo { + bool equal_picture_interval = false; + }; + + struct DecoderModelInfo { + int buffer_delay_length_minus_1 = 0; + int buffer_removal_time_length_minus_1 = 0; + int frame_presentation_time_length_minus_1 = 0; + }; + + struct SequenceHeaderObu { + int seq_profile = 0; + bool reduced_still_picture_header = false; + + TimingInfo timing_info; + bool decoder_model_info_present_flag = false; + DecoderModelInfo decoder_model_info; + + int operating_points_cnt_minus_1 = 0; + static constexpr int kMaxOperatingPointsCount = 1 << 5; + int operating_point_idc[kMaxOperatingPointsCount] = {}; + bool decoder_model_present_for_this_op[kMaxOperatingPointsCount] = {}; + + int frame_width_bits_minus_1 = 0; + int frame_height_bits_minus_1 = 0; + int max_frame_width_minus_1 = 0; + int max_frame_height_minus_1 = 0; + + bool frame_id_numbers_present_flag = false; + int delta_frame_id_length_minus_2 = 0; + int additional_frame_id_length_minus_1 = 0; + + bool use_128x128_superblock = false; + + bool enable_warped_motion = false; + bool enable_order_hint = false; + bool enable_ref_frame_mvs = false; + int order_hint_bits = 0; + + int seq_force_screen_content_tools = 0; + int seq_force_integer_mv = 0; + + bool enable_superres = false; + bool enable_cdef = false; + bool enable_restoration = false; + ColorConfig color_config; + bool film_grain_params_present = false; + }; + + struct TileInfo { + int tile_cols = 0; + int tile_rows = 0; + int tile_cols_log2 = 0; + int tile_rows_log2 = 0; + int tile_size_bytes = 0; + }; + + struct QuantizationParams { + int base_q_idx = 0; + int delta_qydc = 0; + int delta_quac = 0; + int delta_qudc = 0; + int delta_qvac = 0; + int delta_qvdc = 0; + }; + + static constexpr int kMaxSegments = 8; + static constexpr int kSegLvlMax = 8; + struct SegmentationParams { + bool segmentation_enabled = false; + bool feature_enabled[kMaxSegments][kSegLvlMax] = {}; + int feature_data[kMaxSegments][kSegLvlMax] = {}; + }; + + static constexpr int kRefsPerFrame = 7; + struct FrameHeaderObu { + bool seen_frame_header = false; + + bool show_existing_frame = false; + int frame_to_show_map_idx = 0; + + int frame_type = 0; + int refresh_frame_flags = 0; + + int ref_frame_idx[kRefsPerFrame] = {}; + + int order_hint = 0; + + int frame_width = 0; + int frame_height = 0; + int upscaled_width = 0; + int render_width = 0; + int render_height = 0; + + int mi_cols = 0; + int mi_rows = 0; + + TileInfo tile_info; + QuantizationParams quantization_params; + SegmentationParams segmentation_params; + }; + + struct ReferenceFrame { + int frame_type = 0; + int order_hint = 0; + + int frame_width = 0; + int frame_height = 0; + int upscaled_width = 0; + int render_width = 0; + int render_height = 0; + + int mi_cols = 0; + int mi_rows = 0; + + int bit_depth = 0; + bool subsampling_x = false; + bool subsampling_y = false; + }; + + bool ParseOpenBitstreamUnit(BitReader* reader); + bool ParseObuHeader(BitReader* reader, ObuHeader* obu_header); + bool ParseObuExtensionHeader(BitReader* reader, + ObuExtensionHeader* obu_extension_header); + bool ParseTrailingBits(size_t nb_bits, BitReader* reader); + bool ByteAlignment(BitReader* reader); + + // SequenceHeader OBU and children structures. + bool ParseSequenceHeaderObu(BitReader* reader); + bool ParseColorConfig(BitReader* reader); + bool ParseTimingInfo(BitReader* reader); + bool ParseDecoderModelInfo(BitReader* reader); + bool SkipOperatingParametersInfo(BitReader* reader); + + // FrameHeader OBU and children structures. + bool ParseFrameHeaderObu(const ObuHeader& obu_header, BitReader* reader); + bool ParseUncompressedHeader(const ObuHeader& obu_header, BitReader* reader); + int GetRelativeDist(int a, int b); + bool ParseFrameSize(bool frame_size_override_flag, BitReader* reader); + bool ParseRenderSize(BitReader* reader); + bool ParseFrameSizeWithRefs(bool frame_size_override_flag, BitReader* reader); + bool ParseSuperresParams(BitReader* reader); + void ComputeImageSize(); + bool SkipInterpolationFilter(BitReader* reader); + bool ParseLoopFilterParams(bool coded_lossless, + bool allow_intrabc, + BitReader* reader); + bool ParseTileInfo(BitReader* reader); + bool ParseQuantizationParams(BitReader* reader); + bool ReadDeltaQ(BitReader* reader, int* delta_q); + bool ParseSegmentationParams(int primary_ref_frame, BitReader* reader); + bool SkipDeltaQParams(BitReader* reader, bool* delta_q_present); + bool SkipDeltaLfParams(bool delta_q_present, + bool allow_intrabc, + BitReader* reader); + bool ParseCdefParams(bool coded_lossless, + bool allow_intrabc, + BitReader* reader); + bool ParseLrParams(bool all_lossless, bool allow_intrabc, BitReader* reader); + bool SkipTxMode(bool coded_lossless, BitReader* reader); + bool SkipSkipModeParams(bool frame_is_intra, + bool reference_select, + BitReader* reader); + bool ParseFrameReferenceMode(bool frame_is_intra, + BitReader* reader, + bool* reference_select); + bool SkipGlobalMotionParams(bool frame_is_intra, + bool allow_high_precision_mv, + BitReader* reader); + bool SkipGlobalParam(int type, + int ref, + int idx, + bool allow_high_precision_mv, + BitReader* reader); + bool SkipDecodeSignedSubexpWithRef(int low, int high, BitReader* reader); + bool SkipDecodeUnsignedSubexpWithRef(int mx, BitReader* reader); + bool SkipDecodeSubexp(int num_syms, BitReader* reader); + bool SkipFilmGrainParams(bool show_frame, + bool showable_frame, + BitReader* reader); + bool SkipTemporalPointInfo(BitReader* reader); + + // Frame OBU. + bool ParseFrameObu(const ObuHeader& obu_header, + size_t size, + BitReader* reader); + + // TileGroup OBU. + bool ParseTileGroupObu(size_t size, BitReader* reader); + bool SegFeatureActiveIdx(int idx, int feature); + + // Decoding process related helper functions. + // We do not care about decoding itself, but we need to take care of reference + // frame states. + void DecodeFrameWrapup(); + bool SetFrameRefs(int last_frame_idx, int gold_frame_idx); + int GetQIndex(bool ignore_delta_q, int segment_id); + + SequenceHeaderObu sequence_header_; + FrameHeaderObu frame_header_; + static constexpr int kNumRefFrames = 8; + ReferenceFrame reference_frames_[kNumRefFrames]; +}; + +} // namespace media +} // namespace shaka + +#endif // PACKAGER_MEDIA_CODECS_AV1_PARSER_H_ diff --git a/packager/media/codecs/av1_parser_unittest.cc b/packager/media/codecs/av1_parser_unittest.cc new file mode 100644 index 00000000000..cf510db0b4b --- /dev/null +++ b/packager/media/codecs/av1_parser_unittest.cc @@ -0,0 +1,24 @@ +// Copyright 2018 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/media/codecs/av1_parser.h" + +#include + +#include "packager/media/test/test_data_util.h" + +namespace shaka { +namespace media { + +TEST(AV1ParserTest, ParseIFrameSuccess) { + const std::vector buffer = ReadTestDataFile("av1-I-frame-320x240"); + + AV1Parser parser; + ASSERT_TRUE(parser.Parse(buffer.data(), buffer.size())); +} + +} // namespace media +} // namespace shaka diff --git a/packager/media/codecs/codecs.gyp b/packager/media/codecs/codecs.gyp index 44d2b329b18..d8978925da4 100644 --- a/packager/media/codecs/codecs.gyp +++ b/packager/media/codecs/codecs.gyp @@ -19,6 +19,8 @@ 'ac3_audio_util.h', 'av1_codec_configuration_record.cc', 'av1_codec_configuration_record.h', + 'av1_parser.cc', + 'av1_parser.h', 'avc_decoder_configuration_record.cc', 'avc_decoder_configuration_record.h', 'decoder_configuration_record.cc', @@ -69,6 +71,7 @@ 'aac_audio_specific_config_unittest.cc', 'ac3_audio_util_unittest.cc', 'av1_codec_configuration_record_unittest.cc', + 'av1_parser_unittest.cc', 'avc_decoder_configuration_record_unittest.cc', 'ec3_audio_util_unittest.cc', 'es_descriptor_unittest.cc', diff --git a/packager/media/test/data/av1-I-frame-320x240 b/packager/media/test/data/av1-I-frame-320x240 new file mode 100644 index 0000000000000000000000000000000000000000..64c26ef288483fb2150e8001b2e93e173d479df3 GIT binary patch literal 1278 zcmVFi`V%~f$L0Ko}Wbs_h1P4YN#TE3FAe7EjoWiJD$}z1D zTT{P1=?RW6F=8A45QM*by)<({U>gm~^Zp-S`3DT|BVTaZ3zZYiVE_@n^!(M0*=(iq z9LvOfW(ZPqrJMYR07PwoCN%l^ylq-=dl?M`jbUP8twt0>cL8VIkNn zA&dkCcsQb-?gS#ymRAz?;jO7eg!pVS?ry<1mP4<60!tXx>rKkiN$8_ub!4qj-d~PR zVLJ_;GpAb72)<+fGzWp76Rqz(|k8nw*Jud5vYI{DV+eCX@;oqNsO&Mc(laGDhr3Qc~^ zhPxjcdNjI*cs`t-ZuCb@`u*vefuQu$j&A+eqF-$!a`3>2#tYEfMTJPrEkTm@ z$7DK{B)dEh>FJ4#g42&y73r^iQ>-drI)&=~hV2C54dK8*djMyQ=t0~Nmhkdb|kBofQmAWTPQPdhQcKj zZb9P;_rV$C{lZV~$WBP3RkHS%dI4oyMpOPNXN^}`Qk|i4^;)uUlAx*DU6lgQMZea6 z&G9%3U4a&Iqo&cmb^&&hqI&Ywc(zr3QxLyC)a_lFXK0b(Qq&1b*%{mdZu~VLyNIt= zxn@QKn;5<5`1|77j2{61T^84BG4(Nfm5QLOoQRPpTZp~jKyldNwD|iMoUlDEBLI%* z1@I`SAx4RkplHRl-3RC8k~ID3)}(N~GLBqb7he7yP5)Yjx;qEsbqLnz&th`KzU{7O z9Qh|dIi_twXw&}+>pr7%5Tb+jd^C$waRSOqQ3hC2WB?Mo?!K8OP;>$f0)CjqV+^F< z5SSdsf{Bn3EopbRv$Jd4NvC6Bhd);Do!6FaumZ1b@S;_9VF#i1>{opWEQ`vlCr@1O z@*JlBI3bMPk