// Copyright 2021 The libgav1 Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/obu_parser.h" #include #include #include #include #include #include #include #include #include "gtest/gtest.h" #include "src/buffer_pool.h" #include "src/decoder_impl.h" #include "src/decoder_state.h" #include "src/gav1/decoder_buffer.h" #include "src/gav1/status_code.h" #include "src/utils/common.h" #include "src/utils/constants.h" #include "src/utils/dynamic_buffer.h" #include "src/utils/segmentation.h" #include "src/utils/types.h" #include "src/utils/vector.h" #include "tests/third_party/libvpx/acm_random.h" // Note the following test classes access private functions/members of // ObuParser. To be declared friends of ObuParser they must not have internal // linkage (they must be outside the anonymous namespace). namespace libgav1 { // Helper class to manipulate individual bits and generate a byte string. class BytesAndBits { public: // Append a bit to the end. void AppendBit(uint8_t bit) { bits_.push_back(bit != 0); } // Append a byte to the end. void AppendByte(uint8_t byte) { for (int i = 0; i < 8; ++i) { AppendBit(GetNthBit(byte, i, 8)); } } // Append a literal of size |bits| to the end. void AppendLiteral(int bits, int value) { InsertLiteral(static_cast(bits_.size()), bits, value); } // Append an inverse signed literal to the end. |bits + 1| bits are appended. void AppendInverseSignedLiteral(int bits, int value) { InsertInverseSignedLiteral(static_cast(bits_.size()), bits, value); } // Append a sequence of bytes to the end. void AppendBytes(const std::vector& bytes) { for (const auto& byte : bytes) { AppendByte(byte); } } // Insert |bit| in |offset|. Moves all other bits to the right by 1. void InsertBit(int offset, uint8_t bit) { auto iterator = bits_.begin(); bits_.insert(iterator + offset, bit != 0); } // Insert |value| of size |bits| at offset |offset|. Moves all other bits to // the right by |bits|. void InsertLiteral(int offset, int bits, int value) { for (int i = 0; i < bits; ++i) { InsertBit(i + offset, GetNthBit(value, i, bits)); } } // Insert |value| of size |bits| at offset |offset| as an inverse signed // literal. Move all other bits to the right by |bits + 1|. // // Note: This is denoted su(1+bits) in the spec. void InsertInverseSignedLiteral(int offset, int bits, int value) { InsertBit(offset, (value >= 0) ? 0 : 1); InsertLiteral(offset + 1, bits, value); } // Insert |value| at |offset| as an unsigned variable length code (uvlc). // Return the number of bits inserted. int InsertUvlc(int offset, int value) { int leading_zeros = 1; int shift_value = ++value; while ((shift_value >>= 1) != 0) leading_zeros += 2; int bits = 0; InsertLiteral(offset, leading_zeros >> 1, 0); bits += leading_zeros >> 1; InsertLiteral(offset + bits, (leading_zeros + 1) >> 1, value); bits += (leading_zeros + 1) >> 1; return bits; } // Set the bit at |offset| to |bit|. The bit should already exist. void SetBit(int offset, uint8_t bit) { bits_[offset] = bit != 0; } // Set |bits| starting at |offset| to |value|. The bits should already exist. void SetLiteral(int offset, int bits, int value) { for (int i = 0; i < bits; ++i) { SetBit(offset + i, GetNthBit(value, i, bits)); } } // Remove a bit in |offset|. Moves over all the following bits to the left by // 1. void RemoveBit(int offset) { RemoveLiteral(offset, 1); } // Remove a literal of size |bits| from |offset|. Moves over all the // following bits to the left by |bits|. void RemoveLiteral(int offset, int bits) { bits_.erase(bits_.begin() + offset, bits_.begin() + offset + bits); } // Remove all bits after offset. void RemoveAllBitsAfter(int offset) { RemoveLiteral(offset, static_cast(bits_.size()) - offset); } // Clear all the bits stored. void Clear() { bits_.clear(); } // Generate the data vector from the bits. Pads 0 to the end of the last byte // if necessary. const std::vector& GenerateData() { data_.clear(); for (size_t i = 0; i < bits_.size(); i += 8) { uint8_t byte = 0; for (int j = 0; j < 8; ++j) { const uint8_t bit = ((i + j) < bits_.size()) ? static_cast(bits_[i + j]) : 0; byte |= bit << (7 - j); } data_.push_back(byte); } return data_; } private: // Get the |n|th MSB from |value| with the assumption that |value| has |size| // bits. static uint8_t GetNthBit(int value, int n, int size) { return (value >> (size - n - 1)) & 0x01; } std::vector data_; std::vector bits_; }; class ObuParserTest : public testing::Test { protected: // Constants for unit tests. static constexpr int kFrameWidthBits = 9; static constexpr int kFrameHeightBits = 8; static constexpr int kHeight = 240; static constexpr int kWidth = 426; static constexpr int kRows4x4 = 60; static constexpr int kColumns4x4 = 108; static constexpr int kFrameToShow = 2; static constexpr int kDisplayFrameId = 10; static constexpr int kFrameIdLengthBits = 15; static constexpr int kDeltaFrameIdLengthBits = 14; // Bit streams for testing. These may contain trailing bits and tests may have // to remove some of the trailing bits to keep the boundary alignment. const std::vector kDefaultTemporalDelimiter = {0x12, 0x00}; // Bits Syntax element Value // 1 obu_forbidden_bit 0 // 4 obu_type 2 (OBU_TEMPORAL_DELIMITER) // 1 obu_extension_flag 1 // 1 obu_has_size_field 1 // 1 obu_reserved_1bit 0 // 3 temporal_id 6 // 2 spatial_id 2 // 3 extension_header_reserved_3bits 0 // 8 obu_size 0 const std::vector kDefaultTemporalDelimiterWithExtension = { 0x16, 0xd0, 0x00}; const std::vector kDefaultHeaderWithoutSizeField = {0x10}; // Offset Bits Syntax element Value // 0 3 seq_profile 0 // 3 1 still_picture 0 // 4 1 reduced_still_picture_header 0 // 5 1 timing_info_present_flag 0 // 6 1 initial_display_delay_present_flag 0 // 7 5 operating_points_cnt_minus_1 0 // 12 12 operating_point_idc[ 0 ] 0 // 24 5 seq_level_idx[ 0 ] 0 // 29 4 frame_width_bits_minus_1 8 // 33 4 frame_height_bits_minus_1 7 // 37 9 max_frame_width_minus_1 425 // 46 8 max_frame_height_minus_1 239 // 54 1 frame_id_numbers_present_flag 0 // 55 1 use_128x128_superblock 1 // 56 1 enable_filter_intra 1 // 57 1 enable_intra_edge_filter 1 // 58 1 enable_interintra_compound 1 // 59 1 enable_masked_compound 1 // 60 1 enable_warped_motion 0 // 61 1 enable_dual_filter 1 // 62 1 enable_order_hint 1 // 63 1 enable_jnt_comp 1 // 64 1 enable_ref_frame_mvs 1 // 65 1 seq_choose_screen_content_tools 1 // 66 1 seq_choose_integer_mv 1 // 67 3 order_hint_bits_minus_1 6 // 70 1 enable_superres 0 // 71 1 enable_cdef 1 // 72 1 enable_restoration 1 // ... const std::vector kDefaultSequenceHeader = { 0x00, 0x00, 0x00, 0x04, 0x3e, 0xa7, 0xbd, 0xf7, 0xf9, 0x80, 0x40}; const std::vector kDefaultFrameHeaderKeyFrame = {0x10, 0x00}; // Bits Syntax element Value // 1 show_existing_frame 0 // 2 frame_type 2 (kFrameIntraOnly) // 1 show_frame 1 // 1 error_resilient_mode 0 // 1 disable_cdf_update 0 // 1 frame_size_override_flag 0 // 8 refresh_frame_flags 4 // ... const std::vector kDefaultFrameHeaderIntraOnlyFrame = {0x50, 0x08, 0x00}; // Bits Syntax element Value // 1 show_existing_frame 0 // 2 frame_type 1 (kFrameInter) // 1 show_frame 1 // 1 error_resilient_mode 0 // 1 disable_cdf_update 0 // 1 frame_size_override_flag 0 // 3 primary_ref_frame 1 // 8 refresh_frame_flags 4 // 3 ref_frame_idx[0] 0 // 3 ref_frame_idx[1] 1 // 3 ref_frame_idx[2] 2 // 3 ref_frame_idx[3] 3 // 3 ref_frame_idx[4] 4 // 3 ref_frame_idx[5] 5 // 3 ref_frame_idx[6] 6 // ... const std::vector kDefaultFrameHeaderInterFrame = {0x30, 0x41, 0x01, 0x4e, 0x5c, 0x60}; const std::vector kDefaultGlobalMotionParametersRotZoom = { 0xff, 0x50, 0x77, 0x7e, 0x1f, 0xcd}; const std::vector kDefaultGlobalMotionParametersAffine = { 0x3f, 0x50, 0x77, 0x7b, 0xbf, 0xa8, 0x3e, 0x1f, 0xcd}; void SetUp() override { buffer_pool_.reset(new (std::nothrow) BufferPool(nullptr, nullptr, nullptr, nullptr)); ASSERT_NE(buffer_pool_, nullptr); } bool Init() { obu_.reset(new (std::nothrow) ObuParser(nullptr, 0, 0, buffer_pool_.get(), &decoder_state_)); if (obu_ == nullptr) return false; obu_headers_ = &obu_->obu_headers_; obu_frame_header_ = &obu_->frame_header_; obu_sequence_header_ = &obu_->sequence_header_; return true; } bool Init(const std::vector& data, bool init_bit_reader = true) { obu_.reset(new (std::nothrow) ObuParser( data.data(), data.size(), 0, buffer_pool_.get(), &decoder_state_)); if (obu_ == nullptr) return false; obu_headers_ = &obu_->obu_headers_; obu_frame_header_ = &obu_->frame_header_; obu_sequence_header_ = &obu_->sequence_header_; return init_bit_reader ? obu_->InitBitReader(data.data(), data.size()) : true; } bool Parse(const std::string& input, const ObuSequenceHeader* const sequence_header = nullptr) { std::vector data(input.begin(), input.end()); return Parse(data, sequence_header); } bool Parse(const std::vector& data, const ObuSequenceHeader* const sequence_header = nullptr) { EXPECT_TRUE(Init(data, false)); if (sequence_header != nullptr) obu_->set_sequence_header(*sequence_header); return obu_->ParseOneFrame(¤t_frame_) == kStatusOk; } bool ParseSequenceHeader(const std::vector& data) { EXPECT_TRUE(Init(data)); return obu_->ParseSequenceHeader(/*seen_frame_header=*/false); } bool ParseFrameParameters(const std::vector& data, bool id_bits_present = false, int force_screen_content_tools = 0, int force_integer_mv = 0, bool enable_superres = false) { EXPECT_TRUE(Init(data)); if (id_bits_present) { obu_->sequence_header_.frame_id_numbers_present = true; obu_->sequence_header_.frame_id_length_bits = kFrameIdLengthBits; obu_->sequence_header_.delta_frame_id_length_bits = kDeltaFrameIdLengthBits; } obu_->sequence_header_.force_screen_content_tools = force_screen_content_tools; obu_->sequence_header_.force_integer_mv = force_integer_mv; obu_->sequence_header_.enable_superres = enable_superres; obu_->sequence_header_.frame_width_bits = kFrameWidthBits; obu_->sequence_header_.frame_height_bits = kFrameHeightBits; obu_->sequence_header_.max_frame_width = kWidth; obu_->sequence_header_.max_frame_height = kHeight; return obu_->ParseFrameParameters(); } bool ParseSegmentationParameters(const std::vector& data, int primary_reference_frame, int prev_frame_index) { EXPECT_TRUE(Init(data)); obu_->frame_header_.primary_reference_frame = primary_reference_frame; if (primary_reference_frame != kPrimaryReferenceNone) { obu_->frame_header_.reference_frame_index[primary_reference_frame] = prev_frame_index; } return obu_->ParseSegmentationParameters(); } bool ParseFrameReferenceModeSyntax(const std::vector& data, FrameType frame_type) { EXPECT_TRUE(Init(data)); obu_->frame_header_.frame_type = frame_type; return obu_->ParseFrameReferenceModeSyntax(); } bool ParseGlobalMotionParameters(const std::vector& data, FrameType frame_type) { EXPECT_TRUE(Init(data)); obu_->frame_header_.frame_type = frame_type; obu_->frame_header_.primary_reference_frame = kPrimaryReferenceNone; return obu_->ParseGlobalMotionParameters(); } bool ParseFilmGrainParameters(const std::vector& data, const ObuSequenceHeader& sequence_header, const ObuFrameHeader& frame_header) { EXPECT_TRUE(Init(data)); obu_->set_sequence_header(sequence_header); obu_->frame_header_ = frame_header; return obu_->ParseFilmGrainParameters(); } bool ParseTileInfoSyntax(const std::vector& data, int columns4x4, int rows4x4, bool use_128x128_superblock) { EXPECT_TRUE(Init(data)); obu_->frame_header_.columns4x4 = columns4x4; obu_->frame_header_.rows4x4 = rows4x4; obu_->sequence_header_.use_128x128_superblock = use_128x128_superblock; return obu_->ParseTileInfoSyntax(); } bool ParseMetadata(const std::vector& data) { EXPECT_TRUE(Init(data)); return obu_->ParseMetadata(data.data(), data.size()); } void DefaultSequenceHeader(ObuSequenceHeader* const gold) { memset(gold, 0, sizeof(*gold)); gold->profile = kProfile0; gold->level[0].major = kMinimumMajorBitstreamLevel; gold->operating_points = 1; gold->max_frame_width = kWidth; gold->max_frame_height = kHeight; gold->frame_width_bits = kFrameWidthBits; gold->frame_height_bits = kFrameHeightBits; gold->use_128x128_superblock = true; gold->enable_filter_intra = true; gold->enable_intra_edge_filter = true; gold->enable_interintra_compound = true; gold->enable_masked_compound = true; gold->enable_dual_filter = true; gold->enable_order_hint = true; gold->enable_jnt_comp = true; gold->enable_ref_frame_mvs = true; gold->choose_screen_content_tools = true; gold->force_screen_content_tools = 2; gold->choose_integer_mv = true; gold->force_integer_mv = 2; gold->order_hint_bits = 7; gold->enable_cdef = true; gold->enable_restoration = true; gold->color_config.bitdepth = 8; gold->color_config.color_primary = kColorPrimaryUnspecified; gold->color_config.transfer_characteristics = kTransferCharacteristicsUnspecified; gold->color_config.matrix_coefficients = kMatrixCoefficientsUnspecified; gold->color_config.subsampling_x = 1; gold->color_config.subsampling_y = 1; } void DefaultFrameHeader(ObuFrameHeader* const gold, FrameType frame_type) { memset(gold, 0, sizeof(*gold)); gold->frame_type = frame_type; gold->show_frame = true; gold->showable_frame = (frame_type != kFrameKey); gold->enable_cdf_update = true; gold->width = kWidth; gold->height = kHeight; gold->render_width = kWidth; gold->render_height = kHeight; gold->upscaled_width = kWidth; gold->primary_reference_frame = kPrimaryReferenceNone; gold->enable_frame_end_update_cdf = true; gold->rows4x4 = kRows4x4; gold->columns4x4 = kColumns4x4; if (frame_type == kFrameKey) { gold->refresh_frame_flags = 0xff; gold->error_resilient_mode = true; gold->force_integer_mv = 1; } else if (frame_type == kFrameIntraOnly) { gold->refresh_frame_flags = 4; gold->force_integer_mv = 1; } else if (frame_type == kFrameInter) { gold->refresh_frame_flags = 4; gold->primary_reference_frame = 1; for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { gold->reference_frame_index[i] = i; } gold->is_motion_mode_switchable = true; } } void OverrideFrameSize(BytesAndBits* const data, ObuFrameHeader* const gold, int flag_offset, int size_offset) { data->SetBit(flag_offset, 1); // frame_size_override_flag. data->InsertLiteral(size_offset, kFrameWidthBits, kWidth - 2); // frame_width_minus_1. data->InsertLiteral(size_offset + kFrameWidthBits, kFrameHeightBits, kHeight - 2); // frame_height_minus_1. gold->frame_size_override_flag = true; gold->width = kWidth - 1; gold->height = kHeight - 1; gold->render_width = gold->width; gold->render_height = gold->height; gold->upscaled_width = gold->width; } void OverrideRenderSize(BytesAndBits* const data, ObuFrameHeader* const gold, int flag_offset) { data->SetBit(flag_offset, 1); // render_and_frame_size_different. data->InsertLiteral(flag_offset + 1, 16, kWidth - 10); // render_width_minus_1. data->InsertLiteral(flag_offset + 17, 16, kHeight - 10); // render_height_minus_1. gold->render_width = kWidth - 9; gold->render_height = kHeight - 9; gold->render_and_frame_size_different = true; } void OverrideSegmentation(BytesAndBits* const data, Segmentation* const gold, int offset) { gold->update_data = true; data->SetBit(offset++, static_cast(gold->update_data)); libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); gold->segment_id_pre_skip = false; gold->last_active_segment_id = 0; for (int i = 0; i < kMaxSegments; ++i) { for (int j = 0; j < kSegmentFeatureMax; ++j) { gold->feature_enabled[i][j] = static_cast(rnd.Rand8() & 1); data->InsertBit(offset++, static_cast(gold->feature_enabled[i][j])); if (gold->feature_enabled[i][j]) { gold->feature_data[i][j] = rnd(1 << kSegmentationFeatureBits[j]); if (Segmentation::FeatureSigned(static_cast(j))) { if (static_cast(rnd.Rand8() & 1)) { gold->feature_data[i][j] *= -1; } data->InsertInverseSignedLiteral( offset, kSegmentationFeatureBits[j], gold->feature_data[i][j]); offset += kSegmentationFeatureBits[j] + 1; } else { data->InsertLiteral(offset, kSegmentationFeatureBits[j], gold->feature_data[i][j]); offset += kSegmentationFeatureBits[j]; } gold->last_active_segment_id = i; if (j >= kSegmentFeatureReferenceFrame) { gold->segment_id_pre_skip = true; } } } } } void VerifyObuHeader(bool extension) { EXPECT_EQ(obu_->obu_headers().back().temporal_id, extension ? 6 : 0); EXPECT_EQ(obu_->obu_headers().back().spatial_id, extension ? 2 : 0); } #define OBU_TEST_COMPARE(x) EXPECT_EQ(expected.x, actual.x) void VerifyFrameParameters(const ObuFrameHeader& expected, bool id_bits_present = false) { const ObuFrameHeader& actual = obu_->frame_header(); OBU_TEST_COMPARE(show_existing_frame); if (actual.show_existing_frame) { OBU_TEST_COMPARE(frame_to_show); OBU_TEST_COMPARE(frame_presentation_time); if (id_bits_present) { OBU_TEST_COMPARE(display_frame_id); } return; } OBU_TEST_COMPARE(frame_type); OBU_TEST_COMPARE(show_frame); OBU_TEST_COMPARE(frame_presentation_time); OBU_TEST_COMPARE(showable_frame); OBU_TEST_COMPARE(error_resilient_mode); OBU_TEST_COMPARE(enable_cdf_update); OBU_TEST_COMPARE(current_frame_id); OBU_TEST_COMPARE(frame_size_override_flag); OBU_TEST_COMPARE(order_hint); for (int i = 0; i < kNumReferenceFrameTypes; ++i) { OBU_TEST_COMPARE(reference_order_hint[i]); } OBU_TEST_COMPARE(primary_reference_frame); OBU_TEST_COMPARE(width); OBU_TEST_COMPARE(height); OBU_TEST_COMPARE(render_and_frame_size_different); OBU_TEST_COMPARE(render_width); OBU_TEST_COMPARE(render_height); OBU_TEST_COMPARE(upscaled_width); OBU_TEST_COMPARE(coded_lossless); OBU_TEST_COMPARE(upscaled_lossless); OBU_TEST_COMPARE(allow_screen_content_tools); OBU_TEST_COMPARE(is_motion_mode_switchable); OBU_TEST_COMPARE(refresh_frame_flags); OBU_TEST_COMPARE(enable_frame_end_update_cdf); OBU_TEST_COMPARE(force_integer_mv); if (actual.frame_type == kFrameInter) { for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { OBU_TEST_COMPARE(reference_frame_index[i]); } } OBU_TEST_COMPARE(use_superres); OBU_TEST_COMPARE(rows4x4); OBU_TEST_COMPARE(columns4x4); } void VerifyLoopFilterParameters(const LoopFilter& expected) { const LoopFilter& actual = obu_->frame_header().loop_filter; for (int i = 0; i < 4; ++i) { OBU_TEST_COMPARE(level[i]); } OBU_TEST_COMPARE(sharpness); OBU_TEST_COMPARE(delta_enabled); OBU_TEST_COMPARE(delta_update); for (int i = 0; i < kNumReferenceFrameTypes; ++i) { OBU_TEST_COMPARE(ref_deltas[i]); } for (int i = 0; i < kLoopFilterMaxModeDeltas; ++i) { OBU_TEST_COMPARE(mode_deltas[i]); } } void VerifyQuantizerParameters(const QuantizerParameters& expected) { const QuantizerParameters& actual = obu_->frame_header().quantizer; OBU_TEST_COMPARE(base_index); OBU_TEST_COMPARE(delta_dc[kPlaneY]); OBU_TEST_COMPARE(delta_dc[kPlaneU]); OBU_TEST_COMPARE(delta_dc[kPlaneV]); EXPECT_EQ(0, actual.delta_ac[kPlaneY]); OBU_TEST_COMPARE(delta_ac[kPlaneY]); OBU_TEST_COMPARE(delta_ac[kPlaneU]); OBU_TEST_COMPARE(delta_ac[kPlaneV]); OBU_TEST_COMPARE(use_matrix); OBU_TEST_COMPARE(matrix_level[kPlaneY]); OBU_TEST_COMPARE(matrix_level[kPlaneU]); OBU_TEST_COMPARE(matrix_level[kPlaneV]); } void VerifySegmentationParameters(const Segmentation& expected) { const Segmentation& actual = obu_->frame_header().segmentation; OBU_TEST_COMPARE(enabled); OBU_TEST_COMPARE(update_map); OBU_TEST_COMPARE(update_data); OBU_TEST_COMPARE(temporal_update); OBU_TEST_COMPARE(segment_id_pre_skip); OBU_TEST_COMPARE(last_active_segment_id); for (int i = 0; i < kMaxSegments; ++i) { for (int j = 0; j < kSegmentFeatureMax; ++j) { OBU_TEST_COMPARE(feature_enabled[i][j]); OBU_TEST_COMPARE(feature_data[i][j]); } } } void VerifyDeltaParameters(const Delta& expected, const Delta& actual) { OBU_TEST_COMPARE(present); OBU_TEST_COMPARE(scale); OBU_TEST_COMPARE(multi); } void VerifyCdefParameters(const Cdef& expected) { const Cdef& actual = obu_->frame_header().cdef; OBU_TEST_COMPARE(damping); OBU_TEST_COMPARE(bits); for (int i = 0; i < (1 << actual.bits); ++i) { OBU_TEST_COMPARE(y_primary_strength[i]); OBU_TEST_COMPARE(y_secondary_strength[i]); OBU_TEST_COMPARE(uv_primary_strength[i]); OBU_TEST_COMPARE(uv_secondary_strength[i]); } } void VerifyLoopRestorationParameters(const LoopRestoration& expected) { const LoopRestoration& actual = obu_->frame_header().loop_restoration; for (int i = 0; i < kMaxPlanes; ++i) { OBU_TEST_COMPARE(type[i]); OBU_TEST_COMPARE(unit_size_log2[i]); } } void VerifyGlobalMotionParameters( const std::array& gold) { for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) { const GlobalMotion& expected = gold[i]; const GlobalMotion& actual = obu_->frame_header().global_motion[i]; OBU_TEST_COMPARE(type) << " i: " << i; for (int j = 0; j < 6; ++j) { OBU_TEST_COMPARE(params[j]) << " i: " << i << " j: " << j; } } } void VerifyFilmGrainParameters(const FilmGrainParams& expected) { const FilmGrainParams& actual = obu_->frame_header().film_grain_params; OBU_TEST_COMPARE(apply_grain); OBU_TEST_COMPARE(update_grain); OBU_TEST_COMPARE(chroma_scaling_from_luma); OBU_TEST_COMPARE(overlap_flag); OBU_TEST_COMPARE(clip_to_restricted_range); OBU_TEST_COMPARE(num_y_points); OBU_TEST_COMPARE(num_u_points); OBU_TEST_COMPARE(num_v_points); for (int i = 0; i < 14; ++i) { OBU_TEST_COMPARE(point_y_value[i]); OBU_TEST_COMPARE(point_y_scaling[i]); } for (int i = 0; i < 10; ++i) { OBU_TEST_COMPARE(point_u_value[i]); OBU_TEST_COMPARE(point_u_scaling[i]); } for (int i = 0; i < 10; ++i) { OBU_TEST_COMPARE(point_v_value[i]); OBU_TEST_COMPARE(point_v_scaling[i]); } OBU_TEST_COMPARE(chroma_scaling); OBU_TEST_COMPARE(auto_regression_coeff_lag); for (int i = 0; i < 24; ++i) { OBU_TEST_COMPARE(auto_regression_coeff_y[i]); } for (int i = 0; i < 25; ++i) { OBU_TEST_COMPARE(auto_regression_coeff_u[i]); } for (int i = 0; i < 25; ++i) { OBU_TEST_COMPARE(auto_regression_coeff_v[i]); } OBU_TEST_COMPARE(auto_regression_shift); OBU_TEST_COMPARE(grain_seed); OBU_TEST_COMPARE(reference_index); OBU_TEST_COMPARE(grain_scale_shift); OBU_TEST_COMPARE(u_multiplier); OBU_TEST_COMPARE(u_luma_multiplier); OBU_TEST_COMPARE(u_offset); OBU_TEST_COMPARE(v_multiplier); OBU_TEST_COMPARE(v_luma_multiplier); OBU_TEST_COMPARE(v_offset); } void VerifyTileInfoParameters(const TileInfo& expected) { const TileInfo& actual = obu_->frame_header().tile_info; OBU_TEST_COMPARE(uniform_spacing); OBU_TEST_COMPARE(tile_columns_log2); OBU_TEST_COMPARE(tile_columns); for (int i = 0; i < kMaxTileColumns + 1; ++i) { OBU_TEST_COMPARE(tile_column_start[i]) << "tile_column: " << i; OBU_TEST_COMPARE(tile_column_width_in_superblocks[i]) << "tile_column: " << i; } OBU_TEST_COMPARE(tile_rows_log2); OBU_TEST_COMPARE(tile_rows); for (int i = 0; i < kMaxTileRows + 1; ++i) { OBU_TEST_COMPARE(tile_row_start[i]) << "tile_row: " << i; OBU_TEST_COMPARE(tile_row_height_in_superblocks[i]) << "tile_rows: " << i; } OBU_TEST_COMPARE(tile_count); OBU_TEST_COMPARE(context_update_id); OBU_TEST_COMPARE(tile_size_bytes); } void VerifySequenceHeader(const ObuSequenceHeader& expected) { EXPECT_TRUE(obu_->sequence_header_changed()); const ObuSequenceHeader& actual = obu_->sequence_header(); OBU_TEST_COMPARE(profile); OBU_TEST_COMPARE(still_picture); OBU_TEST_COMPARE(reduced_still_picture_header); OBU_TEST_COMPARE(operating_points); for (int i = 0; i < actual.operating_points; ++i) { OBU_TEST_COMPARE(operating_point_idc[i]) << "i: " << i; OBU_TEST_COMPARE(level[i].major) << "i: " << i; OBU_TEST_COMPARE(level[i].minor) << "i: " << i; OBU_TEST_COMPARE(tier[i]) << "i: " << i; } OBU_TEST_COMPARE(frame_width_bits); OBU_TEST_COMPARE(frame_height_bits); OBU_TEST_COMPARE(max_frame_width); OBU_TEST_COMPARE(max_frame_height); OBU_TEST_COMPARE(frame_id_numbers_present); if (actual.frame_id_numbers_present) { OBU_TEST_COMPARE(frame_id_length_bits); OBU_TEST_COMPARE(delta_frame_id_length_bits); } OBU_TEST_COMPARE(use_128x128_superblock); OBU_TEST_COMPARE(enable_filter_intra); OBU_TEST_COMPARE(enable_intra_edge_filter); OBU_TEST_COMPARE(enable_interintra_compound); OBU_TEST_COMPARE(enable_masked_compound); OBU_TEST_COMPARE(enable_warped_motion); OBU_TEST_COMPARE(enable_dual_filter); OBU_TEST_COMPARE(enable_order_hint); OBU_TEST_COMPARE(enable_jnt_comp); OBU_TEST_COMPARE(enable_ref_frame_mvs); OBU_TEST_COMPARE(choose_screen_content_tools); OBU_TEST_COMPARE(force_screen_content_tools); OBU_TEST_COMPARE(choose_integer_mv); OBU_TEST_COMPARE(force_integer_mv); OBU_TEST_COMPARE(order_hint_bits); OBU_TEST_COMPARE(enable_superres); OBU_TEST_COMPARE(enable_cdef); OBU_TEST_COMPARE(enable_restoration); OBU_TEST_COMPARE(color_config.bitdepth); OBU_TEST_COMPARE(color_config.is_monochrome); OBU_TEST_COMPARE(color_config.color_range); OBU_TEST_COMPARE(color_config.subsampling_x); OBU_TEST_COMPARE(color_config.subsampling_y); OBU_TEST_COMPARE(color_config.chroma_sample_position); OBU_TEST_COMPARE(timing_info_present_flag); OBU_TEST_COMPARE(timing_info.num_units_in_tick); OBU_TEST_COMPARE(timing_info.time_scale); OBU_TEST_COMPARE(timing_info.equal_picture_interval); OBU_TEST_COMPARE(timing_info.num_ticks_per_picture); OBU_TEST_COMPARE(decoder_model_info_present_flag); OBU_TEST_COMPARE(decoder_model_info.encoder_decoder_buffer_delay_length); OBU_TEST_COMPARE(decoder_model_info.num_units_in_decoding_tick); OBU_TEST_COMPARE(decoder_model_info.buffer_removal_time_length); OBU_TEST_COMPARE(decoder_model_info.frame_presentation_time_length); for (int i = 0; i < actual.operating_points; ++i) { SCOPED_TRACE("i: " + std::to_string(i)); OBU_TEST_COMPARE(operating_parameters.decoder_buffer_delay[i]); OBU_TEST_COMPARE(operating_parameters.encoder_buffer_delay[i]); OBU_TEST_COMPARE(operating_parameters.low_delay_mode_flag[i]); OBU_TEST_COMPARE(initial_display_delay[i]); } OBU_TEST_COMPARE(film_grain_params_present); } void VerifyMetadataHdrCll(const ObuMetadataHdrCll& expected) { EXPECT_TRUE(obu_->current_frame_->hdr_cll_set()); const ObuMetadataHdrCll& actual = obu_->current_frame_->hdr_cll(); OBU_TEST_COMPARE(max_cll); OBU_TEST_COMPARE(max_fall); } void VerifyMetadataHdrMdcv(const ObuMetadataHdrMdcv& expected) { EXPECT_TRUE(obu_->current_frame_->hdr_mdcv_set()); const ObuMetadataHdrMdcv& actual = obu_->current_frame_->hdr_mdcv(); for (int i = 0; i < 3; ++i) { OBU_TEST_COMPARE(primary_chromaticity_x[i]); OBU_TEST_COMPARE(primary_chromaticity_y[i]); } OBU_TEST_COMPARE(white_point_chromaticity_x); OBU_TEST_COMPARE(white_point_chromaticity_y); OBU_TEST_COMPARE(luminance_max); OBU_TEST_COMPARE(luminance_min); } void VerifyMetadataItutT35(const ObuMetadataItutT35& expected) { EXPECT_TRUE(obu_->current_frame_->itut_t35_set()); const ObuMetadataItutT35& actual = obu_->current_frame_->itut_t35(); OBU_TEST_COMPARE(country_code); if (actual.country_code == 0xFF) { OBU_TEST_COMPARE(country_code_extension_byte); } ASSERT_EQ(expected.payload_size, actual.payload_size); if (actual.payload_size != 0) { EXPECT_EQ(memcmp(expected.payload_bytes, actual.payload_bytes, actual.payload_size), 0); } } #undef OBU_TEST_COMPARE // Accessors to private members of ObuParser. This avoids the need for a // dependency on a googletest header in the main library for FRIEND_TEST() // (or the need to duplicate the implementation). bool ObuParseFrameParameters() { return obu_->ParseFrameParameters(); } bool ObuParseLoopFilterParameters() { return obu_->ParseLoopFilterParameters(); } bool ObuParseLoopFilterDeltaParameters() { return obu_->ParseLoopFilterDeltaParameters(); } bool ObuParseQuantizerParameters() { return obu_->ParseQuantizerParameters(); } bool ObuParseQuantizerIndexDeltaParameters() { return obu_->ParseQuantizerIndexDeltaParameters(); } void ObuComputeSegmentLosslessAndQIndex() { obu_->ComputeSegmentLosslessAndQIndex(); } bool ObuParseCdefParameters() { return obu_->ParseCdefParameters(); } bool ObuParseLoopRestorationParameters() { return obu_->ParseLoopRestorationParameters(); } bool ObuParseTxModeSyntax() { return obu_->ParseTxModeSyntax(); } bool ObuIsSkipModeAllowed() { return obu_->IsSkipModeAllowed(); } bool ObuParseSkipModeParameters() { return obu_->ParseSkipModeParameters(); } bool ObuReadAllowWarpedMotion() { return obu_->ReadAllowWarpedMotion(); } bool ObuSetFrameReferences(int8_t last_frame_idx, int8_t gold_frame_idx) { return obu_->SetFrameReferences(last_frame_idx, gold_frame_idx); } std::unique_ptr buffer_pool_; DecoderState decoder_state_; std::unique_ptr obu_; // The following members are reset with each Init(). Vector* obu_headers_; ObuFrameHeader* obu_frame_header_; ObuSequenceHeader* obu_sequence_header_; RefCountedBufferPtr current_frame_; }; TEST_F(ObuParserTest, InvalidInputs) { obu_.reset(new (std::nothrow) ObuParser(nullptr, 0, 0, buffer_pool_.get(), &decoder_state_)); EXPECT_EQ(obu_->ParseOneFrame(¤t_frame_), kStatusInvalidArgument); obu_.reset(new (std::nothrow) ObuParser(nullptr, 10, 0, buffer_pool_.get(), &decoder_state_)); EXPECT_EQ(obu_->ParseOneFrame(¤t_frame_), kStatusInvalidArgument); obu_.reset(new (std::nothrow) ObuParser(kDefaultTemporalDelimiter.data(), 0, 0, buffer_pool_.get(), &decoder_state_)); EXPECT_EQ(obu_->ParseOneFrame(¤t_frame_), kStatusInvalidArgument); } TEST_F(ObuParserTest, TemporalDelimiter) { BytesAndBits data; data.AppendBytes(kDefaultTemporalDelimiter); ASSERT_TRUE(Parse(data.GenerateData())); EXPECT_EQ(obu_->obu_headers().size(), 1); EXPECT_EQ(obu_->obu_headers().back().type, kObuTemporalDelimiter); VerifyObuHeader(false); // forbidden_bit is not zero. data.SetBit(0, 1); EXPECT_FALSE(Parse(data.GenerateData())); } TEST_F(ObuParserTest, HeaderExtensions) { BytesAndBits data; data.AppendBytes(kDefaultTemporalDelimiterWithExtension); ASSERT_TRUE(Parse(data.GenerateData())); EXPECT_EQ(obu_->obu_headers().size(), 1); EXPECT_EQ(obu_->obu_headers().back().type, kObuTemporalDelimiter); VerifyObuHeader(true); // extension flag is set but no extensions found. data.Clear(); data.AppendByte(kDefaultTemporalDelimiterWithExtension[0]); EXPECT_FALSE(Parse(data.GenerateData())); } TEST_F(ObuParserTest, HeaderHasSizeFieldNotSet) { BytesAndBits data; data.AppendBytes(kDefaultHeaderWithoutSizeField); EXPECT_FALSE(Parse(data.GenerateData())); } TEST_F(ObuParserTest, SequenceHeader) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderLevel) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); // Set level to 1. gold.level[0].major = 2; gold.level[0].minor = 1; data.SetLiteral(24, 5, 1); // level. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); // Set operating_point_idc of operating point 1 to 0x101 (temporal layer 0 // and spatial layer 0 should be decoded). Set level of operating point 1 to // 8 (4.0) and tier to 1. gold.operating_points = 2; gold.operating_point_idc[1] = (1 << 0) | (1 << (0 + 8)); gold.level[1].major = 4; gold.level[1].minor = 0; gold.tier[1] = 1; data.SetLiteral(7, 5, gold.operating_points - 1); data.InsertLiteral(29, 12, 0x101); // operating_point_idc. data.InsertLiteral(41, 5, 8); // level. data.InsertBit(46, gold.tier[1]); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderProfile) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.still_picture = true; data.SetBit(3, static_cast(gold.still_picture)); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); // profile 2; bitdepth 8; gold.profile = kProfile2; gold.color_config.bitdepth = 8; gold.color_config.subsampling_x = 1; gold.color_config.subsampling_y = 0; data.SetLiteral(0, 3, gold.profile); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); // profile 2; bitdepth 10; gold.color_config.bitdepth = 10; data.SetBit(73, 1); // high_bitdepth. data.InsertBit(74, 0); // twelve_bit. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); // profile 2; bitdepth 12; gold.color_config.bitdepth = 12; gold.color_config.subsampling_y = 1; data.SetBit(74, 1); // twelve_bit. data.InsertBit(78, 1); // subsampling_x. data.InsertBit(79, 1); // subsampling_y. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderIdLength) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.frame_id_numbers_present = true; gold.delta_frame_id_length_bits = kDeltaFrameIdLengthBits; gold.frame_id_length_bits = kFrameIdLengthBits; data.SetBit(54, 1); // frame_id_numbers_present. data.InsertLiteral(55, 4, kDeltaFrameIdLengthBits - 2); data.InsertLiteral(59, 3, kFrameIdLengthBits - kDeltaFrameIdLengthBits - 1); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } // An idLen greater than 16 is invalid. TEST_F(ObuParserTest, SequenceHeaderIdLengthInvalid) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); data.SetBit(54, 1); // frame_id_numbers_present. data.InsertLiteral(55, 4, kDeltaFrameIdLengthBits - 2); data.InsertLiteral(59, 3, 17 - kDeltaFrameIdLengthBits - 1); // idLen = 17. ASSERT_FALSE(ParseSequenceHeader(data.GenerateData())); } TEST_F(ObuParserTest, SequenceHeaderFlags) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.enable_warped_motion = true; gold.enable_superres = true; data.SetBit(60, 1); // enable_warped_motion. data.SetBit(70, 1); // enable_superres. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderForceScreenContentToolsEqualTo0) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.choose_screen_content_tools = false; gold.force_screen_content_tools = 0; gold.choose_integer_mv = false; gold.force_integer_mv = 2; data.SetBit(65, 0); // choose_screen_content_tools. data.SetBit(66, 0); // force_screen_content_tools. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderMonochrome) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.color_config.is_monochrome = true; gold.color_config.color_range = kColorRangeFull; data.SetBit(74, 1); // monochrome. data.InsertBit(76, 1); // color_range. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } // This tests TimingInfo, DecoderModelInfo and OperatingParameters. The test is // kind of long but it is the simplest way to test all three since they are // dependent on one another. TEST_F(ObuParserTest, SequenceHeaderTimingInfo) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.timing_info_present_flag = true; gold.timing_info.num_units_in_tick = 100; gold.timing_info.time_scale = 1000; gold.timing_info.equal_picture_interval = false; gold.decoder_model_info_present_flag = false; data.SetBit(5, static_cast(gold.timing_info_present_flag)); data.InsertLiteral(6, 32, gold.timing_info.num_units_in_tick); data.InsertLiteral(38, 32, gold.timing_info.time_scale); data.InsertBit(70, static_cast(gold.timing_info.equal_picture_interval)); data.InsertBit(71, static_cast(gold.decoder_model_info_present_flag)); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); gold.timing_info.equal_picture_interval = true; gold.timing_info.num_ticks_per_picture = 7; data.SetBit(70, static_cast(gold.timing_info.equal_picture_interval)); EXPECT_EQ(data.InsertUvlc(71, gold.timing_info.num_ticks_per_picture - 1), 5); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); gold.decoder_model_info_present_flag = true; gold.decoder_model_info.encoder_decoder_buffer_delay_length = 5; gold.decoder_model_info.num_units_in_decoding_tick = 1000; gold.decoder_model_info.buffer_removal_time_length = 18; gold.decoder_model_info.frame_presentation_time_length = 20; data.SetBit(76, static_cast(gold.decoder_model_info_present_flag)); data.InsertLiteral( 77, 5, gold.decoder_model_info.encoder_decoder_buffer_delay_length - 1); data.InsertLiteral(82, 32, gold.decoder_model_info.num_units_in_decoding_tick); data.InsertLiteral(114, 5, gold.decoder_model_info.buffer_removal_time_length - 1); data.InsertLiteral( 119, 5, gold.decoder_model_info.frame_presentation_time_length - 1); data.InsertBit(147, 0); // decoder_model_present_for_this_op. ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); gold.operating_parameters.decoder_buffer_delay[0] = 10; gold.operating_parameters.encoder_buffer_delay[0] = 20; gold.operating_parameters.low_delay_mode_flag[0] = true; data.SetBit(147, 1); // decoder_model_present_for_this_op. data.InsertLiteral( 148, gold.decoder_model_info.encoder_decoder_buffer_delay_length, gold.operating_parameters.decoder_buffer_delay[0]); data.InsertLiteral( 153, gold.decoder_model_info.encoder_decoder_buffer_delay_length, gold.operating_parameters.encoder_buffer_delay[0]); data.InsertBit(158, static_cast( gold.operating_parameters.low_delay_mode_flag[0])); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } TEST_F(ObuParserTest, SequenceHeaderInitialDisplayDelay) { BytesAndBits data; data.AppendBytes(kDefaultSequenceHeader); ObuSequenceHeader gold; DefaultSequenceHeader(&gold); gold.initial_display_delay[0] = 8; data.SetBit(6, 1); // initial_display_delay_present_flag. data.InsertBit(29, 1); // initial_display_delay_present_for_this_op. data.InsertLiteral(30, 4, gold.initial_display_delay[0] - 1); ASSERT_TRUE(ParseSequenceHeader(data.GenerateData())); VerifySequenceHeader(gold); } // Parsing of a frame header should fail if no sequence header has been // received. TEST_F(ObuParserTest, FrameHeaderWithoutSequenceHeader) { // The aom-test-data test vector av1-1-b8-01-size-16x16.ivf has two temporal // units. The first temporal unit has a presentation timestamp of 0 and // consists of three OBUs: a temporal delimiter OBU, a sequence header OBU, // and a frame OBU. const std::vector kTemporalDelimiter = {0x12, 0x00}; const std::vector kSequenceHeader = { 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x9f, 0xfb, 0xff, 0xf3, 0x00, 0x80}; const std::vector kFrame = { 0x32, 0xa6, 0x01, 0x10, 0x00, 0x87, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x9e, 0x86, 0x5b, 0xb2, 0x22, 0xb5, 0x58, 0x4d, 0x68, 0xe6, 0x37, 0x54, 0x42, 0x7b, 0x84, 0xce, 0xdf, 0x9f, 0xec, 0xab, 0x07, 0x4d, 0xf6, 0xe1, 0x5e, 0x9e, 0x27, 0xbf, 0x93, 0x2f, 0x47, 0x0d, 0x7b, 0x7c, 0x45, 0x8d, 0xcf, 0x26, 0xf7, 0x6c, 0x06, 0xd7, 0x8c, 0x2e, 0xf5, 0x2c, 0xb0, 0x8a, 0x31, 0xac, 0x69, 0xf5, 0xcd, 0xd8, 0x71, 0x5d, 0xaf, 0xf8, 0x96, 0x43, 0x8c, 0x9c, 0x23, 0x6f, 0xab, 0xd0, 0x35, 0x43, 0xdf, 0x81, 0x12, 0xe3, 0x7d, 0xec, 0x22, 0xb0, 0x30, 0x54, 0x32, 0x9f, 0x90, 0xc0, 0x5d, 0x64, 0x9b, 0x0f, 0x75, 0x31, 0x84, 0x3a, 0x57, 0xd7, 0x5f, 0x03, 0x6e, 0x7f, 0x43, 0x17, 0x6d, 0x08, 0xc3, 0x81, 0x8a, 0xae, 0x73, 0x1c, 0xa8, 0xa7, 0xe4, 0x9c, 0xa9, 0x5b, 0x3f, 0xd1, 0xeb, 0x75, 0x3a, 0x7f, 0x22, 0x77, 0x38, 0x64, 0x1c, 0x77, 0xdb, 0xcd, 0xef, 0xb7, 0x08, 0x45, 0x8e, 0x7f, 0xea, 0xa3, 0xd0, 0x81, 0xc9, 0xc1, 0xbc, 0x93, 0x9b, 0x41, 0xb1, 0xa1, 0x42, 0x17, 0x98, 0x3f, 0x1e, 0x95, 0xdf, 0x68, 0x7c, 0xb7, 0x98}; BytesAndBits data; data.AppendBytes(kTemporalDelimiter); // Skip the sequence header OBU. data.AppendBytes(kFrame); ASSERT_FALSE(Parse(data.GenerateData())); // Now verify that all three OBUs are correct, by adding them to |data| // successively. data.Clear(); data.AppendBytes(kTemporalDelimiter); ASSERT_TRUE(Parse(data.GenerateData())); data.Clear(); data.AppendBytes(kTemporalDelimiter); data.AppendBytes(kSequenceHeader); ASSERT_TRUE(Parse(data.GenerateData())); data.Clear(); data.AppendBytes(kTemporalDelimiter); data.AppendBytes(kSequenceHeader); data.AppendBytes(kFrame); ASSERT_TRUE(Parse(data.GenerateData())); } TEST_F(ObuParserTest, FrameParameterShowExistingFrame) { BytesAndBits data; data.AppendBit(1); // show_existing_frame. data.AppendLiteral(3, kFrameToShow); // frame_to_show. ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); gold.show_existing_frame = true; gold.frame_to_show = kFrameToShow; // kFrameToShow'th frame is not yet decoded. ASSERT_FALSE(ParseFrameParameters(data.GenerateData())); decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer(); // kFrameToShow'th frame is not a showable frame. ASSERT_FALSE(ParseFrameParameters(data.GenerateData())); decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParametersShowExistingFrameWithDisplayFrameId) { BytesAndBits data; data.AppendBit(1); // show_existing_frame. data.AppendLiteral(3, kFrameToShow); // frame_to_show. data.AppendLiteral(15, kDisplayFrameId); // display_frame_id. ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); gold.show_existing_frame = true; gold.frame_to_show = kFrameToShow; gold.display_frame_id = kDisplayFrameId; // kFrameToShow'th frame is not yet decoded. ASSERT_FALSE(ParseFrameParameters(data.GenerateData(), true)); decoder_state_.reference_frame_id[kFrameToShow] = kDisplayFrameId; decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer(); // kFrameToShow'th frame is not a showable frame. ASSERT_FALSE(ParseFrameParameters(data.GenerateData(), true)); decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true); ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), true)); VerifyFrameParameters(gold, true); } TEST_F(ObuParserTest, FrameParameterShowExistingFrameTemporalPointInfo) { BytesAndBits data; data.AppendBit(1); // show_existing_frame. data.AppendLiteral(3, kFrameToShow); // frame_to_show. data.AppendLiteral(20, 38); // frame_presentation_time. ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); gold.show_existing_frame = true; gold.frame_to_show = kFrameToShow; gold.frame_presentation_time = 38; EXPECT_TRUE(Init(data.GenerateData())); obu_sequence_header_->frame_width_bits = kFrameWidthBits; obu_sequence_header_->frame_height_bits = kFrameHeightBits; obu_sequence_header_->max_frame_width = kWidth; obu_sequence_header_->max_frame_height = kHeight; obu_sequence_header_->decoder_model_info_present_flag = true; obu_sequence_header_->decoder_model_info.frame_presentation_time_length = 20; decoder_state_.reference_frame[kFrameToShow] = buffer_pool_->GetFreeBuffer(); decoder_state_.reference_frame[kFrameToShow]->set_showable_frame(true); ASSERT_TRUE(ObuParseFrameParameters()); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterErrorResilientMode) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameIntraOnly); gold.error_resilient_mode = true; data.SetBit(4, static_cast(gold.error_resilient_mode)); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterKeyFrame) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderKeyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterKeyFrameTemporalPointInfo) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderKeyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); data.InsertLiteral(4, 20, 38); // frame_presentation_time. gold.frame_presentation_time = 38; EXPECT_TRUE(Init(data.GenerateData())); obu_sequence_header_->frame_width_bits = kFrameWidthBits; obu_sequence_header_->frame_height_bits = kFrameHeightBits; obu_sequence_header_->max_frame_width = kWidth; obu_sequence_header_->max_frame_height = kHeight; obu_sequence_header_->decoder_model_info_present_flag = true; obu_sequence_header_->decoder_model_info.frame_presentation_time_length = 20; ASSERT_TRUE(ObuParseFrameParameters()); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterKeyFrameOverrideSize) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderKeyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); OverrideFrameSize(&data, &gold, 5, 6); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); OverrideRenderSize(&data, &gold, 23); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterKeyFrameSuperRes) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderKeyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); gold.use_superres = true; gold.superres_scale_denominator = 15; gold.width = kWidth * 8 / 15; gold.columns4x4 = 58; data.SetBit(6, static_cast(gold.use_superres)); data.SetLiteral(7, 3, gold.superres_scale_denominator - 9); ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 0, 0, true)); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterKeyFrameAllowScreenContentTools) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderKeyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameKey); data.InsertBit(5, 1); // allow_screen_content_tools. data.InsertBit(8, 1); // allow_intrabc. gold.allow_screen_content_tools = true; gold.allow_intrabc = true; ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2)); VerifyFrameParameters(gold); data.InsertBit(6, 1); // force_integer_mv. gold.force_integer_mv = 1; ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2, 2)); VerifyFrameParameters(gold); data.SetBit(6, 0); // force_integer_mv. // Gold need not be updated, because force_integer_mv is always 1 for // keyframes. ASSERT_TRUE(ParseFrameParameters(data.GenerateData(), false, 2, 2)); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterIntraOnlyFrame) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameIntraOnly); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterIntraOnlyFrameOverrideSize) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameIntraOnly); OverrideFrameSize(&data, &gold, 6, 15); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); OverrideRenderSize(&data, &gold, 32); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } // An INTRA_ONLY_FRAME cannot set refresh_frame_flags to 0xff. TEST_F(ObuParserTest, FrameParameterIntraOnlyFrameRefreshAllFrames) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderIntraOnlyFrame); data.SetLiteral(7, 8, 0xFF); // refresh_frame_flags. ASSERT_FALSE(ParseFrameParameters(data.GenerateData())); } TEST_F(ObuParserTest, FrameParameterInterFrame) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderInterFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameInter); ObuFrameHeader reference_frame_header; reference_frame_header.width = kWidth; reference_frame_header.height = kHeight; reference_frame_header.render_width = kWidth; reference_frame_header.render_height = kHeight; reference_frame_header.upscaled_width = kWidth; reference_frame_header.rows4x4 = kRows4x4; reference_frame_header.columns4x4 = kColumns4x4; reference_frame_header.refresh_frame_flags = 0; for (auto& reference_frame : decoder_state_.reference_frame) { reference_frame = buffer_pool_->GetFreeBuffer(); EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header)); } ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } TEST_F(ObuParserTest, FrameParameterInterFrameOverrideSize) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderInterFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameInter); ObuFrameHeader reference_frame_header; reference_frame_header.width = kWidth; reference_frame_header.height = kHeight; reference_frame_header.render_width = kWidth; reference_frame_header.render_height = kHeight; reference_frame_header.upscaled_width = kWidth; reference_frame_header.rows4x4 = kRows4x4; reference_frame_header.columns4x4 = kColumns4x4; reference_frame_header.refresh_frame_flags = 0; for (auto& reference_frame : decoder_state_.reference_frame) { reference_frame = buffer_pool_->GetFreeBuffer(); EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header)); } data.InsertLiteral(39, kNumInterReferenceFrameTypes, 0); // found_ref. OverrideFrameSize(&data, &gold, 6, 46); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); OverrideRenderSize(&data, &gold, 63); ASSERT_TRUE(ParseFrameParameters(data.GenerateData())); VerifyFrameParameters(gold); } // This test verifies we check the following requirement at the end of Section // 6.8.4: // If FrameIsIntra is equal to 0 (indicating that this frame may use inter // prediction), the requirements described in the frame size with refs // semantics of section 6.8.6 must also be satisfied. TEST_F(ObuParserTest, FrameParameterInterFrameInvalidSize) { BytesAndBits data; data.AppendBytes(kDefaultFrameHeaderInterFrame); ObuFrameHeader gold; DefaultFrameHeader(&gold, kFrameInter); ObuFrameHeader reference_frame_header; reference_frame_header.width = kWidth; reference_frame_header.height = 2 * kHeight + 8; reference_frame_header.render_width = kWidth; reference_frame_header.render_height = 2 * kHeight + 8; reference_frame_header.upscaled_width = kWidth; reference_frame_header.rows4x4 = 2 * kRows4x4 + 2; reference_frame_header.columns4x4 = kColumns4x4; reference_frame_header.refresh_frame_flags = 0; for (auto& reference_frame : decoder_state_.reference_frame) { reference_frame = buffer_pool_->GetFreeBuffer(); EXPECT_TRUE(reference_frame->SetFrameDimensions(reference_frame_header)); } EXPECT_FALSE(ParseFrameParameters(data.GenerateData())); } // Tests the ObuParser::SetFrameReferences() method. // // This method uses the following data members as input: // decoder_state_.reference_order_hint // sequence_header_.enable_order_hint // sequence_header_.order_hint_bits // frame_header_.order_hint // So we need to set up these data members before calling // ObuParser::SetFrameReferences(). // // The output is in frame_header_.reference_frame_index. TEST_F(ObuParserTest, SetFrameReferences) { // All reference frames are forward references (because 9 < 17). for (int i = 0; i < kNumReferenceFrameTypes; ++i) { decoder_state_.reference_order_hint[i] = 9; } ASSERT_TRUE(Init()); obu_sequence_header_->enable_order_hint = true; obu_sequence_header_->order_hint_bits = 5; obu_sequence_header_->order_hint_shift_bits = Mod32(32 - obu_sequence_header_->order_hint_bits); obu_frame_header_->order_hint = 17; const int8_t last_frame_idx = 0; const int8_t gold_frame_idx = 1; // Since all reference frames are forward references, we set the remaining // five references in reverse chronological order. So Last2, Last3, Backward, // Alternate2, and Alternate are set to 7, 6, 5, 4, and 3, respectively. EXPECT_TRUE(ObuSetFrameReferences(last_frame_idx, gold_frame_idx)); EXPECT_EQ( obu_frame_header_ ->reference_frame_index[kReferenceFrameLast - kReferenceFrameLast], 0); EXPECT_EQ( obu_frame_header_ ->reference_frame_index[kReferenceFrameLast2 - kReferenceFrameLast], 7); EXPECT_EQ( obu_frame_header_ ->reference_frame_index[kReferenceFrameLast3 - kReferenceFrameLast], 6); EXPECT_EQ( obu_frame_header_ ->reference_frame_index[kReferenceFrameGolden - kReferenceFrameLast], 1); EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameBackward - kReferenceFrameLast], 5); EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameAlternate2 - kReferenceFrameLast], 4); EXPECT_EQ(obu_frame_header_->reference_frame_index[kReferenceFrameAlternate - kReferenceFrameLast], 3); } TEST_F(ObuParserTest, LoopFilterParameters) { LoopFilter gold; memset(&gold, 0, sizeof(gold)); BytesAndBits data; data.AppendBit(0); // dummy. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone; obu_frame_header_->coded_lossless = true; gold.ref_deltas[kReferenceFrameIntra] = 1; gold.ref_deltas[kReferenceFrameGolden] = -1; gold.ref_deltas[kReferenceFrameAlternate] = -1; gold.ref_deltas[kReferenceFrameAlternate2] = -1; ASSERT_TRUE(ObuParseLoopFilterParameters()); VerifyLoopFilterParameters(gold); ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone; obu_frame_header_->allow_intrabc = true; ASSERT_TRUE(ObuParseLoopFilterParameters()); VerifyLoopFilterParameters(gold); gold.level[0] = 32; gold.level[3] = 48; gold.sharpness = 4; data.Clear(); for (const auto& level : gold.level) { data.AppendLiteral(6, level); } data.AppendLiteral(3, gold.sharpness); data.AppendBit(0); // delta_enabled. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone; ASSERT_TRUE(ObuParseLoopFilterParameters()); VerifyLoopFilterParameters(gold); gold.delta_enabled = true; gold.delta_update = true; gold.ref_deltas[0] = 20; gold.mode_deltas[0] = -20; data.SetBit(27, 1); // delta_enabled. data.AppendBit(1); // delta_update. for (int i = 0; i < kNumReferenceFrameTypes; ++i) { if (i == 0) { data.AppendBit(1); // update_ref_delta. data.AppendInverseSignedLiteral(6, gold.ref_deltas[0]); // ref_delta. } else { data.AppendBit(0); // update_ref_delta. } } for (int i = 0; i < kLoopFilterMaxModeDeltas; ++i) { if (i == 0) { data.AppendBit(1); // update_mode_delta. data.AppendInverseSignedLiteral(6, gold.mode_deltas[0]); // mode_delta. } else { data.AppendBit(0); // update_mode_delta. } } ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->primary_reference_frame = kPrimaryReferenceNone; ASSERT_TRUE(ObuParseLoopFilterParameters()); VerifyLoopFilterParameters(gold); } TEST_F(ObuParserTest, QuantizerParameters) { QuantizerParameters gold = {}; gold.base_index = 48; BytesAndBits data; data.AppendLiteral(8, gold.base_index); data.AppendLiteral(3, 0); // delta_coded. data.AppendBit(0); // use_matrix. ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); } TEST_F(ObuParserTest, QuantizerParametersMonochrome) { QuantizerParameters gold = {}; gold.base_index = 48; BytesAndBits data; data.AppendLiteral(8, gold.base_index); data.AppendBit(0); // delta_coded. data.AppendBit(0); // use_matrix. // The quantizer parameters end here. Add a 1 bit. It should not be parsed. data.AppendBit(1); // Would be segmentation_enabled in a bitstream. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.is_monochrome = true; ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); } TEST_F(ObuParserTest, QuantizerParametersDeltaCoded) { QuantizerParameters gold = {}; gold.base_index = 48; gold.delta_dc[kPlaneY] = -30; BytesAndBits data; data.AppendLiteral(8, gold.base_index); data.AppendBit(1); // delta_coded. data.AppendInverseSignedLiteral(6, gold.delta_dc[kPlaneY]); data.AppendLiteral(2, 0); // delta_coded u dc/ac. data.AppendBit(0); // use_matrix. ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); gold.delta_dc[kPlaneU] = -40; gold.delta_dc[kPlaneV] = gold.delta_dc[kPlaneU]; data.SetBit(16, 1); // delta_coded. data.InsertInverseSignedLiteral(17, 6, gold.delta_dc[kPlaneU]); ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); gold.delta_ac[kPlaneU] = 50; gold.delta_ac[kPlaneV] = gold.delta_ac[kPlaneU]; data.SetBit(24, 1); // delta_coded. data.InsertInverseSignedLiteral(25, 6, gold.delta_ac[kPlaneU]); ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); gold.delta_dc[kPlaneV] = 60; gold.delta_ac[kPlaneV] = 0; data.InsertBit(16, 1); // diff_uv_delta. data.InsertBit(33, 1); // delta_coded. data.InsertInverseSignedLiteral(34, 6, gold.delta_dc[kPlaneV]); data.InsertBit(41, 0); // delta_coded. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.separate_uv_delta_q = true; ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); gold.delta_ac[kPlaneV] = -20; data.SetBit(41, 1); // delta_coded. data.InsertInverseSignedLiteral(42, 6, gold.delta_ac[kPlaneV]); ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.separate_uv_delta_q = true; ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); } TEST_F(ObuParserTest, QuantizerParametersUseQmatrix) { QuantizerParameters gold = {}; gold.base_index = 48; gold.use_matrix = true; gold.matrix_level[kPlaneY] = 3; gold.matrix_level[kPlaneU] = 6; gold.matrix_level[kPlaneV] = gold.matrix_level[kPlaneU]; // Test three cases. // 1. separate_uv_delta_q = false (which implies diff_uv_delta = false). BytesAndBits data; data.AppendLiteral(8, gold.base_index); data.AppendLiteral(3, 0); // delta_coded. data.AppendBit(static_cast(gold.use_matrix)); data.AppendLiteral(4, gold.matrix_level[kPlaneY]); data.AppendLiteral(4, gold.matrix_level[kPlaneU]); ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); // 2. separate_uv_delta_q = true and diff_uv_delta = false. gold.matrix_level[kPlaneV] = 5; data.InsertBit(9, 0); // diff_uv_delta. data.AppendLiteral(4, gold.matrix_level[kPlaneV]); ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.separate_uv_delta_q = true; ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); // 3. separate_uv_delta_q = true and diff_uv_delta = true. data.SetBit(9, 1); // diff_uv_delta. data.InsertLiteral(12, 2, 0); // delta_coded. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.separate_uv_delta_q = true; ASSERT_TRUE(ObuParseQuantizerParameters()); VerifyQuantizerParameters(gold); } TEST_F(ObuParserTest, SegmentationParameters) { const int kPrimaryReferenceNotNone = 1; const int kPrevFrameIndexNotNone = 2; // Set up decoder_state_ with a previous frame containing saved segmentation // parameters. decoder_state_.reference_frame[kPrevFrameIndexNotNone] = buffer_pool_->GetFreeBuffer(); ASSERT_NE(decoder_state_.reference_frame[kPrevFrameIndexNotNone], nullptr); Segmentation prev_segmentation = {}; prev_segmentation.feature_enabled[2][0] = true; prev_segmentation.feature_enabled[5][0] = true; prev_segmentation.last_active_segment_id = 5; decoder_state_.reference_frame[kPrevFrameIndexNotNone] ->SetSegmentationParameters(prev_segmentation); Segmentation gold; memset(&gold, 0, sizeof(gold)); BytesAndBits data; data.AppendBit(0); // segmentation_enabled. // Since segmentation_enabled is false, we expect the parameters to be all // zero/false. ASSERT_TRUE(ParseSegmentationParameters( data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone)); VerifySegmentationParameters(gold); gold.enabled = true; gold.update_map = true; gold.temporal_update = true; data.SetBit(0, static_cast(gold.enabled)); data.AppendBit(static_cast(gold.update_map)); data.AppendBit(static_cast(gold.temporal_update)); data.AppendBit(static_cast(gold.update_data)); // Since update_data is false, we expect the parameters to be loaded from the // previous frame in |decoder_state_|. So change |gold| accordingly. gold.feature_enabled[2][0] = true; gold.feature_enabled[5][0] = true; gold.last_active_segment_id = 5; ASSERT_TRUE(ParseSegmentationParameters( data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone)); VerifySegmentationParameters(gold); OverrideSegmentation(&data, &gold, 3); ASSERT_TRUE(ParseSegmentationParameters( data.GenerateData(), kPrimaryReferenceNotNone, kPrevFrameIndexNotNone)); VerifySegmentationParameters(gold); // If primary_ref_frame is kPrimaryReferenceNone, these three fields are // implied. data.RemoveBit(1); // segmentation_update_map. data.RemoveBit(1); // segmentation_temporal_update. data.RemoveBit(1); // segmentation_update_data. gold.update_map = true; gold.temporal_update = false; gold.update_data = true; // Since update_data is true, we expect the parameters to be read from // |data|. ASSERT_TRUE(ParseSegmentationParameters(data.GenerateData(), kPrimaryReferenceNone, 0)); VerifySegmentationParameters(gold); } TEST_F(ObuParserTest, QuantizerIndexDeltaParameters) { BytesAndBits data; data.AppendBit(1); // delta_q_present. data.AppendLiteral(2, 2); // delta_q_res. Delta gold; memset(&gold, 0, sizeof(gold)); ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseQuantizerIndexDeltaParameters()); VerifyDeltaParameters(gold, obu_->frame_header().delta_q); gold.present = true; gold.scale = 2; ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->quantizer.base_index = 40; ASSERT_TRUE(ObuParseQuantizerIndexDeltaParameters()); VerifyDeltaParameters(gold, obu_->frame_header().delta_q); } TEST_F(ObuParserTest, LoopFilterDeltaParameters) { BytesAndBits data; data.AppendBit(1); // delta_lf_present. data.AppendLiteral(2, 2); // delta_lf_res. data.AppendBit(1); // delta_lf_multi. Delta gold; memset(&gold, 0, sizeof(gold)); // delta_q_present is false, so loop filter delta will not be read. ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseLoopFilterDeltaParameters()); VerifyDeltaParameters(gold, obu_->frame_header().delta_lf); // allow_intrabc is true, so loop filter delta will not be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->delta_q.present = true; obu_frame_header_->allow_intrabc = true; ASSERT_TRUE(ObuParseLoopFilterDeltaParameters()); VerifyDeltaParameters(gold, obu_->frame_header().delta_lf); gold.present = true; gold.scale = 2; gold.multi = true; ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->delta_q.present = true; ASSERT_TRUE(ObuParseLoopFilterDeltaParameters()); VerifyDeltaParameters(gold, obu_->frame_header().delta_lf); } TEST_F(ObuParserTest, ComputeSegmentLosslessAndQIndex) { BytesAndBits data; data.AppendBit(0); // dummy. ASSERT_TRUE(Init(data.GenerateData())); // Segmentation is disabled. All quantizers are 0. ObuComputeSegmentLosslessAndQIndex(); EXPECT_TRUE(obu_->frame_header().coded_lossless); EXPECT_TRUE(obu_->frame_header().upscaled_lossless); for (const auto& qindex : obu_->frame_header().segmentation.qindex) { EXPECT_EQ(qindex, 0); } // Segmentation is enabled. All quantizers are zero. obu_frame_header_->segmentation.enabled = true; ObuComputeSegmentLosslessAndQIndex(); EXPECT_TRUE(obu_->frame_header().coded_lossless); EXPECT_TRUE(obu_->frame_header().upscaled_lossless); for (const auto& qindex : obu_->frame_header().segmentation.qindex) { EXPECT_EQ(qindex, 0); } // Segmentation is enabled. All quantizers are zero. upscaled_width != width. obu_frame_header_->segmentation.enabled = true; obu_frame_header_->upscaled_width = 100; ObuComputeSegmentLosslessAndQIndex(); EXPECT_TRUE(obu_->frame_header().coded_lossless); EXPECT_FALSE(obu_->frame_header().upscaled_lossless); for (const auto& qindex : obu_->frame_header().segmentation.qindex) { EXPECT_EQ(qindex, 0); } // Segmentation in disabled. Some quantizer deltas are non zero. obu_frame_header_->segmentation.enabled = false; obu_frame_header_->quantizer.delta_dc[kPlaneY] = 40; ObuComputeSegmentLosslessAndQIndex(); EXPECT_FALSE(obu_->frame_header().coded_lossless); EXPECT_FALSE(obu_->frame_header().upscaled_lossless); for (const auto& qindex : obu_->frame_header().segmentation.qindex) { EXPECT_EQ(qindex, 0); } // Segmentation is disabled. Quantizer base index is non zero. obu_frame_header_->segmentation.enabled = true; obu_frame_header_->quantizer.delta_dc[kPlaneY] = 0; obu_frame_header_->quantizer.base_index = 40; ObuComputeSegmentLosslessAndQIndex(); EXPECT_FALSE(obu_->frame_header().coded_lossless); EXPECT_FALSE(obu_->frame_header().upscaled_lossless); for (const auto& qindex : obu_->frame_header().segmentation.qindex) { EXPECT_EQ(qindex, 40); } } TEST_F(ObuParserTest, CdefParameters) { Cdef gold; memset(&gold, 0, sizeof(gold)); const int coeff_shift = 2; // bitdepth - 8. gold.damping = 3 + coeff_shift; BytesAndBits data; data.AppendBit(0); // dummy. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->color_config.bitdepth = 10; ASSERT_TRUE(ObuParseCdefParameters()); // Cdef will be {0} except for damping because enable_cdef is false. VerifyCdefParameters(gold); ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_cdef = true; obu_sequence_header_->color_config.bitdepth = 10; obu_frame_header_->coded_lossless = true; ASSERT_TRUE(ObuParseCdefParameters()); // Cdef will be {0} except for damping because coded_lossless is true. VerifyCdefParameters(gold); ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_cdef = true; obu_sequence_header_->color_config.bitdepth = 10; obu_frame_header_->allow_intrabc = true; ASSERT_TRUE(ObuParseCdefParameters()); // Cdef will be {0} except for damping because allow_intrabc is true. VerifyCdefParameters(gold); gold.damping = 5; gold.bits = 1; data.Clear(); data.AppendLiteral(2, gold.damping - 3); // cdef_damping_minus3. gold.damping += coeff_shift; data.AppendLiteral(2, gold.bits); // cdef_bits. for (int i = 0; i < 2; ++i) { gold.y_primary_strength[i] = 10; gold.y_secondary_strength[i] = (i == 0) ? 2 : 3; gold.uv_primary_strength[i] = 12; gold.uv_secondary_strength[i] = (i == 1) ? 2 : 3; data.AppendLiteral(4, gold.y_primary_strength[i]); data.AppendLiteral(2, gold.y_secondary_strength[i]); data.AppendLiteral(4, gold.uv_primary_strength[i]); data.AppendLiteral(2, gold.uv_secondary_strength[i]); if (gold.y_secondary_strength[i] == 3) ++gold.y_secondary_strength[i]; if (gold.uv_secondary_strength[i] == 3) ++gold.uv_secondary_strength[i]; gold.y_primary_strength[i] <<= coeff_shift; gold.uv_primary_strength[i] <<= coeff_shift; gold.y_secondary_strength[i] <<= coeff_shift; gold.uv_secondary_strength[i] <<= coeff_shift; } ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_cdef = true; obu_sequence_header_->color_config.bitdepth = 10; ASSERT_TRUE(ObuParseCdefParameters()); VerifyCdefParameters(gold); } TEST_F(ObuParserTest, LoopRestorationParameters) { for (bool use_128x128_superblock : testing::Bool()) { SCOPED_TRACE("use_128x128_superblock: " + std::to_string(use_128x128_superblock)); LoopRestoration gold; memset(&gold, 0, sizeof(gold)); BytesAndBits data; data.AppendBit(0); // dummy. // enable_restoration is false. nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->allow_intrabc = true; obu_frame_header_->coded_lossless = true; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); // allow_intrabc is true. nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->allow_intrabc = true; obu_sequence_header_->enable_restoration = true; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); // coded_lossless is true. nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->coded_lossless = true; obu_sequence_header_->enable_restoration = true; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); data.Clear(); for (int i = 0; i < kMaxPlanes; ++i) { data.AppendLiteral(2, kLoopRestorationTypeNone); // lr_type. } ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_restoration = true; obu_sequence_header_->use_128x128_superblock = use_128x128_superblock; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); gold.type[0] = gold.type[1] = kLoopRestorationTypeWiener; gold.unit_size_log2[0] = gold.unit_size_log2[1] = gold.unit_size_log2[2] = use_128x128_superblock ? 8 : 7; data.SetLiteral(0, 2, gold.type[0]); // lr_type. data.SetLiteral(2, 2, gold.type[0]); // lr_type. data.AppendBit(1); // lr_unit_shift. if (!use_128x128_superblock) { data.AppendBit(0); // lr_unit_extra_shift. } ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_restoration = true; obu_sequence_header_->use_128x128_superblock = use_128x128_superblock; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); if (!use_128x128_superblock) { gold.unit_size_log2[0] = gold.unit_size_log2[1] = gold.unit_size_log2[2] = 8; data.SetBit(7, 1); // lr_unit_extra_shift. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_restoration = true; obu_sequence_header_->use_128x128_superblock = use_128x128_superblock; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); } gold.unit_size_log2[1] = gold.unit_size_log2[2] = 7; data.AppendBit(1); // lr_uv_shift. ASSERT_TRUE(Init(data.GenerateData())); obu_sequence_header_->enable_restoration = true; obu_sequence_header_->use_128x128_superblock = use_128x128_superblock; obu_sequence_header_->color_config.subsampling_x = 1; obu_sequence_header_->color_config.subsampling_y = 1; ASSERT_TRUE(ObuParseLoopRestorationParameters()); VerifyLoopRestorationParameters(gold); } } TEST_F(ObuParserTest, TxModeSyntax) { BytesAndBits data; data.AppendBit(1); // tx_mode_select. ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseTxModeSyntax()); EXPECT_EQ(kTxModeSelect, obu_->frame_header().tx_mode); data.SetBit(0, 0); // tx_mode_select. ASSERT_TRUE(Init(data.GenerateData())); ASSERT_TRUE(ObuParseTxModeSyntax()); EXPECT_EQ(kTxModeLargest, obu_->frame_header().tx_mode); ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->coded_lossless = true; ASSERT_TRUE(ObuParseTxModeSyntax()); EXPECT_EQ(kTxModeOnly4x4, obu_->frame_header().tx_mode); } TEST_F(ObuParserTest, FrameReferenceModeSyntax) { BytesAndBits data; data.AppendBit(0); // dummy. ASSERT_TRUE(ParseFrameReferenceModeSyntax(data.GenerateData(), kFrameKey)); EXPECT_FALSE(obu_->frame_header().reference_mode_select); data.SetBit(0, 1); // reference_mode_select. ASSERT_TRUE(ParseFrameReferenceModeSyntax(data.GenerateData(), kFrameInter)); EXPECT_TRUE(obu_->frame_header().reference_mode_select); } TEST_F(ObuParserTest, SkipModeParameters) { BytesAndBits data; data.AppendBit(1); // skip_mode_present. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameKey; ASSERT_FALSE(ObuIsSkipModeAllowed()); ASSERT_TRUE(ObuParseSkipModeParameters()); EXPECT_FALSE(obu_->frame_header().skip_mode_present); ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->reference_mode_select = true; ASSERT_FALSE(ObuIsSkipModeAllowed()); ASSERT_TRUE(ObuParseSkipModeParameters()); EXPECT_FALSE(obu_->frame_header().skip_mode_present); ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->reference_mode_select = true; obu_sequence_header_->enable_order_hint = true; obu_sequence_header_->order_hint_bits = 7; obu_sequence_header_->order_hint_shift_bits = Mod32(32 - obu_sequence_header_->order_hint_bits); ASSERT_FALSE(ObuIsSkipModeAllowed()); ASSERT_TRUE(ObuParseSkipModeParameters()); EXPECT_FALSE(obu_->frame_header().skip_mode_present); ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->reference_mode_select = true; obu_frame_header_->order_hint = 1; decoder_state_.order_hint = 1; obu_sequence_header_->enable_order_hint = true; obu_sequence_header_->order_hint_bits = 7; obu_sequence_header_->order_hint_shift_bits = Mod32(32 - obu_sequence_header_->order_hint_bits); ASSERT_FALSE(ObuIsSkipModeAllowed()); ASSERT_TRUE(ObuParseSkipModeParameters()); EXPECT_FALSE(obu_->frame_header().skip_mode_present); ASSERT_TRUE(Init(data.GenerateData())); for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { obu_frame_header_->reference_frame_index[i] = i; decoder_state_.reference_order_hint[i] = i; } obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->reference_mode_select = true; obu_frame_header_->order_hint = 1; decoder_state_.order_hint = 1; obu_sequence_header_->enable_order_hint = true; obu_sequence_header_->order_hint_bits = 7; obu_sequence_header_->order_hint_shift_bits = Mod32(32 - obu_sequence_header_->order_hint_bits); ASSERT_TRUE(ObuIsSkipModeAllowed()); ASSERT_TRUE(ObuParseSkipModeParameters()); EXPECT_TRUE(obu_->frame_header().skip_mode_present); } TEST_F(ObuParserTest, AllowWarpedMotion) { BytesAndBits data; data.AppendBit(0xff); // dummy. // IsIntraFrame is true, so nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameKey; obu_frame_header_->error_resilient_mode = false; obu_sequence_header_->enable_warped_motion = true; ASSERT_TRUE(ObuReadAllowWarpedMotion()); EXPECT_FALSE(obu_->frame_header().allow_warped_motion); // error_resilient_mode is true, so nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->error_resilient_mode = true; obu_sequence_header_->enable_warped_motion = true; ASSERT_TRUE(ObuReadAllowWarpedMotion()); EXPECT_FALSE(obu_->frame_header().allow_warped_motion); // enable_warped_motion is false, so nothing will be read. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->error_resilient_mode = false; obu_sequence_header_->enable_warped_motion = false; ASSERT_TRUE(ObuReadAllowWarpedMotion()); EXPECT_FALSE(obu_->frame_header().allow_warped_motion); // allow_warped_motion will be read and equal to true. ASSERT_TRUE(Init(data.GenerateData())); obu_frame_header_->frame_type = kFrameInter; obu_frame_header_->error_resilient_mode = false; obu_sequence_header_->enable_warped_motion = true; ASSERT_TRUE(ObuReadAllowWarpedMotion()); EXPECT_TRUE(obu_->frame_header().allow_warped_motion); } TEST_F(ObuParserTest, GlobalMotionParameters) { BytesAndBits data; data.AppendBit(0); // dummy. std::array gold; for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) { gold[i].type = kGlobalMotionTransformationTypeIdentity; for (int j = 0; j < 6; ++j) { gold[i].params[j] = (j % 3 == 2) ? 1 << kWarpedModelPrecisionBits : 0; } } ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameKey)); VerifyGlobalMotionParameters(gold); data.Clear(); for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) { // is_global=1; is_rot_zoom=1; parameter_values; data.AppendBytes(kDefaultGlobalMotionParametersRotZoom); // Magic numbers based on kDefaultGlobalMotionParametersRotZoom. gold[i].type = kGlobalMotionTransformationTypeRotZoom; gold[i].params[0] = -73728; gold[i].params[1] = -23552; gold[i].params[2] = 65952; gold[i].params[3] = -62; gold[i].params[4] = 62; gold[i].params[5] = 65952; } ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameInter)); VerifyGlobalMotionParameters(gold); data.Clear(); for (int i = kReferenceFrameLast; i <= kReferenceFrameAlternate; ++i) { // This bit is not part of the hex string because it would make the whole // string not align to 8 bits. Appending this separately so that we can keep // the rest of them a magic hex string. data.AppendBit(1); // is_global. // is_rot_zoom=0; is_translation=0; parameter_values; data.AppendBytes(kDefaultGlobalMotionParametersAffine); // Magic numbers based on kDefaultGlobalMotionParametersAffine. gold[i].type = kGlobalMotionTransformationTypeAffine; gold[i].params[4] = -62; } ASSERT_TRUE(ParseGlobalMotionParameters(data.GenerateData(), kFrameInter)); VerifyGlobalMotionParameters(gold); } TEST_F(ObuParserTest, FilmGrainParameters) { BytesAndBits data; data.AppendBit(0); // dummy. // Test film grain not present. FilmGrainParams gold = {}; ObuSequenceHeader sequence_header = {}; sequence_header.film_grain_params_present = false; ObuFrameHeader frame_header = {}; ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); VerifyFilmGrainParameters(gold); // Test if show_frame = false and showable_frame = false. data.Clear(); gold = {}; sequence_header.film_grain_params_present = true; frame_header.show_frame = false; frame_header.showable_frame = false; ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); VerifyFilmGrainParameters(gold); // Test if apply_grain = false. data.Clear(); gold = {}; sequence_header.film_grain_params_present = true; frame_header.show_frame = true; frame_header.showable_frame = true; data.AppendBit(0); ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); VerifyFilmGrainParameters(gold); // Test if update_grain = false. data.Clear(); gold = {}; sequence_header.film_grain_params_present = true; frame_header.show_frame = true; frame_header.showable_frame = true; frame_header.frame_type = kFrameInter; for (auto& index : frame_header.reference_frame_index) { index = 1; } data.AppendBit(1); gold.apply_grain = true; data.AppendLiteral(16, 8); gold.grain_seed = 8; data.AppendBit(0); gold.update_grain = false; data.AppendLiteral(3, 1); gold.reference_index = 1; // Set up decoder_state_ with a previous frame containing saved film grain // parameters. decoder_state_.reference_frame[1] = buffer_pool_->GetFreeBuffer(); EXPECT_NE(decoder_state_.reference_frame[1], nullptr); FilmGrainParams prev_grain_params = {}; prev_grain_params.apply_grain = true; prev_grain_params.grain_seed = 11; prev_grain_params.update_grain = true; decoder_state_.reference_frame[1]->set_film_grain_params(prev_grain_params); ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); VerifyFilmGrainParameters(gold); // Test if update_grain = true, is_monochrome = true; data.Clear(); gold = {}; frame_header.frame_type = kFrameKey; for (auto& index : frame_header.reference_frame_index) { index = 0; } data.AppendBit(1); gold.apply_grain = true; data.AppendLiteral(16, 8); gold.grain_seed = 8; gold.update_grain = true; data.AppendLiteral(4, 10); gold.num_y_points = 10; for (int i = 0; i < gold.num_y_points; ++i) { data.AppendLiteral(8, 2 * i); gold.point_y_value[i] = 2 * i; data.AppendLiteral(8, i); gold.point_y_scaling[i] = i; } sequence_header.color_config.is_monochrome = true; gold.chroma_scaling_from_luma = false; gold.num_u_points = 0; gold.num_v_points = 0; data.AppendLiteral(2, 3); gold.chroma_scaling = 11; data.AppendLiteral(2, 1); gold.auto_regression_coeff_lag = 1; const int num_pos_luma = 2 * gold.auto_regression_coeff_lag * (gold.auto_regression_coeff_lag + 1); for (int i = 0; i < num_pos_luma; ++i) { data.AppendLiteral(8, i + 128); gold.auto_regression_coeff_y[i] = i; } data.AppendLiteral(2, 0); gold.auto_regression_shift = 6; data.AppendLiteral(2, 1); gold.grain_scale_shift = 1; data.AppendBit(1); gold.overlap_flag = true; data.AppendBit(0); gold.clip_to_restricted_range = false; ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); ASSERT_TRUE( obu_->frame_header().frame_type == kFrameInter || obu_->frame_header().film_grain_params.update_grain); // a implies b. VerifyFilmGrainParameters(gold); // Test if update_grain = true, is_monochrome = false; data.Clear(); gold = {}; frame_header.frame_type = kFrameKey; data.AppendBit(1); gold.apply_grain = true; data.AppendLiteral(16, 8); gold.grain_seed = 8; gold.update_grain = true; data.AppendLiteral(4, 10); gold.num_y_points = 10; for (int i = 0; i < gold.num_y_points; ++i) { data.AppendLiteral(8, 2 * i); gold.point_y_value[i] = 2 * i; data.AppendLiteral(8, i); gold.point_y_scaling[i] = i; } sequence_header.color_config.is_monochrome = false; data.AppendBit(0); gold.chroma_scaling_from_luma = false; data.AppendLiteral(4, 5); gold.num_u_points = 5; for (int i = 0; i < gold.num_u_points; ++i) { data.AppendLiteral(8, 2 * i + 1); gold.point_u_value[i] = 2 * i + 1; data.AppendLiteral(8, i); gold.point_u_scaling[i] = i; } data.AppendLiteral(4, 3); gold.num_v_points = 3; for (int i = 0; i < gold.num_v_points; ++i) { data.AppendLiteral(8, i); gold.point_v_value[i] = i; data.AppendLiteral(8, i + 1); gold.point_v_scaling[i] = i + 1; } data.AppendLiteral(2, 3); gold.chroma_scaling = 11; data.AppendLiteral(2, 1); gold.auto_regression_coeff_lag = 1; const int num_pos_luma2 = 2 * gold.auto_regression_coeff_lag * (gold.auto_regression_coeff_lag + 1); for (int i = 0; i < num_pos_luma2; ++i) { data.AppendLiteral(8, i + 128); gold.auto_regression_coeff_y[i] = i; } for (int i = 0; i < num_pos_luma2 + 1; ++i) { data.AppendLiteral(8, i); gold.auto_regression_coeff_u[i] = i - 128; } for (int i = 0; i < num_pos_luma2 + 1; ++i) { data.AppendLiteral(8, i); gold.auto_regression_coeff_v[i] = i - 128; } data.AppendLiteral(2, 0); gold.auto_regression_shift = 6; data.AppendLiteral(2, 1); gold.grain_scale_shift = 1; data.AppendLiteral(8, 2); gold.u_multiplier = -126; data.AppendLiteral(8, 1); gold.u_luma_multiplier = -127; data.AppendLiteral(9, 3); gold.u_offset = -253; data.AppendLiteral(8, 3); gold.v_multiplier = -125; data.AppendLiteral(8, 2); gold.v_luma_multiplier = -126; data.AppendLiteral(9, 1); gold.v_offset = -255; data.AppendBit(1); gold.overlap_flag = true; data.AppendBit(0); gold.clip_to_restricted_range = false; ASSERT_TRUE(ParseFilmGrainParameters(data.GenerateData(), sequence_header, frame_header)); ASSERT_TRUE( obu_->frame_header().frame_type == kFrameInter || obu_->frame_header().film_grain_params.update_grain); // a implies b. VerifyFilmGrainParameters(gold); } TEST_F(ObuParserTest, TileInfoSyntax) { BytesAndBits data; TileInfo gold; memset(&gold, 0, sizeof(gold)); gold.uniform_spacing = true; gold.tile_columns_log2 = 1; gold.tile_columns = 2; gold.tile_rows_log2 = 1; gold.tile_rows = 2; gold.tile_count = 4; gold.tile_column_start[1] = 64; gold.tile_column_start[2] = 88; gold.tile_row_start[1] = 64; gold.tile_row_start[2] = 72; gold.context_update_id = 3; gold.tile_size_bytes = 4; data.AppendBit(static_cast(gold.uniform_spacing)); data.AppendBit(1); // increment_tile_cols_log2. data.AppendBit(0); // increment_tile_cols_log2. data.AppendBit(1); // increment_tile_rows_log2. data.AppendBit(0); // increment_tile_rows_log2. data.AppendBit(1); // context update id, columns_log2+rows_log2 bits data.AppendBit(1); data.AppendLiteral(2, gold.tile_size_bytes - 1); ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true)); VerifyTileInfoParameters(gold); gold.uniform_spacing = false; gold.tile_column_width_in_superblocks[0] = 2; gold.tile_column_width_in_superblocks[1] = 1; gold.tile_row_height_in_superblocks[0] = 2; gold.tile_row_height_in_superblocks[1] = 1; data.SetBit(0, static_cast(gold.uniform_spacing)); // The next 4 bits remain the same except now they represent f(w - 1) and // extra_bit in DecodeUniform. All the subsequent bits are unchanged the // represent the same thing as above. ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true)); VerifyTileInfoParameters(gold); // No tiles. memset(&gold, 0, sizeof(gold)); gold.uniform_spacing = true; gold.tile_columns = 1; gold.tile_rows = 1; gold.tile_count = 1; gold.tile_column_start[1] = 88; gold.tile_row_start[1] = 72; data.Clear(); data.AppendBit(static_cast(gold.uniform_spacing)); data.AppendBit(0); // tile_cols_log2. data.AppendBit(0); // tile_rows_log2. ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 88, 72, true)); VerifyTileInfoParameters(gold); // 64x64 superblocks. No tiles. gold.tile_column_start[1] = 640; gold.tile_row_start[1] = 360; ASSERT_TRUE(ParseTileInfoSyntax(data.GenerateData(), 640, 360, false)); VerifyTileInfoParameters(gold); } TEST_F(ObuParserTest, MetadataUnknownType) { BytesAndBits data; // The metadata_type 10 is a user private value (6-31). data.AppendLiteral(8, 10); // metadata_type. // The Note in Section 5.8.1 says "Decoders should ignore the entire OBU if // they do not understand the metadata_type." ASSERT_TRUE(ParseMetadata(data.GenerateData())); } TEST_F(ObuParserTest, MetadataHdrCll) { BytesAndBits data; ObuMetadataHdrCll gold; gold.max_cll = 25; gold.max_fall = 100; data.AppendLiteral(8, kMetadataTypeHdrContentLightLevel); data.AppendLiteral(16, gold.max_cll); data.AppendLiteral(16, gold.max_fall); ASSERT_TRUE(ParseMetadata(data.GenerateData())); VerifyMetadataHdrCll(gold); } TEST_F(ObuParserTest, MetadataHdrMdcv) { BytesAndBits data; ObuMetadataHdrMdcv gold; for (int i = 0; i < 3; ++i) { gold.primary_chromaticity_x[i] = 0; gold.primary_chromaticity_y[i] = 0; } gold.white_point_chromaticity_x = 250; gold.white_point_chromaticity_y = 2500; gold.luminance_max = 6000; gold.luminance_min = 3000; data.AppendLiteral(8, kMetadataTypeHdrMasteringDisplayColorVolume); for (int i = 0; i < 3; ++i) { data.AppendLiteral(16, gold.primary_chromaticity_x[i]); data.AppendLiteral(16, gold.primary_chromaticity_y[i]); } data.AppendLiteral(16, gold.white_point_chromaticity_x); data.AppendLiteral(16, gold.white_point_chromaticity_y); data.AppendLiteral(32, gold.luminance_max); data.AppendLiteral(32, gold.luminance_min); ASSERT_TRUE(ParseMetadata(data.GenerateData())); VerifyMetadataHdrMdcv(gold); } TEST_F(ObuParserTest, MetadataScalability) { BytesAndBits data; data.AppendLiteral(8, kMetadataTypeScalability); data.AppendLiteral(8, 0); // scalability_mode_idc ASSERT_TRUE(ParseMetadata(data.GenerateData())); } TEST_F(ObuParserTest, MetadataItutT35) { BytesAndBits data; ObuMetadataItutT35 gold; gold.country_code = 0xA6; // 1 0 1 0 0 1 1 0 Switzerland DynamicBuffer payload_bytes; ASSERT_TRUE(payload_bytes.Resize(10)); gold.payload_bytes = payload_bytes.get(); for (int i = 0; i < 10; ++i) { gold.payload_bytes[i] = 9 - i; } gold.payload_size = 10; data.AppendLiteral(8, kMetadataTypeItutT35); data.AppendLiteral(8, gold.country_code); for (int i = 0; i < 10; ++i) { data.AppendLiteral(8, 9 - i); } // For the kMetadataTypeItutT35 metadata type, we must include the trailing // bit so that the end of the itu_t_t35_payload_bytes can be identified. data.AppendLiteral(8, 0x80); data.AppendLiteral(8, 0x00); data.AppendLiteral(8, 0x00); ASSERT_TRUE(ParseMetadata(data.GenerateData())); VerifyMetadataItutT35(gold); gold.country_code = 0xFF; gold.country_code_extension_byte = 10; data.SetLiteral(8, 8, gold.country_code); data.InsertLiteral(16, 8, gold.country_code_extension_byte); ASSERT_TRUE(ParseMetadata(data.GenerateData())); VerifyMetadataItutT35(gold); } TEST_F(ObuParserTest, MetadataTimecode) { BytesAndBits data; data.AppendLiteral(8, kMetadataTypeTimecode); data.AppendLiteral(5, 0); // counting_type data.AppendBit(1); // full_timestamp_flag data.AppendBit(0); // discontinuity_flag data.AppendBit(0); // cnt_dropped_flag data.AppendLiteral(9, 8); // n_frames data.AppendLiteral(6, 59); // seconds_value data.AppendLiteral(6, 59); // minutes_value data.AppendLiteral(5, 23); // hours_value data.AppendLiteral(5, 0); // time_offset_length ASSERT_TRUE(ParseMetadata(data.GenerateData())); } TEST_F(ObuParserTest, MetadataTimecodeInvalidSecondsValue) { BytesAndBits data; data.AppendLiteral(8, kMetadataTypeTimecode); data.AppendLiteral(5, 0); // counting_type data.AppendBit(1); // full_timestamp_flag data.AppendBit(0); // discontinuity_flag data.AppendBit(0); // cnt_dropped_flag data.AppendLiteral(9, 8); // n_frames data.AppendLiteral(6, 60); // seconds_value data.AppendLiteral(6, 59); // minutes_value data.AppendLiteral(5, 23); // hours_value data.AppendLiteral(5, 0); // time_offset_length EXPECT_FALSE(ParseMetadata(data.GenerateData())); } TEST_F(ObuParserTest, MetadataTimecodeInvalidMinutesValue) { BytesAndBits data; data.AppendLiteral(8, kMetadataTypeTimecode); data.AppendLiteral(5, 0); // counting_type data.AppendBit(1); // full_timestamp_flag data.AppendBit(0); // discontinuity_flag data.AppendBit(0); // cnt_dropped_flag data.AppendLiteral(9, 8); // n_frames data.AppendLiteral(6, 59); // seconds_value data.AppendLiteral(6, 60); // minutes_value data.AppendLiteral(5, 23); // hours_value data.AppendLiteral(5, 0); // time_offset_length EXPECT_FALSE(ParseMetadata(data.GenerateData())); } TEST_F(ObuParserTest, MetadataTimecodeInvalidHoursValue) { BytesAndBits data; data.AppendLiteral(8, kMetadataTypeTimecode); data.AppendLiteral(5, 0); // counting_type data.AppendBit(1); // full_timestamp_flag data.AppendBit(0); // discontinuity_flag data.AppendBit(0); // cnt_dropped_flag data.AppendLiteral(9, 8); // n_frames data.AppendLiteral(6, 59); // seconds_value data.AppendLiteral(6, 59); // minutes_value data.AppendLiteral(5, 24); // hours_value data.AppendLiteral(5, 0); // time_offset_length EXPECT_FALSE(ParseMetadata(data.GenerateData())); } } // namespace libgav1