2018-08-28 00:54:42 +00:00
|
|
|
// 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
|
|
|
|
|
2023-10-10 23:51:11 +00:00
|
|
|
#include <packager/media/codecs/av1_parser.h>
|
2018-08-28 00:54:42 +00:00
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
2023-10-13 19:42:47 +00:00
|
|
|
#include <absl/log/check.h>
|
|
|
|
#include <absl/log/log.h>
|
2023-10-11 08:49:50 +00:00
|
|
|
|
2023-10-14 16:36:01 +00:00
|
|
|
#include <packager/macros/logging.h>
|
2023-10-10 23:51:11 +00:00
|
|
|
#include <packager/media/base/bit_reader.h>
|
|
|
|
#include <packager/media/base/rcheck.h>
|
2018-08-28 00:54:42 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-10-09 17:41:18 +00:00
|
|
|
bool AV1Parser::Parse(const uint8_t* data,
|
|
|
|
size_t data_size,
|
|
|
|
std::vector<Tile>* tiles) {
|
|
|
|
tiles->clear();
|
|
|
|
|
2018-08-28 00:54:42 +00:00
|
|
|
BitReader reader(data, data_size);
|
|
|
|
while (reader.bits_available() > 0) {
|
2018-10-09 17:41:18 +00:00
|
|
|
if (!ParseOpenBitstreamUnit(&reader, tiles))
|
2018-08-28 00:54:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5.3.1. General OBU syntax.
|
2018-10-09 17:41:18 +00:00
|
|
|
bool AV1Parser::ParseOpenBitstreamUnit(BitReader* reader,
|
|
|
|
std::vector<Tile>* tiles) {
|
2018-08-28 00:54:42 +00:00
|
|
|
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:
|
2018-10-09 17:41:18 +00:00
|
|
|
RCHECK(ParseTileGroupObu(obu_size, reader, tiles));
|
2018-08-28 00:54:42 +00:00
|
|
|
break;
|
|
|
|
case OBU_FRAME:
|
2018-10-09 17:41:18 +00:00
|
|
|
RCHECK(ParseFrameObu(obu_header, obu_size, reader, tiles));
|
2018-08-28 00:54:42 +00:00
|
|
|
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,
|
2022-12-16 00:53:36 +00:00
|
|
|
int /*ref*/,
|
2018-08-28 00:54:42 +00:00
|
|
|
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,
|
2018-10-09 17:41:18 +00:00
|
|
|
BitReader* reader,
|
|
|
|
std::vector<Tile>* tiles) {
|
2018-08-28 00:54:42 +00:00
|
|
|
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;
|
2018-10-09 17:41:18 +00:00
|
|
|
RCHECK(ParseTileGroupObu(size - header_bytes, reader, tiles));
|
2018-08-28 00:54:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5.11.1. General tile group OBU syntax.
|
2018-10-09 17:41:18 +00:00
|
|
|
bool AV1Parser::ParseTileGroupObu(size_t size,
|
|
|
|
BitReader* reader,
|
|
|
|
std::vector<Tile>* tiles) {
|
2018-08-28 00:54:42 +00:00
|
|
|
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;
|
|
|
|
}
|
2018-10-09 17:41:18 +00:00
|
|
|
tiles->push_back({reader->bit_position() / 8, tile_size});
|
2018-08-28 00:54:42 +00:00
|
|
|
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,
|
|
|
|
};
|
2022-12-16 00:53:36 +00:00
|
|
|
static_assert(std::size(kRefFrameList) == kRefsPerFrame - 2,
|
2018-08-28 00:54:42 +00:00
|
|
|
"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
|