// Copyright 2019 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 "src/buffer_pool.h" #include "src/decoder_impl.h" #include "src/motion_vector.h" #include "src/utils/common.h" #include "src/utils/logging.h" namespace libgav1 { namespace { // 5.9.16. // Find the smallest value of k such that block_size << k is greater than or // equal to target. // // NOTE: TileLog2(block_size, target) is equal to // CeilLog2(ceil((double)target / block_size)) // where the division is a floating-point number division. (This equality holds // even when |target| is equal to 0.) In the special case of block_size == 1, // TileLog2(1, target) is equal to CeilLog2(target). int TileLog2(int block_size, int target) { int k = 0; for (; (block_size << k) < target; ++k) { } return k; } void ParseBitStreamLevel(BitStreamLevel* const level, uint8_t level_bits) { level->major = kMinimumMajorBitstreamLevel + (level_bits >> 2); level->minor = level_bits & 3; } // This function assumes loop_filter is zero-initialized, so only it needs to // set the nonzero default values. void SetDefaultRefDeltas(LoopFilter* const loop_filter) { loop_filter->ref_deltas[kReferenceFrameIntra] = 1; loop_filter->ref_deltas[kReferenceFrameGolden] = -1; loop_filter->ref_deltas[kReferenceFrameAlternate] = -1; loop_filter->ref_deltas[kReferenceFrameAlternate2] = -1; } bool InTemporalLayer(int operating_point_idc, int temporal_id) { return ((operating_point_idc >> temporal_id) & 1) != 0; } bool InSpatialLayer(int operating_point_idc, int spatial_id) { return ((operating_point_idc >> (spatial_id + 8)) & 1) != 0; } // Returns the index of the last nonzero byte in the |data| buffer of |size| // bytes. If there is no nonzero byte in the |data| buffer, returns -1. int GetLastNonzeroByteIndex(const uint8_t* data, size_t size) { // Scan backward for a nonzero byte. if (size > INT_MAX) return -1; int i = static_cast(size) - 1; while (i >= 0 && data[i] == 0) { --i; } return i; } // A cleanup helper class that releases the frame buffer reference held in // |frame| in the destructor. class RefCountedBufferPtrCleanup { public: explicit RefCountedBufferPtrCleanup(RefCountedBufferPtr* frame) : frame_(*frame) {} // Not copyable or movable. RefCountedBufferPtrCleanup(const RefCountedBufferPtrCleanup&) = delete; RefCountedBufferPtrCleanup& operator=(const RefCountedBufferPtrCleanup&) = delete; ~RefCountedBufferPtrCleanup() { frame_ = nullptr; } private: RefCountedBufferPtr& frame_; }; } // namespace bool ObuSequenceHeader::ParametersChanged(const ObuSequenceHeader& old) const { // Note that the operating_parameters field is not compared per Section 7.5: // Within a particular coded video sequence, the contents of // sequence_header_obu must be bit-identical each time the sequence header // appears except for the contents of operating_parameters_info. return memcmp(this, &old, offsetof(ObuSequenceHeader, operating_parameters)) != 0; } // Macros to avoid repeated error checks in the parser code. #define OBU_LOG_AND_RETURN_FALSE \ do { \ LIBGAV1_DLOG(ERROR, "%s:%d (%s): Not enough bits.", __FILE__, __LINE__, \ __func__); \ return false; \ } while (false) #define OBU_PARSER_FAIL \ do { \ if (scratch == -1) { \ OBU_LOG_AND_RETURN_FALSE; \ } \ } while (false) #define OBU_READ_BIT_OR_FAIL \ scratch = bit_reader_->ReadBit(); \ OBU_PARSER_FAIL #define OBU_READ_LITERAL_OR_FAIL(n) \ scratch = bit_reader_->ReadLiteral(n); \ OBU_PARSER_FAIL #define OBU_READ_UVLC_OR_FAIL(x) \ do { \ if (!bit_reader_->ReadUvlc(&(x))) { \ OBU_LOG_AND_RETURN_FALSE; \ } \ } while (false) bool ObuParser::ParseColorConfig(ObuSequenceHeader* sequence_header) { int64_t scratch; ColorConfig* const color_config = &sequence_header->color_config; OBU_READ_BIT_OR_FAIL; const bool high_bitdepth = scratch != 0; if (sequence_header->profile == kProfile2 && high_bitdepth) { OBU_READ_BIT_OR_FAIL; const bool is_twelve_bit = scratch != 0; color_config->bitdepth = is_twelve_bit ? 12 : 10; } else { color_config->bitdepth = high_bitdepth ? 10 : 8; } if (sequence_header->profile == kProfile1) { color_config->is_monochrome = false; } else { OBU_READ_BIT_OR_FAIL; color_config->is_monochrome = scratch != 0; } OBU_READ_BIT_OR_FAIL; const bool color_description_present_flag = scratch != 0; if (color_description_present_flag) { OBU_READ_LITERAL_OR_FAIL(8); color_config->color_primary = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL(8); color_config->transfer_characteristics = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL(8); color_config->matrix_coefficients = static_cast(scratch); } else { color_config->color_primary = kColorPrimaryUnspecified; color_config->transfer_characteristics = kTransferCharacteristicsUnspecified; color_config->matrix_coefficients = kMatrixCoefficientsUnspecified; } if (color_config->is_monochrome) { OBU_READ_BIT_OR_FAIL; color_config->color_range = static_cast(scratch); // Set subsampling_x and subsampling_y to 1 for monochrome. This makes it // easy to allow monochrome to be supported in profile 0. Profile 0 // requires subsampling_x and subsampling_y to be 1. color_config->subsampling_x = 1; color_config->subsampling_y = 1; color_config->chroma_sample_position = kChromaSamplePositionUnknown; } else { if (color_config->color_primary == kColorPrimaryBt709 && color_config->transfer_characteristics == kTransferCharacteristicsSrgb && color_config->matrix_coefficients == kMatrixCoefficientsIdentity) { color_config->color_range = kColorRangeFull; color_config->subsampling_x = 0; color_config->subsampling_y = 0; // YUV 4:4:4 is only allowed in profile 1, or profile 2 with bit depth 12. // See the table at the beginning of Section 6.4.1. if (sequence_header->profile != kProfile1 && (sequence_header->profile != kProfile2 || color_config->bitdepth != 12)) { LIBGAV1_DLOG(ERROR, "YUV 4:4:4 is not allowed in profile %d for bitdepth %d.", sequence_header->profile, color_config->bitdepth); return false; } } else { OBU_READ_BIT_OR_FAIL; color_config->color_range = static_cast(scratch); if (sequence_header->profile == kProfile0) { color_config->subsampling_x = 1; color_config->subsampling_y = 1; } else if (sequence_header->profile == kProfile1) { color_config->subsampling_x = 0; color_config->subsampling_y = 0; } else { if (color_config->bitdepth == 12) { OBU_READ_BIT_OR_FAIL; color_config->subsampling_x = scratch; if (color_config->subsampling_x == 1) { OBU_READ_BIT_OR_FAIL; color_config->subsampling_y = scratch; } else { color_config->subsampling_y = 0; } } else { color_config->subsampling_x = 1; color_config->subsampling_y = 0; } } if (color_config->subsampling_x == 1 && color_config->subsampling_y == 1) { OBU_READ_LITERAL_OR_FAIL(2); color_config->chroma_sample_position = static_cast(scratch); } } OBU_READ_BIT_OR_FAIL; color_config->separate_uv_delta_q = scratch != 0; } if (color_config->matrix_coefficients == kMatrixCoefficientsIdentity && (color_config->subsampling_x != 0 || color_config->subsampling_y != 0)) { LIBGAV1_DLOG(ERROR, "matrix_coefficients is MC_IDENTITY, but subsampling_x (%d) " "and subsampling_y (%d) are not both 0.", color_config->subsampling_x, color_config->subsampling_y); return false; } return true; } bool ObuParser::ParseTimingInfo(ObuSequenceHeader* sequence_header) { int64_t scratch; OBU_READ_BIT_OR_FAIL; sequence_header->timing_info_present_flag = scratch != 0; if (!sequence_header->timing_info_present_flag) return true; TimingInfo* const info = &sequence_header->timing_info; OBU_READ_LITERAL_OR_FAIL(32); info->num_units_in_tick = static_cast(scratch); if (info->num_units_in_tick == 0) { LIBGAV1_DLOG(ERROR, "num_units_in_tick is 0."); return false; } OBU_READ_LITERAL_OR_FAIL(32); info->time_scale = static_cast(scratch); if (info->time_scale == 0) { LIBGAV1_DLOG(ERROR, "time_scale is 0."); return false; } OBU_READ_BIT_OR_FAIL; info->equal_picture_interval = scratch != 0; if (info->equal_picture_interval) { OBU_READ_UVLC_OR_FAIL(info->num_ticks_per_picture); ++info->num_ticks_per_picture; } return true; } bool ObuParser::ParseDecoderModelInfo(ObuSequenceHeader* sequence_header) { if (!sequence_header->timing_info_present_flag) return true; int64_t scratch; OBU_READ_BIT_OR_FAIL; sequence_header->decoder_model_info_present_flag = scratch != 0; if (!sequence_header->decoder_model_info_present_flag) return true; DecoderModelInfo* const info = &sequence_header->decoder_model_info; OBU_READ_LITERAL_OR_FAIL(5); info->encoder_decoder_buffer_delay_length = 1 + scratch; OBU_READ_LITERAL_OR_FAIL(32); info->num_units_in_decoding_tick = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL(5); info->buffer_removal_time_length = 1 + scratch; OBU_READ_LITERAL_OR_FAIL(5); info->frame_presentation_time_length = 1 + scratch; return true; } bool ObuParser::ParseOperatingParameters(ObuSequenceHeader* sequence_header, int index) { int64_t scratch; OBU_READ_BIT_OR_FAIL; sequence_header->decoder_model_present_for_operating_point[index] = scratch != 0; if (!sequence_header->decoder_model_present_for_operating_point[index]) { return true; } OperatingParameters* const params = &sequence_header->operating_parameters; OBU_READ_LITERAL_OR_FAIL( sequence_header->decoder_model_info.encoder_decoder_buffer_delay_length); params->decoder_buffer_delay[index] = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL( sequence_header->decoder_model_info.encoder_decoder_buffer_delay_length); params->encoder_buffer_delay[index] = static_cast(scratch); OBU_READ_BIT_OR_FAIL; params->low_delay_mode_flag[index] = scratch != 0; return true; } bool ObuParser::ParseSequenceHeader(bool seen_frame_header) { ObuSequenceHeader sequence_header = {}; int64_t scratch; OBU_READ_LITERAL_OR_FAIL(3); if (scratch >= kMaxProfiles) { LIBGAV1_DLOG(ERROR, "Invalid profile: %d.", static_cast(scratch)); return false; } sequence_header.profile = static_cast(scratch); OBU_READ_BIT_OR_FAIL; sequence_header.still_picture = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.reduced_still_picture_header = scratch != 0; if (sequence_header.reduced_still_picture_header) { if (!sequence_header.still_picture) { LIBGAV1_DLOG( ERROR, "reduced_still_picture_header is 1, but still_picture is 0."); return false; } sequence_header.operating_points = 1; sequence_header.operating_point_idc[0] = 0; OBU_READ_LITERAL_OR_FAIL(5); ParseBitStreamLevel(&sequence_header.level[0], scratch); } else { if (!ParseTimingInfo(&sequence_header) || !ParseDecoderModelInfo(&sequence_header)) { return false; } OBU_READ_BIT_OR_FAIL; const bool initial_display_delay_present_flag = scratch != 0; OBU_READ_LITERAL_OR_FAIL(5); sequence_header.operating_points = static_cast(1 + scratch); if (operating_point_ >= sequence_header.operating_points) { LIBGAV1_DLOG( ERROR, "Invalid operating point: %d (valid range is [0,%d] inclusive).", operating_point_, sequence_header.operating_points - 1); return false; } for (int i = 0; i < sequence_header.operating_points; ++i) { OBU_READ_LITERAL_OR_FAIL(12); sequence_header.operating_point_idc[i] = static_cast(scratch); for (int j = 0; j < i; ++j) { if (sequence_header.operating_point_idc[i] == sequence_header.operating_point_idc[j]) { LIBGAV1_DLOG(ERROR, "operating_point_idc[%d] (%d) is equal to " "operating_point_idc[%d] (%d).", i, sequence_header.operating_point_idc[i], j, sequence_header.operating_point_idc[j]); return false; } } OBU_READ_LITERAL_OR_FAIL(5); ParseBitStreamLevel(&sequence_header.level[i], scratch); if (sequence_header.level[i].major > 3) { OBU_READ_BIT_OR_FAIL; sequence_header.tier[i] = scratch; } if (sequence_header.decoder_model_info_present_flag && !ParseOperatingParameters(&sequence_header, i)) { return false; } if (initial_display_delay_present_flag) { OBU_READ_BIT_OR_FAIL; if (scratch != 0) { OBU_READ_LITERAL_OR_FAIL(4); sequence_header.initial_display_delay[i] = 1 + scratch; } } } } OBU_READ_LITERAL_OR_FAIL(4); sequence_header.frame_width_bits = 1 + scratch; OBU_READ_LITERAL_OR_FAIL(4); sequence_header.frame_height_bits = 1 + scratch; OBU_READ_LITERAL_OR_FAIL(sequence_header.frame_width_bits); sequence_header.max_frame_width = static_cast(1 + scratch); OBU_READ_LITERAL_OR_FAIL(sequence_header.frame_height_bits); sequence_header.max_frame_height = static_cast(1 + scratch); if (!sequence_header.reduced_still_picture_header) { OBU_READ_BIT_OR_FAIL; sequence_header.frame_id_numbers_present = scratch != 0; } if (sequence_header.frame_id_numbers_present) { OBU_READ_LITERAL_OR_FAIL(4); sequence_header.delta_frame_id_length_bits = 2 + scratch; OBU_READ_LITERAL_OR_FAIL(3); sequence_header.frame_id_length_bits = sequence_header.delta_frame_id_length_bits + 1 + scratch; // Section 6.8.2: It is a requirement of bitstream conformance that the // number of bits needed to read display_frame_id does not exceed 16. This // is equivalent to the constraint that idLen <= 16. if (sequence_header.frame_id_length_bits > 16) { LIBGAV1_DLOG(ERROR, "Invalid frame_id_length_bits: %d.", sequence_header.frame_id_length_bits); return false; } } OBU_READ_BIT_OR_FAIL; sequence_header.use_128x128_superblock = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_filter_intra = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_intra_edge_filter = scratch != 0; if (sequence_header.reduced_still_picture_header) { sequence_header.force_screen_content_tools = kSelectScreenContentTools; sequence_header.force_integer_mv = kSelectIntegerMv; } else { OBU_READ_BIT_OR_FAIL; sequence_header.enable_interintra_compound = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_masked_compound = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_warped_motion = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_dual_filter = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_order_hint = scratch != 0; if (sequence_header.enable_order_hint) { OBU_READ_BIT_OR_FAIL; sequence_header.enable_jnt_comp = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_ref_frame_mvs = scratch != 0; } OBU_READ_BIT_OR_FAIL; sequence_header.choose_screen_content_tools = scratch != 0; if (sequence_header.choose_screen_content_tools) { sequence_header.force_screen_content_tools = kSelectScreenContentTools; } else { OBU_READ_BIT_OR_FAIL; sequence_header.force_screen_content_tools = scratch; } if (sequence_header.force_screen_content_tools > 0) { OBU_READ_BIT_OR_FAIL; sequence_header.choose_integer_mv = scratch != 0; if (sequence_header.choose_integer_mv) { sequence_header.force_integer_mv = kSelectIntegerMv; } else { OBU_READ_BIT_OR_FAIL; sequence_header.force_integer_mv = scratch; } } else { sequence_header.force_integer_mv = kSelectIntegerMv; } if (sequence_header.enable_order_hint) { OBU_READ_LITERAL_OR_FAIL(3); sequence_header.order_hint_bits = 1 + scratch; sequence_header.order_hint_shift_bits = Mod32(32 - sequence_header.order_hint_bits); } } OBU_READ_BIT_OR_FAIL; sequence_header.enable_superres = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_cdef = scratch != 0; OBU_READ_BIT_OR_FAIL; sequence_header.enable_restoration = scratch != 0; if (!ParseColorConfig(&sequence_header)) return false; OBU_READ_BIT_OR_FAIL; sequence_header.film_grain_params_present = scratch != 0; // Compare new sequence header with old sequence header. if (has_sequence_header_ && sequence_header.ParametersChanged(sequence_header_)) { // Between the frame header OBU and the last tile group OBU of the frame, // do not allow the sequence header to change. if (seen_frame_header) { LIBGAV1_DLOG(ERROR, "Sequence header changed in the middle of a frame."); return false; } sequence_header_changed_ = true; decoder_state_.ClearReferenceFrames(); } sequence_header_ = sequence_header; if (!has_sequence_header_) { sequence_header_changed_ = true; } has_sequence_header_ = true; // Section 6.4.1: It is a requirement of bitstream conformance that if // OperatingPointIdc is equal to 0, then obu_extension_flag is equal to 0 for // all OBUs that follow this sequence header until the next sequence header. extension_disallowed_ = (sequence_header_.operating_point_idc[operating_point_] == 0); return true; } // Marks reference frames as invalid for referencing when they are too far in // the past to be referenced by the frame id mechanism. void ObuParser::MarkInvalidReferenceFrames() { // The current lower bound of the frame ids for reference frames. int lower_bound = decoder_state_.current_frame_id - (1 << sequence_header_.delta_frame_id_length_bits); // True if lower_bound is smaller than current_frame_id. False if lower_bound // wraps around (in modular arithmetic) to the other side of current_frame_id. bool lower_bound_is_smaller = true; if (lower_bound <= 0) { lower_bound += 1 << sequence_header_.frame_id_length_bits; lower_bound_is_smaller = false; } for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const uint16_t reference_frame_id = decoder_state_.reference_frame_id[i]; if (lower_bound_is_smaller) { if (reference_frame_id > decoder_state_.current_frame_id || reference_frame_id < lower_bound) { decoder_state_.reference_frame[i] = nullptr; } } else { if (reference_frame_id > decoder_state_.current_frame_id && reference_frame_id < lower_bound) { decoder_state_.reference_frame[i] = nullptr; } } } } bool ObuParser::ParseFrameSizeAndRenderSize() { int64_t scratch; // Frame Size. if (frame_header_.frame_size_override_flag) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.frame_width_bits); frame_header_.width = static_cast(1 + scratch); OBU_READ_LITERAL_OR_FAIL(sequence_header_.frame_height_bits); frame_header_.height = static_cast(1 + scratch); if (frame_header_.width > sequence_header_.max_frame_width || frame_header_.height > sequence_header_.max_frame_height) { LIBGAV1_DLOG(ERROR, "Frame dimensions are larger than the maximum values"); return false; } } else { frame_header_.width = sequence_header_.max_frame_width; frame_header_.height = sequence_header_.max_frame_height; } if (!ParseSuperResParametersAndComputeImageSize()) return false; // Render Size. OBU_READ_BIT_OR_FAIL; frame_header_.render_and_frame_size_different = scratch != 0; if (frame_header_.render_and_frame_size_different) { OBU_READ_LITERAL_OR_FAIL(16); frame_header_.render_width = static_cast(1 + scratch); OBU_READ_LITERAL_OR_FAIL(16); frame_header_.render_height = static_cast(1 + scratch); } else { frame_header_.render_width = frame_header_.upscaled_width; frame_header_.render_height = frame_header_.height; } return true; } bool ObuParser::ParseSuperResParametersAndComputeImageSize() { int64_t scratch; // SuperRes. frame_header_.upscaled_width = frame_header_.width; frame_header_.use_superres = false; if (sequence_header_.enable_superres) { OBU_READ_BIT_OR_FAIL; frame_header_.use_superres = scratch != 0; } if (frame_header_.use_superres) { OBU_READ_LITERAL_OR_FAIL(3); // 9 is the smallest value for the denominator. frame_header_.superres_scale_denominator = scratch + 9; frame_header_.width = (frame_header_.upscaled_width * kSuperResScaleNumerator + (frame_header_.superres_scale_denominator / 2)) / frame_header_.superres_scale_denominator; } else { frame_header_.superres_scale_denominator = kSuperResScaleNumerator; } assert(frame_header_.width != 0); assert(frame_header_.height != 0); // Check if multiplying upscaled_width by height would overflow. assert(frame_header_.upscaled_width >= frame_header_.width); if (frame_header_.upscaled_width > INT32_MAX / frame_header_.height) { LIBGAV1_DLOG(ERROR, "Frame dimensions too big: width=%d height=%d.", frame_header_.width, frame_header_.height); return false; } frame_header_.columns4x4 = ((frame_header_.width + 7) >> 3) << 1; frame_header_.rows4x4 = ((frame_header_.height + 7) >> 3) << 1; return true; } bool ObuParser::ValidateInterFrameSize() const { for (int index : frame_header_.reference_frame_index) { const RefCountedBuffer* reference_frame = decoder_state_.reference_frame[index].get(); if (2 * frame_header_.width < reference_frame->upscaled_width() || 2 * frame_header_.height < reference_frame->frame_height() || frame_header_.width > 16 * reference_frame->upscaled_width() || frame_header_.height > 16 * reference_frame->frame_height()) { LIBGAV1_DLOG(ERROR, "Invalid inter frame size: width=%d, height=%d. Reference " "frame: index=%d, upscaled width=%d, height=%d.", frame_header_.width, frame_header_.height, index, reference_frame->upscaled_width(), reference_frame->frame_height()); return false; } } return true; } bool ObuParser::ParseReferenceOrderHint() { if (!frame_header_.error_resilient_mode || !sequence_header_.enable_order_hint) { return true; } int64_t scratch; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.order_hint_bits); frame_header_.reference_order_hint[i] = scratch; if (frame_header_.reference_order_hint[i] != decoder_state_.reference_order_hint[i]) { decoder_state_.reference_frame[i] = nullptr; } } return true; } // static int ObuParser::FindLatestBackwardReference( const int current_frame_hint, const std::array& shifted_order_hints, const std::array& used_frame) { int ref = -1; int latest_order_hint = INT_MIN; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const int hint = shifted_order_hints[i]; if (!used_frame[i] && hint >= current_frame_hint && hint >= latest_order_hint) { ref = i; latest_order_hint = hint; } } return ref; } // static int ObuParser::FindEarliestBackwardReference( const int current_frame_hint, const std::array& shifted_order_hints, const std::array& used_frame) { int ref = -1; int earliest_order_hint = INT_MAX; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const int hint = shifted_order_hints[i]; if (!used_frame[i] && hint >= current_frame_hint && hint < earliest_order_hint) { ref = i; earliest_order_hint = hint; } } return ref; } // static int ObuParser::FindLatestForwardReference( const int current_frame_hint, const std::array& shifted_order_hints, const std::array& used_frame) { int ref = -1; int latest_order_hint = INT_MIN; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const int hint = shifted_order_hints[i]; if (!used_frame[i] && hint < current_frame_hint && hint >= latest_order_hint) { ref = i; latest_order_hint = hint; } } return ref; } // static int ObuParser::FindReferenceWithSmallestOutputOrder( const std::array& shifted_order_hints) { int ref = -1; int earliest_order_hint = INT_MAX; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const int hint = shifted_order_hints[i]; if (hint < earliest_order_hint) { ref = i; earliest_order_hint = hint; } } return ref; } // Computes the elements in the frame_header_.reference_frame_index array // based on: // * the syntax elements last_frame_idx and gold_frame_idx, and // * the values stored within the decoder_state_.reference_order_hint array // (these values represent the least significant bits of the expected output // order of the frames). // // Frame type: { // libgav1_name spec_name int // kReferenceFrameLast, LAST_FRAME 1 // kReferenceFrameLast2, LAST2_FRAME 2 // kReferenceFrameLast3, LAST3_FRAME 3 // kReferenceFrameGolden, GOLDEN_FRAME 4 // kReferenceFrameBackward, BWDREF_FRAME 5 // kReferenceFrameAlternate2, ALTREF2_FRAME 6 // kReferenceFrameAlternate, ALTREF_FRAME 7 // } // // A typical case of a group of pictures (frames) in display order: // (However, more complex cases are possibly allowed in terms of // bitstream conformance.) // // | | | | | | | | // | | | | | | | | // | | | | | | | | // | | | | | | | | // // 4 3 2 1 current_frame 5 6 7 // bool ObuParser::SetFrameReferences(const int8_t last_frame_idx, const int8_t gold_frame_idx) { // Set the ref_frame_idx entries for kReferenceFrameLast and // kReferenceFrameGolden to last_frame_idx and gold_frame_idx. Initialize // the other entries to -1. for (int8_t& reference_frame_index : frame_header_.reference_frame_index) { reference_frame_index = -1; } frame_header_ .reference_frame_index[kReferenceFrameLast - kReferenceFrameLast] = last_frame_idx; frame_header_ .reference_frame_index[kReferenceFrameGolden - kReferenceFrameLast] = gold_frame_idx; // used_frame records which reference frames have been used. std::array used_frame; used_frame.fill(false); used_frame[last_frame_idx] = true; used_frame[gold_frame_idx] = true; assert(sequence_header_.order_hint_bits >= 1); const int current_frame_hint = 1 << (sequence_header_.order_hint_bits - 1); // shifted_order_hints contains the expected output order shifted such that // the current frame has hint equal to current_frame_hint. std::array shifted_order_hints; for (int i = 0; i < kNumReferenceFrameTypes; ++i) { const int relative_distance = GetRelativeDistance( decoder_state_.reference_order_hint[i], frame_header_.order_hint, sequence_header_.order_hint_shift_bits); shifted_order_hints[i] = current_frame_hint + relative_distance; } // The expected output orders for kReferenceFrameLast and // kReferenceFrameGolden. const int last_order_hint = shifted_order_hints[last_frame_idx]; const int gold_order_hint = shifted_order_hints[gold_frame_idx]; // Section 7.8: It is a requirement of bitstream conformance that // lastOrderHint and goldOrderHint are strictly less than curFrameHint. if (last_order_hint >= current_frame_hint || gold_order_hint >= current_frame_hint) { return false; } // Find a backward reference to the frame with highest output order. If // found, set the kReferenceFrameAlternate reference to that backward // reference. int ref = FindLatestBackwardReference(current_frame_hint, shifted_order_hints, used_frame); if (ref >= 0) { frame_header_ .reference_frame_index[kReferenceFrameAlternate - kReferenceFrameLast] = ref; used_frame[ref] = true; } // Find a backward reference to the closest frame. If found, set the // kReferenceFrameBackward reference to that backward reference. ref = FindEarliestBackwardReference(current_frame_hint, shifted_order_hints, used_frame); if (ref >= 0) { frame_header_ .reference_frame_index[kReferenceFrameBackward - kReferenceFrameLast] = ref; used_frame[ref] = true; } // Set the kReferenceFrameAlternate2 reference to the next closest backward // reference. ref = FindEarliestBackwardReference(current_frame_hint, shifted_order_hints, used_frame); if (ref >= 0) { frame_header_.reference_frame_index[kReferenceFrameAlternate2 - kReferenceFrameLast] = ref; used_frame[ref] = true; } // The remaining references are set to be forward references in // reverse chronological order. static constexpr ReferenceFrameType kRefFrameList[kNumInterReferenceFrameTypes - 2] = { kReferenceFrameLast2, kReferenceFrameLast3, kReferenceFrameBackward, kReferenceFrameAlternate2, kReferenceFrameAlternate}; for (const ReferenceFrameType ref_frame : kRefFrameList) { if (frame_header_.reference_frame_index[ref_frame - kReferenceFrameLast] < 0) { ref = FindLatestForwardReference(current_frame_hint, shifted_order_hints, used_frame); if (ref >= 0) { frame_header_.reference_frame_index[ref_frame - kReferenceFrameLast] = ref; used_frame[ref] = true; } } } // Finally, any remaining references are set to the reference frame with // smallest output order. ref = FindReferenceWithSmallestOutputOrder(shifted_order_hints); assert(ref >= 0); for (int8_t& reference_frame_index : frame_header_.reference_frame_index) { if (reference_frame_index < 0) { reference_frame_index = ref; } } return true; } bool ObuParser::ParseLoopFilterParameters() { LoopFilter* const loop_filter = &frame_header_.loop_filter; if (frame_header_.coded_lossless || frame_header_.allow_intrabc) { SetDefaultRefDeltas(loop_filter); return true; } // IsIntraFrame implies kPrimaryReferenceNone. assert(!IsIntraFrame(frame_header_.frame_type) || frame_header_.primary_reference_frame == kPrimaryReferenceNone); if (frame_header_.primary_reference_frame == kPrimaryReferenceNone) { // Part of the setup_past_independence() function in the spec. It is not // necessary to set loop_filter->delta_enabled to true. See // https://crbug.com/aomedia/2305. SetDefaultRefDeltas(loop_filter); } else { // Part of the load_previous() function in the spec. const int prev_frame_index = frame_header_ .reference_frame_index[frame_header_.primary_reference_frame]; const RefCountedBuffer* prev_frame = decoder_state_.reference_frame[prev_frame_index].get(); loop_filter->ref_deltas = prev_frame->loop_filter_ref_deltas(); loop_filter->mode_deltas = prev_frame->loop_filter_mode_deltas(); } int64_t scratch; for (int i = 0; i < 2; ++i) { OBU_READ_LITERAL_OR_FAIL(6); loop_filter->level[i] = scratch; } if (!sequence_header_.color_config.is_monochrome && (loop_filter->level[0] != 0 || loop_filter->level[1] != 0)) { for (int i = 2; i < 4; ++i) { OBU_READ_LITERAL_OR_FAIL(6); loop_filter->level[i] = scratch; } } OBU_READ_LITERAL_OR_FAIL(3); loop_filter->sharpness = scratch; OBU_READ_BIT_OR_FAIL; loop_filter->delta_enabled = scratch != 0; if (loop_filter->delta_enabled) { OBU_READ_BIT_OR_FAIL; loop_filter->delta_update = scratch != 0; if (loop_filter->delta_update) { for (auto& ref_delta : loop_filter->ref_deltas) { OBU_READ_BIT_OR_FAIL; const bool update_ref_delta = scratch != 0; if (update_ref_delta) { int scratch_int; if (!bit_reader_->ReadInverseSignedLiteral(6, &scratch_int)) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } ref_delta = scratch_int; } } for (auto& mode_delta : loop_filter->mode_deltas) { OBU_READ_BIT_OR_FAIL; const bool update_mode_delta = scratch != 0; if (update_mode_delta) { int scratch_int; if (!bit_reader_->ReadInverseSignedLiteral(6, &scratch_int)) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } mode_delta = scratch_int; } } } } else { loop_filter->delta_update = false; } return true; } bool ObuParser::ParseDeltaQuantizer(int8_t* const delta) { int64_t scratch; *delta = 0; OBU_READ_BIT_OR_FAIL; const bool delta_coded = scratch != 0; if (delta_coded) { int scratch_int; if (!bit_reader_->ReadInverseSignedLiteral(6, &scratch_int)) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } *delta = scratch_int; } return true; } bool ObuParser::ParseQuantizerParameters() { int64_t scratch; QuantizerParameters* const quantizer = &frame_header_.quantizer; OBU_READ_LITERAL_OR_FAIL(8); quantizer->base_index = scratch; if (!ParseDeltaQuantizer(&quantizer->delta_dc[kPlaneY])) return false; if (!sequence_header_.color_config.is_monochrome) { bool diff_uv_delta = false; if (sequence_header_.color_config.separate_uv_delta_q) { OBU_READ_BIT_OR_FAIL; diff_uv_delta = scratch != 0; } if (!ParseDeltaQuantizer(&quantizer->delta_dc[kPlaneU]) || !ParseDeltaQuantizer(&quantizer->delta_ac[kPlaneU])) { return false; } if (diff_uv_delta) { if (!ParseDeltaQuantizer(&quantizer->delta_dc[kPlaneV]) || !ParseDeltaQuantizer(&quantizer->delta_ac[kPlaneV])) { return false; } } else { quantizer->delta_dc[kPlaneV] = quantizer->delta_dc[kPlaneU]; quantizer->delta_ac[kPlaneV] = quantizer->delta_ac[kPlaneU]; } } OBU_READ_BIT_OR_FAIL; quantizer->use_matrix = scratch != 0; if (quantizer->use_matrix) { OBU_READ_LITERAL_OR_FAIL(4); quantizer->matrix_level[kPlaneY] = scratch; OBU_READ_LITERAL_OR_FAIL(4); quantizer->matrix_level[kPlaneU] = scratch; if (sequence_header_.color_config.separate_uv_delta_q) { OBU_READ_LITERAL_OR_FAIL(4); quantizer->matrix_level[kPlaneV] = scratch; } else { quantizer->matrix_level[kPlaneV] = quantizer->matrix_level[kPlaneU]; } } return true; } // This method implements the following functions in the spec: // - segmentation_params() // - part of setup_past_independence(): Set the FeatureData and FeatureEnabled // arrays to all 0. // - part of load_previous(): Call load_segmentation_params(). // // A careful analysis of the spec shows the part of setup_past_independence() // can be optimized away and the part of load_previous() only needs to be // invoked under a specific condition. Although the logic looks different from // the spec, it is equivalent and more efficient. bool ObuParser::ParseSegmentationParameters() { int64_t scratch; Segmentation* const segmentation = &frame_header_.segmentation; OBU_READ_BIT_OR_FAIL; segmentation->enabled = scratch != 0; if (!segmentation->enabled) return true; if (frame_header_.primary_reference_frame == kPrimaryReferenceNone) { segmentation->update_map = true; segmentation->update_data = true; } else { OBU_READ_BIT_OR_FAIL; segmentation->update_map = scratch != 0; if (segmentation->update_map) { OBU_READ_BIT_OR_FAIL; segmentation->temporal_update = scratch != 0; } OBU_READ_BIT_OR_FAIL; segmentation->update_data = scratch != 0; if (!segmentation->update_data) { // Part of the load_previous() function in the spec. const int prev_frame_index = frame_header_ .reference_frame_index[frame_header_.primary_reference_frame]; decoder_state_.reference_frame[prev_frame_index] ->GetSegmentationParameters(segmentation); return true; } } for (int8_t i = 0; i < kMaxSegments; ++i) { for (int8_t j = 0; j < kSegmentFeatureMax; ++j) { OBU_READ_BIT_OR_FAIL; segmentation->feature_enabled[i][j] = scratch != 0; if (segmentation->feature_enabled[i][j]) { if (Segmentation::FeatureSigned(static_cast(j))) { int scratch_int; if (!bit_reader_->ReadInverseSignedLiteral( kSegmentationFeatureBits[j], &scratch_int)) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } segmentation->feature_data[i][j] = Clip3(scratch_int, -kSegmentationFeatureMaxValues[j], kSegmentationFeatureMaxValues[j]); } else { if (kSegmentationFeatureBits[j] > 0) { OBU_READ_LITERAL_OR_FAIL(kSegmentationFeatureBits[j]); segmentation->feature_data[i][j] = Clip3( static_cast(scratch), 0, kSegmentationFeatureMaxValues[j]); } else { segmentation->feature_data[i][j] = 0; } } segmentation->last_active_segment_id = i; if (j >= kSegmentFeatureReferenceFrame) { segmentation->segment_id_pre_skip = true; } } } } return true; } bool ObuParser::ParseQuantizerIndexDeltaParameters() { int64_t scratch; if (frame_header_.quantizer.base_index > 0) { OBU_READ_BIT_OR_FAIL; frame_header_.delta_q.present = scratch != 0; if (frame_header_.delta_q.present) { OBU_READ_LITERAL_OR_FAIL(2); frame_header_.delta_q.scale = scratch; } } return true; } bool ObuParser::ParseLoopFilterDeltaParameters() { int64_t scratch; if (frame_header_.delta_q.present) { if (!frame_header_.allow_intrabc) { OBU_READ_BIT_OR_FAIL; frame_header_.delta_lf.present = scratch != 0; } if (frame_header_.delta_lf.present) { OBU_READ_LITERAL_OR_FAIL(2); frame_header_.delta_lf.scale = scratch; OBU_READ_BIT_OR_FAIL; frame_header_.delta_lf.multi = scratch != 0; } } return true; } void ObuParser::ComputeSegmentLosslessAndQIndex() { frame_header_.coded_lossless = true; Segmentation* const segmentation = &frame_header_.segmentation; const QuantizerParameters* const quantizer = &frame_header_.quantizer; for (int i = 0; i < kMaxSegments; ++i) { segmentation->qindex[i] = GetQIndex(*segmentation, i, quantizer->base_index); segmentation->lossless[i] = segmentation->qindex[i] == 0 && quantizer->delta_dc[kPlaneY] == 0 && quantizer->delta_dc[kPlaneU] == 0 && quantizer->delta_ac[kPlaneU] == 0 && quantizer->delta_dc[kPlaneV] == 0 && quantizer->delta_ac[kPlaneV] == 0; if (!segmentation->lossless[i]) frame_header_.coded_lossless = false; // The spec calls for setting up a two-dimensional SegQMLevel array here. // We avoid the SegQMLevel array by using segmentation->lossless[i] and // quantizer->matrix_level[plane] directly in the reconstruct process of // Section 7.12.3. } frame_header_.upscaled_lossless = frame_header_.coded_lossless && frame_header_.width == frame_header_.upscaled_width; } bool ObuParser::ParseCdefParameters() { const int coeff_shift = sequence_header_.color_config.bitdepth - 8; if (frame_header_.coded_lossless || frame_header_.allow_intrabc || !sequence_header_.enable_cdef) { frame_header_.cdef.damping = 3 + coeff_shift; return true; } Cdef* const cdef = &frame_header_.cdef; int64_t scratch; OBU_READ_LITERAL_OR_FAIL(2); cdef->damping = scratch + 3 + coeff_shift; OBU_READ_LITERAL_OR_FAIL(2); cdef->bits = scratch; for (int i = 0; i < (1 << cdef->bits); ++i) { OBU_READ_LITERAL_OR_FAIL(4); cdef->y_primary_strength[i] = scratch << coeff_shift; OBU_READ_LITERAL_OR_FAIL(2); cdef->y_secondary_strength[i] = scratch; if (cdef->y_secondary_strength[i] == 3) ++cdef->y_secondary_strength[i]; cdef->y_secondary_strength[i] <<= coeff_shift; if (sequence_header_.color_config.is_monochrome) continue; OBU_READ_LITERAL_OR_FAIL(4); cdef->uv_primary_strength[i] = scratch << coeff_shift; OBU_READ_LITERAL_OR_FAIL(2); cdef->uv_secondary_strength[i] = scratch; if (cdef->uv_secondary_strength[i] == 3) ++cdef->uv_secondary_strength[i]; cdef->uv_secondary_strength[i] <<= coeff_shift; } return true; } bool ObuParser::ParseLoopRestorationParameters() { if (frame_header_.upscaled_lossless || frame_header_.allow_intrabc || !sequence_header_.enable_restoration) { return true; } int64_t scratch; bool uses_loop_restoration = false; bool uses_chroma_loop_restoration = false; LoopRestoration* const loop_restoration = &frame_header_.loop_restoration; const int num_planes = sequence_header_.color_config.is_monochrome ? kMaxPlanesMonochrome : kMaxPlanes; for (int i = 0; i < num_planes; ++i) { OBU_READ_LITERAL_OR_FAIL(2); loop_restoration->type[i] = static_cast(scratch); if (loop_restoration->type[i] != kLoopRestorationTypeNone) { uses_loop_restoration = true; if (i > 0) uses_chroma_loop_restoration = true; } } if (uses_loop_restoration) { uint8_t unit_shift; if (sequence_header_.use_128x128_superblock) { OBU_READ_BIT_OR_FAIL; unit_shift = scratch + 1; } else { OBU_READ_BIT_OR_FAIL; unit_shift = scratch; if (unit_shift != 0) { OBU_READ_BIT_OR_FAIL; const uint8_t unit_extra_shift = scratch; unit_shift += unit_extra_shift; } } loop_restoration->unit_size_log2[kPlaneY] = 6 + unit_shift; uint8_t uv_shift = 0; if (sequence_header_.color_config.subsampling_x != 0 && sequence_header_.color_config.subsampling_y != 0 && uses_chroma_loop_restoration) { OBU_READ_BIT_OR_FAIL; uv_shift = scratch; } loop_restoration->unit_size_log2[kPlaneU] = loop_restoration->unit_size_log2[kPlaneV] = loop_restoration->unit_size_log2[0] - uv_shift; } return true; } bool ObuParser::ParseTxModeSyntax() { if (frame_header_.coded_lossless) { frame_header_.tx_mode = kTxModeOnly4x4; return true; } int64_t scratch; OBU_READ_BIT_OR_FAIL; frame_header_.tx_mode = (scratch == 1) ? kTxModeSelect : kTxModeLargest; return true; } bool ObuParser::ParseFrameReferenceModeSyntax() { int64_t scratch; if (!IsIntraFrame(frame_header_.frame_type)) { OBU_READ_BIT_OR_FAIL; frame_header_.reference_mode_select = scratch != 0; } return true; } bool ObuParser::IsSkipModeAllowed() { if (IsIntraFrame(frame_header_.frame_type) || !frame_header_.reference_mode_select || !sequence_header_.enable_order_hint) { return false; } // Identify the nearest forward and backward references. int forward_index = -1; int backward_index = -1; int forward_hint = -1; int backward_hint = -1; for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { const unsigned int reference_hint = decoder_state_ .reference_order_hint[frame_header_.reference_frame_index[i]]; // TODO(linfengz): |relative_distance| equals // current_frame_->reference_info()-> // relative_distance_from[i + kReferenceFrameLast]; // However, the unit test ObuParserTest.SkipModeParameters() would fail. // Will figure out how to initialize |current_frame_.reference_info_| in the // RefCountedBuffer later. const int relative_distance = GetRelativeDistance(reference_hint, frame_header_.order_hint, sequence_header_.order_hint_shift_bits); if (relative_distance < 0) { if (forward_index < 0 || GetRelativeDistance(reference_hint, forward_hint, sequence_header_.order_hint_shift_bits) > 0) { forward_index = i; forward_hint = reference_hint; } } else if (relative_distance > 0) { if (backward_index < 0 || GetRelativeDistance(reference_hint, backward_hint, sequence_header_.order_hint_shift_bits) < 0) { backward_index = i; backward_hint = reference_hint; } } } if (forward_index < 0) return false; if (backward_index >= 0) { // Bidirectional prediction. frame_header_.skip_mode_frame[0] = static_cast( kReferenceFrameLast + std::min(forward_index, backward_index)); frame_header_.skip_mode_frame[1] = static_cast( kReferenceFrameLast + std::max(forward_index, backward_index)); return true; } // Forward prediction only. Identify the second nearest forward reference. int second_forward_index = -1; int second_forward_hint = -1; for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { const unsigned int reference_hint = decoder_state_ .reference_order_hint[frame_header_.reference_frame_index[i]]; if (GetRelativeDistance(reference_hint, forward_hint, sequence_header_.order_hint_shift_bits) < 0) { if (second_forward_index < 0 || GetRelativeDistance(reference_hint, second_forward_hint, sequence_header_.order_hint_shift_bits) > 0) { second_forward_index = i; second_forward_hint = reference_hint; } } } if (second_forward_index < 0) return false; frame_header_.skip_mode_frame[0] = static_cast( kReferenceFrameLast + std::min(forward_index, second_forward_index)); frame_header_.skip_mode_frame[1] = static_cast( kReferenceFrameLast + std::max(forward_index, second_forward_index)); return true; } bool ObuParser::ParseSkipModeParameters() { if (!IsSkipModeAllowed()) return true; int64_t scratch; OBU_READ_BIT_OR_FAIL; frame_header_.skip_mode_present = scratch != 0; return true; } // Sets frame_header_.global_motion[ref].params[index]. bool ObuParser::ParseGlobalParamSyntax( int ref, int index, const std::array& prev_global_motions) { GlobalMotion* const global_motion = &frame_header_.global_motion[ref]; const GlobalMotion* const prev_global_motion = &prev_global_motions[ref]; int abs_bits = kGlobalMotionAlphaBits; int precision_bits = kGlobalMotionAlphaPrecisionBits; if (index < 2) { if (global_motion->type == kGlobalMotionTransformationTypeTranslation) { const auto high_precision_mv_factor = static_cast(!frame_header_.allow_high_precision_mv); abs_bits = kGlobalMotionTranslationOnlyBits - high_precision_mv_factor; precision_bits = kGlobalMotionTranslationOnlyPrecisionBits - high_precision_mv_factor; } else { abs_bits = kGlobalMotionTranslationBits; precision_bits = kGlobalMotionTranslationPrecisionBits; } } const int precision_diff = kWarpedModelPrecisionBits - precision_bits; const int round = (index % 3 == 2) ? 1 << kWarpedModelPrecisionBits : 0; const int sub = (index % 3 == 2) ? 1 << precision_bits : 0; const int mx = 1 << abs_bits; const int reference = (prev_global_motion->params[index] >> precision_diff) - sub; int scratch; if (!bit_reader_->DecodeSignedSubexpWithReference( -mx, mx + 1, reference, kGlobalMotionReadControl, &scratch)) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } global_motion->params[index] = LeftShift(scratch, precision_diff) + round; return true; } bool ObuParser::ParseGlobalMotionParameters() { for (int ref = kReferenceFrameLast; ref <= kReferenceFrameAlternate; ++ref) { frame_header_.global_motion[ref].type = kGlobalMotionTransformationTypeIdentity; for (int i = 0; i < 6; ++i) { frame_header_.global_motion[ref].params[i] = (i % 3 == 2) ? 1 << kWarpedModelPrecisionBits : 0; } } if (IsIntraFrame(frame_header_.frame_type)) return true; const std::array* prev_global_motions = nullptr; if (frame_header_.primary_reference_frame == kPrimaryReferenceNone) { // Part of the setup_past_independence() function in the spec. The value // that the spec says PrevGmParams[ref][i] should be set to is exactly // the value frame_header_.global_motion[ref].params[i] is set to by the // for loop above. Therefore prev_global_motions can simply point to // frame_header_.global_motion. prev_global_motions = &frame_header_.global_motion; } else { // Part of the load_previous() function in the spec. const int prev_frame_index = frame_header_ .reference_frame_index[frame_header_.primary_reference_frame]; prev_global_motions = &decoder_state_.reference_frame[prev_frame_index]->GlobalMotions(); } for (int ref = kReferenceFrameLast; ref <= kReferenceFrameAlternate; ++ref) { GlobalMotion* const global_motion = &frame_header_.global_motion[ref]; int64_t scratch; OBU_READ_BIT_OR_FAIL; const bool is_global = scratch != 0; if (is_global) { OBU_READ_BIT_OR_FAIL; const bool is_rot_zoom = scratch != 0; if (is_rot_zoom) { global_motion->type = kGlobalMotionTransformationTypeRotZoom; } else { OBU_READ_BIT_OR_FAIL; const bool is_translation = scratch != 0; global_motion->type = is_translation ? kGlobalMotionTransformationTypeTranslation : kGlobalMotionTransformationTypeAffine; } } else { global_motion->type = kGlobalMotionTransformationTypeIdentity; } if (global_motion->type >= kGlobalMotionTransformationTypeRotZoom) { if (!ParseGlobalParamSyntax(ref, 2, *prev_global_motions) || !ParseGlobalParamSyntax(ref, 3, *prev_global_motions)) { return false; } if (global_motion->type == kGlobalMotionTransformationTypeAffine) { if (!ParseGlobalParamSyntax(ref, 4, *prev_global_motions) || !ParseGlobalParamSyntax(ref, 5, *prev_global_motions)) { return false; } } else { global_motion->params[4] = -global_motion->params[3]; global_motion->params[5] = global_motion->params[2]; } } if (global_motion->type >= kGlobalMotionTransformationTypeTranslation) { if (!ParseGlobalParamSyntax(ref, 0, *prev_global_motions) || !ParseGlobalParamSyntax(ref, 1, *prev_global_motions)) { return false; } } } return true; } bool ObuParser::ParseFilmGrainParameters() { if (!sequence_header_.film_grain_params_present || (!frame_header_.show_frame && !frame_header_.showable_frame)) { // frame_header_.film_grain_params is already zero-initialized. return true; } FilmGrainParams& film_grain_params = frame_header_.film_grain_params; int64_t scratch; OBU_READ_BIT_OR_FAIL; film_grain_params.apply_grain = scratch != 0; if (!film_grain_params.apply_grain) { // film_grain_params is already zero-initialized. return true; } OBU_READ_LITERAL_OR_FAIL(16); film_grain_params.grain_seed = static_cast(scratch); film_grain_params.update_grain = true; if (frame_header_.frame_type == kFrameInter) { OBU_READ_BIT_OR_FAIL; film_grain_params.update_grain = scratch != 0; } if (!film_grain_params.update_grain) { OBU_READ_LITERAL_OR_FAIL(3); film_grain_params.reference_index = static_cast(scratch); bool found = false; for (const auto index : frame_header_.reference_frame_index) { if (film_grain_params.reference_index == index) { found = true; break; } } if (!found) { static_assert(sizeof(frame_header_.reference_frame_index) / sizeof(frame_header_.reference_frame_index[0]) == 7, ""); LIBGAV1_DLOG(ERROR, "Invalid value for film_grain_params_ref_idx (%d). " "ref_frame_idx = {%d, %d, %d, %d, %d, %d, %d}", film_grain_params.reference_index, frame_header_.reference_frame_index[0], frame_header_.reference_frame_index[1], frame_header_.reference_frame_index[2], frame_header_.reference_frame_index[3], frame_header_.reference_frame_index[4], frame_header_.reference_frame_index[5], frame_header_.reference_frame_index[6]); return false; } const RefCountedBuffer* grain_params_reference_frame = decoder_state_.reference_frame[film_grain_params.reference_index].get(); if (grain_params_reference_frame == nullptr) { LIBGAV1_DLOG(ERROR, "Buffer %d does not contain a decoded frame", film_grain_params.reference_index); return false; } const int temp_grain_seed = film_grain_params.grain_seed; const bool temp_update_grain = film_grain_params.update_grain; const int temp_reference_index = film_grain_params.reference_index; film_grain_params = grain_params_reference_frame->film_grain_params(); film_grain_params.grain_seed = temp_grain_seed; film_grain_params.update_grain = temp_update_grain; film_grain_params.reference_index = temp_reference_index; return true; } OBU_READ_LITERAL_OR_FAIL(4); film_grain_params.num_y_points = scratch; if (film_grain_params.num_y_points > 14) { LIBGAV1_DLOG(ERROR, "Invalid value for num_y_points (%d).", film_grain_params.num_y_points); return false; } for (int i = 0; i < film_grain_params.num_y_points; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_y_value[i] = scratch; if (i != 0 && film_grain_params.point_y_value[i - 1] >= film_grain_params.point_y_value[i]) { LIBGAV1_DLOG(ERROR, "point_y_value[%d] (%d) >= point_y_value[%d] (%d).", i - 1, film_grain_params.point_y_value[i - 1], i, film_grain_params.point_y_value[i]); return false; } OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_y_scaling[i] = scratch; } if (sequence_header_.color_config.is_monochrome) { film_grain_params.chroma_scaling_from_luma = false; } else { OBU_READ_BIT_OR_FAIL; film_grain_params.chroma_scaling_from_luma = scratch != 0; } if (sequence_header_.color_config.is_monochrome || film_grain_params.chroma_scaling_from_luma || (sequence_header_.color_config.subsampling_x == 1 && sequence_header_.color_config.subsampling_y == 1 && film_grain_params.num_y_points == 0)) { film_grain_params.num_u_points = 0; film_grain_params.num_v_points = 0; } else { OBU_READ_LITERAL_OR_FAIL(4); film_grain_params.num_u_points = scratch; if (film_grain_params.num_u_points > 10) { LIBGAV1_DLOG(ERROR, "Invalid value for num_u_points (%d).", film_grain_params.num_u_points); return false; } for (int i = 0; i < film_grain_params.num_u_points; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_u_value[i] = scratch; if (i != 0 && film_grain_params.point_u_value[i - 1] >= film_grain_params.point_u_value[i]) { LIBGAV1_DLOG(ERROR, "point_u_value[%d] (%d) >= point_u_value[%d] (%d).", i - 1, film_grain_params.point_u_value[i - 1], i, film_grain_params.point_u_value[i]); return false; } OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_u_scaling[i] = scratch; } OBU_READ_LITERAL_OR_FAIL(4); film_grain_params.num_v_points = scratch; if (film_grain_params.num_v_points > 10) { LIBGAV1_DLOG(ERROR, "Invalid value for num_v_points (%d).", film_grain_params.num_v_points); return false; } if (sequence_header_.color_config.subsampling_x == 1 && sequence_header_.color_config.subsampling_y == 1 && (film_grain_params.num_u_points == 0) != (film_grain_params.num_v_points == 0)) { LIBGAV1_DLOG(ERROR, "Invalid values for num_u_points (%d) and num_v_points (%d) " "for 4:2:0 chroma subsampling.", film_grain_params.num_u_points, film_grain_params.num_v_points); return false; } for (int i = 0; i < film_grain_params.num_v_points; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_v_value[i] = scratch; if (i != 0 && film_grain_params.point_v_value[i - 1] >= film_grain_params.point_v_value[i]) { LIBGAV1_DLOG(ERROR, "point_v_value[%d] (%d) >= point_v_value[%d] (%d).", i - 1, film_grain_params.point_v_value[i - 1], i, film_grain_params.point_v_value[i]); return false; } OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.point_v_scaling[i] = scratch; } } OBU_READ_LITERAL_OR_FAIL(2); film_grain_params.chroma_scaling = scratch + 8; OBU_READ_LITERAL_OR_FAIL(2); film_grain_params.auto_regression_coeff_lag = scratch; const int num_pos_y = MultiplyBy2(film_grain_params.auto_regression_coeff_lag) * (film_grain_params.auto_regression_coeff_lag + 1); int num_pos_uv = num_pos_y; if (film_grain_params.num_y_points > 0) { ++num_pos_uv; for (int i = 0; i < num_pos_y; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.auto_regression_coeff_y[i] = static_cast(scratch - 128); } } if (film_grain_params.chroma_scaling_from_luma || film_grain_params.num_u_points > 0) { for (int i = 0; i < num_pos_uv; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.auto_regression_coeff_u[i] = static_cast(scratch - 128); } } if (film_grain_params.chroma_scaling_from_luma || film_grain_params.num_v_points > 0) { for (int i = 0; i < num_pos_uv; ++i) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.auto_regression_coeff_v[i] = static_cast(scratch - 128); } } OBU_READ_LITERAL_OR_FAIL(2); film_grain_params.auto_regression_shift = static_cast(scratch + 6); OBU_READ_LITERAL_OR_FAIL(2); film_grain_params.grain_scale_shift = static_cast(scratch); if (film_grain_params.num_u_points > 0) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.u_multiplier = static_cast(scratch - 128); OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.u_luma_multiplier = static_cast(scratch - 128); OBU_READ_LITERAL_OR_FAIL(9); film_grain_params.u_offset = static_cast(scratch - 256); } if (film_grain_params.num_v_points > 0) { OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.v_multiplier = static_cast(scratch - 128); OBU_READ_LITERAL_OR_FAIL(8); film_grain_params.v_luma_multiplier = static_cast(scratch - 128); OBU_READ_LITERAL_OR_FAIL(9); film_grain_params.v_offset = static_cast(scratch - 256); } OBU_READ_BIT_OR_FAIL; film_grain_params.overlap_flag = scratch != 0; OBU_READ_BIT_OR_FAIL; film_grain_params.clip_to_restricted_range = scratch != 0; return true; } bool ObuParser::ParseTileInfoSyntax() { TileInfo* const tile_info = &frame_header_.tile_info; const int sb_columns = sequence_header_.use_128x128_superblock ? ((frame_header_.columns4x4 + 31) >> 5) : ((frame_header_.columns4x4 + 15) >> 4); const int sb_rows = sequence_header_.use_128x128_superblock ? ((frame_header_.rows4x4 + 31) >> 5) : ((frame_header_.rows4x4 + 15) >> 4); tile_info->sb_columns = sb_columns; tile_info->sb_rows = sb_rows; const int sb_shift = sequence_header_.use_128x128_superblock ? 5 : 4; const int sb_size = 2 + sb_shift; const int sb_max_tile_width = kMaxTileWidth >> sb_size; const int sb_max_tile_area = kMaxTileArea >> MultiplyBy2(sb_size); const int minlog2_tile_columns = TileLog2(sb_max_tile_width, sb_columns); const int maxlog2_tile_columns = CeilLog2(std::min(sb_columns, static_cast(kMaxTileColumns))); const int maxlog2_tile_rows = CeilLog2(std::min(sb_rows, static_cast(kMaxTileRows))); const int min_log2_tiles = std::max( minlog2_tile_columns, TileLog2(sb_max_tile_area, sb_rows * sb_columns)); int64_t scratch; OBU_READ_BIT_OR_FAIL; tile_info->uniform_spacing = scratch != 0; if (tile_info->uniform_spacing) { // Read tile columns. tile_info->tile_columns_log2 = minlog2_tile_columns; while (tile_info->tile_columns_log2 < maxlog2_tile_columns) { OBU_READ_BIT_OR_FAIL; if (scratch == 0) break; ++tile_info->tile_columns_log2; } // Compute tile column starts. const int sb_tile_width = (sb_columns + (1 << tile_info->tile_columns_log2) - 1) >> tile_info->tile_columns_log2; if (sb_tile_width <= 0) return false; int i = 0; for (int sb_start = 0; sb_start < sb_columns; sb_start += sb_tile_width) { if (i >= kMaxTileColumns) { LIBGAV1_DLOG(ERROR, "tile_columns would be greater than kMaxTileColumns."); return false; } tile_info->tile_column_start[i++] = sb_start << sb_shift; } tile_info->tile_column_start[i] = frame_header_.columns4x4; tile_info->tile_columns = i; // Read tile rows. const int minlog2_tile_rows = std::max(min_log2_tiles - tile_info->tile_columns_log2, 0); tile_info->tile_rows_log2 = minlog2_tile_rows; while (tile_info->tile_rows_log2 < maxlog2_tile_rows) { OBU_READ_BIT_OR_FAIL; if (scratch == 0) break; ++tile_info->tile_rows_log2; } // Compute tile row starts. const int sb_tile_height = (sb_rows + (1 << tile_info->tile_rows_log2) - 1) >> tile_info->tile_rows_log2; if (sb_tile_height <= 0) return false; i = 0; for (int sb_start = 0; sb_start < sb_rows; sb_start += sb_tile_height) { if (i >= kMaxTileRows) { LIBGAV1_DLOG(ERROR, "tile_rows would be greater than kMaxTileRows."); return false; } tile_info->tile_row_start[i++] = sb_start << sb_shift; } tile_info->tile_row_start[i] = frame_header_.rows4x4; tile_info->tile_rows = i; } else { int widest_tile_sb = 1; int i = 0; for (int sb_start = 0; sb_start < sb_columns; ++i) { if (i >= kMaxTileColumns) { LIBGAV1_DLOG(ERROR, "tile_columns would be greater than kMaxTileColumns."); return false; } tile_info->tile_column_start[i] = sb_start << sb_shift; const int max_width = std::min(sb_columns - sb_start, static_cast(sb_max_tile_width)); if (!bit_reader_->DecodeUniform( max_width, &tile_info->tile_column_width_in_superblocks[i])) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } ++tile_info->tile_column_width_in_superblocks[i]; widest_tile_sb = std::max(tile_info->tile_column_width_in_superblocks[i], widest_tile_sb); sb_start += tile_info->tile_column_width_in_superblocks[i]; } tile_info->tile_column_start[i] = frame_header_.columns4x4; tile_info->tile_columns = i; tile_info->tile_columns_log2 = CeilLog2(tile_info->tile_columns); int max_tile_area_sb = sb_rows * sb_columns; if (min_log2_tiles > 0) max_tile_area_sb >>= min_log2_tiles + 1; const int max_tile_height_sb = std::max(max_tile_area_sb / widest_tile_sb, 1); i = 0; for (int sb_start = 0; sb_start < sb_rows; ++i) { if (i >= kMaxTileRows) { LIBGAV1_DLOG(ERROR, "tile_rows would be greater than kMaxTileRows."); return false; } tile_info->tile_row_start[i] = sb_start << sb_shift; const int max_height = std::min(sb_rows - sb_start, max_tile_height_sb); if (!bit_reader_->DecodeUniform( max_height, &tile_info->tile_row_height_in_superblocks[i])) { LIBGAV1_DLOG(ERROR, "Not enough bits."); return false; } ++tile_info->tile_row_height_in_superblocks[i]; sb_start += tile_info->tile_row_height_in_superblocks[i]; } tile_info->tile_row_start[i] = frame_header_.rows4x4; tile_info->tile_rows = i; tile_info->tile_rows_log2 = CeilLog2(tile_info->tile_rows); } tile_info->tile_count = tile_info->tile_rows * tile_info->tile_columns; if (!tile_buffers_.reserve(tile_info->tile_count)) { LIBGAV1_DLOG(ERROR, "Unable to allocate memory for tile_buffers_."); return false; } tile_info->context_update_id = 0; const int tile_bits = tile_info->tile_columns_log2 + tile_info->tile_rows_log2; if (tile_bits != 0) { OBU_READ_LITERAL_OR_FAIL(tile_bits); tile_info->context_update_id = static_cast(scratch); if (tile_info->context_update_id >= tile_info->tile_count) { LIBGAV1_DLOG(ERROR, "Invalid context_update_tile_id (%d) >= %d.", tile_info->context_update_id, tile_info->tile_count); return false; } OBU_READ_LITERAL_OR_FAIL(2); tile_info->tile_size_bytes = 1 + scratch; } return true; } bool ObuParser::ReadAllowWarpedMotion() { if (IsIntraFrame(frame_header_.frame_type) || frame_header_.error_resilient_mode || !sequence_header_.enable_warped_motion) { return true; } int64_t scratch; OBU_READ_BIT_OR_FAIL; frame_header_.allow_warped_motion = scratch != 0; return true; } bool ObuParser::ParseFrameParameters() { int64_t scratch; if (sequence_header_.reduced_still_picture_header) { frame_header_.show_frame = true; if (!EnsureCurrentFrameIsNotNull()) return false; } else { OBU_READ_BIT_OR_FAIL; frame_header_.show_existing_frame = scratch != 0; if (frame_header_.show_existing_frame) { OBU_READ_LITERAL_OR_FAIL(3); frame_header_.frame_to_show = scratch; if (sequence_header_.decoder_model_info_present_flag && !sequence_header_.timing_info.equal_picture_interval) { OBU_READ_LITERAL_OR_FAIL( sequence_header_.decoder_model_info.frame_presentation_time_length); frame_header_.frame_presentation_time = static_cast(scratch); } if (sequence_header_.frame_id_numbers_present) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.frame_id_length_bits); frame_header_.display_frame_id = static_cast(scratch); // Section 6.8.2: It is a requirement of bitstream conformance that // whenever display_frame_id is read, the value matches // RefFrameId[ frame_to_show_map_idx ] ..., and that // RefValid[ frame_to_show_map_idx ] is equal to 1. // // The current_frame_ == nullptr check below is equivalent to checking // if RefValid[ frame_to_show_map_idx ] is equal to 1. if (frame_header_.display_frame_id != decoder_state_.reference_frame_id[frame_header_.frame_to_show]) { LIBGAV1_DLOG(ERROR, "Reference buffer %d has a frame id number mismatch.", frame_header_.frame_to_show); return false; } } // Section 7.18.2. Note: This is also needed for Section 7.21 if // frame_type is kFrameKey. current_frame_ = decoder_state_.reference_frame[frame_header_.frame_to_show]; if (current_frame_ == nullptr) { LIBGAV1_DLOG(ERROR, "Buffer %d does not contain a decoded frame", frame_header_.frame_to_show); return false; } // Section 6.8.2: It is a requirement of bitstream conformance that // when show_existing_frame is used to show a previous frame, that the // value of showable_frame for the previous frame was equal to 1. if (!current_frame_->showable_frame()) { LIBGAV1_DLOG(ERROR, "Buffer %d does not contain a showable frame", frame_header_.frame_to_show); return false; } if (current_frame_->frame_type() == kFrameKey) { frame_header_.refresh_frame_flags = 0xff; // Section 6.8.2: It is a requirement of bitstream conformance that // when show_existing_frame is used to show a previous frame with // RefFrameType[ frame_to_show_map_idx ] equal to KEY_FRAME, that // the frame is output via the show_existing_frame mechanism at most // once. current_frame_->set_showable_frame(false); // Section 7.21. Note: decoder_state_.current_frame_id must be set // only when frame_type is kFrameKey per the spec. Among all the // variables set in Section 7.21, current_frame_id is the only one // whose value lives across frames. (PrevFrameID is set equal to the // current_frame_id value for the previous frame.) decoder_state_.current_frame_id = decoder_state_.reference_frame_id[frame_header_.frame_to_show]; decoder_state_.order_hint = decoder_state_.reference_order_hint[frame_header_.frame_to_show]; } return true; } if (!EnsureCurrentFrameIsNotNull()) return false; OBU_READ_LITERAL_OR_FAIL(2); frame_header_.frame_type = static_cast(scratch); current_frame_->set_frame_type(frame_header_.frame_type); OBU_READ_BIT_OR_FAIL; frame_header_.show_frame = scratch != 0; if (frame_header_.show_frame && sequence_header_.decoder_model_info_present_flag && !sequence_header_.timing_info.equal_picture_interval) { OBU_READ_LITERAL_OR_FAIL( sequence_header_.decoder_model_info.frame_presentation_time_length); frame_header_.frame_presentation_time = static_cast(scratch); } if (frame_header_.show_frame) { frame_header_.showable_frame = (frame_header_.frame_type != kFrameKey); } else { OBU_READ_BIT_OR_FAIL; frame_header_.showable_frame = scratch != 0; } current_frame_->set_showable_frame(frame_header_.showable_frame); if (frame_header_.frame_type == kFrameSwitch || (frame_header_.frame_type == kFrameKey && frame_header_.show_frame)) { frame_header_.error_resilient_mode = true; } else { OBU_READ_BIT_OR_FAIL; frame_header_.error_resilient_mode = scratch != 0; } } if (frame_header_.frame_type == kFrameKey && frame_header_.show_frame) { decoder_state_.reference_order_hint.fill(0); decoder_state_.reference_frame.fill(nullptr); } OBU_READ_BIT_OR_FAIL; frame_header_.enable_cdf_update = scratch == 0; if (sequence_header_.force_screen_content_tools == kSelectScreenContentTools) { OBU_READ_BIT_OR_FAIL; frame_header_.allow_screen_content_tools = scratch != 0; } else { frame_header_.allow_screen_content_tools = sequence_header_.force_screen_content_tools != 0; } if (frame_header_.allow_screen_content_tools) { if (sequence_header_.force_integer_mv == kSelectIntegerMv) { OBU_READ_BIT_OR_FAIL; frame_header_.force_integer_mv = scratch; } else { frame_header_.force_integer_mv = sequence_header_.force_integer_mv; } } else { frame_header_.force_integer_mv = 0; } if (IsIntraFrame(frame_header_.frame_type)) { frame_header_.force_integer_mv = 1; } if (sequence_header_.frame_id_numbers_present) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.frame_id_length_bits); frame_header_.current_frame_id = static_cast(scratch); const int previous_frame_id = decoder_state_.current_frame_id; decoder_state_.current_frame_id = frame_header_.current_frame_id; if (frame_header_.frame_type != kFrameKey || !frame_header_.show_frame) { if (previous_frame_id >= 0) { // Section 6.8.2: ..., it is a requirement of bitstream conformance // that all of the following conditions are true: // * current_frame_id is not equal to PrevFrameID, // * DiffFrameID is less than 1 << ( idLen - 1 ) int diff_frame_id = decoder_state_.current_frame_id - previous_frame_id; const int id_length_max_value = 1 << sequence_header_.frame_id_length_bits; if (diff_frame_id <= 0) { diff_frame_id += id_length_max_value; } if (diff_frame_id >= DivideBy2(id_length_max_value)) { LIBGAV1_DLOG(ERROR, "current_frame_id (%d) equals or differs too much from " "previous_frame_id (%d).", decoder_state_.current_frame_id, previous_frame_id); return false; } } MarkInvalidReferenceFrames(); } } else { frame_header_.current_frame_id = 0; decoder_state_.current_frame_id = frame_header_.current_frame_id; } if (frame_header_.frame_type == kFrameSwitch) { frame_header_.frame_size_override_flag = true; } else if (!sequence_header_.reduced_still_picture_header) { OBU_READ_BIT_OR_FAIL; frame_header_.frame_size_override_flag = scratch != 0; } if (sequence_header_.order_hint_bits > 0) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.order_hint_bits); frame_header_.order_hint = scratch; } decoder_state_.order_hint = frame_header_.order_hint; if (IsIntraFrame(frame_header_.frame_type) || frame_header_.error_resilient_mode) { frame_header_.primary_reference_frame = kPrimaryReferenceNone; } else { OBU_READ_LITERAL_OR_FAIL(3); frame_header_.primary_reference_frame = scratch; } if (sequence_header_.decoder_model_info_present_flag) { OBU_READ_BIT_OR_FAIL; const bool buffer_removal_time_present = scratch != 0; if (buffer_removal_time_present) { for (int i = 0; i < sequence_header_.operating_points; ++i) { if (!sequence_header_.decoder_model_present_for_operating_point[i]) { continue; } const int index = sequence_header_.operating_point_idc[i]; if (index == 0 || (InTemporalLayer(index, obu_headers_.back().temporal_id) && InSpatialLayer(index, obu_headers_.back().spatial_id))) { OBU_READ_LITERAL_OR_FAIL( sequence_header_.decoder_model_info.buffer_removal_time_length); frame_header_.buffer_removal_time[i] = static_cast(scratch); } } } } if (frame_header_.frame_type == kFrameSwitch || (frame_header_.frame_type == kFrameKey && frame_header_.show_frame)) { frame_header_.refresh_frame_flags = 0xff; } else { OBU_READ_LITERAL_OR_FAIL(8); frame_header_.refresh_frame_flags = scratch; // Section 6.8.2: If frame_type is equal to INTRA_ONLY_FRAME, it is a // requirement of bitstream conformance that refresh_frame_flags is not // equal to 0xff. if (frame_header_.frame_type == kFrameIntraOnly && frame_header_.refresh_frame_flags == 0xff) { LIBGAV1_DLOG(ERROR, "Intra only frames cannot have refresh flags 0xFF."); return false; } } if ((!IsIntraFrame(frame_header_.frame_type) || frame_header_.refresh_frame_flags != 0xff) && !ParseReferenceOrderHint()) { return false; } if (IsIntraFrame(frame_header_.frame_type)) { if (!ParseFrameSizeAndRenderSize()) return false; if (frame_header_.allow_screen_content_tools && frame_header_.width == frame_header_.upscaled_width) { OBU_READ_BIT_OR_FAIL; frame_header_.allow_intrabc = scratch != 0; } } else { if (!sequence_header_.enable_order_hint) { frame_header_.frame_refs_short_signaling = false; } else { OBU_READ_BIT_OR_FAIL; frame_header_.frame_refs_short_signaling = scratch != 0; if (frame_header_.frame_refs_short_signaling) { OBU_READ_LITERAL_OR_FAIL(3); const int8_t last_frame_idx = scratch; OBU_READ_LITERAL_OR_FAIL(3); const int8_t gold_frame_idx = scratch; if (!SetFrameReferences(last_frame_idx, gold_frame_idx)) { return false; } } } for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { if (!frame_header_.frame_refs_short_signaling) { OBU_READ_LITERAL_OR_FAIL(3); frame_header_.reference_frame_index[i] = scratch; } const int reference_frame_index = frame_header_.reference_frame_index[i]; assert(reference_frame_index >= 0); // Section 6.8.2: It is a requirement of bitstream conformance that // RefValid[ ref_frame_idx[ i ] ] is equal to 1 ... // The remainder of the statement is handled by ParseSequenceHeader(). // Note if support for Annex C: Error resilience behavior is added this // check should be omitted per C.5 Decoder consequences of processable // frames. if (decoder_state_.reference_frame[reference_frame_index] == nullptr) { LIBGAV1_DLOG(ERROR, "ref_frame_idx[%d] (%d) is not valid.", i, reference_frame_index); return false; } if (sequence_header_.frame_id_numbers_present) { OBU_READ_LITERAL_OR_FAIL(sequence_header_.delta_frame_id_length_bits); const int delta_frame_id = static_cast(1 + scratch); const int id_length_max_value = 1 << sequence_header_.frame_id_length_bits; frame_header_.expected_frame_id[i] = (frame_header_.current_frame_id + id_length_max_value - delta_frame_id) % id_length_max_value; // Section 6.8.2: It is a requirement of bitstream conformance that // whenever expectedFrameId[ i ] is calculated, the value matches // RefFrameId[ ref_frame_idx[ i ] ] ... if (frame_header_.expected_frame_id[i] != decoder_state_.reference_frame_id[reference_frame_index]) { LIBGAV1_DLOG(ERROR, "Reference buffer %d has a frame id number mismatch.", reference_frame_index); return false; } } } if (frame_header_.frame_size_override_flag && !frame_header_.error_resilient_mode) { // Section 5.9.7. for (int index : frame_header_.reference_frame_index) { OBU_READ_BIT_OR_FAIL; frame_header_.found_reference = scratch != 0; if (frame_header_.found_reference) { const RefCountedBuffer* reference_frame = decoder_state_.reference_frame[index].get(); // frame_header_.upscaled_width will be set in the // ParseSuperResParametersAndComputeImageSize() call below. frame_header_.width = reference_frame->upscaled_width(); frame_header_.height = reference_frame->frame_height(); frame_header_.render_width = reference_frame->render_width(); frame_header_.render_height = reference_frame->render_height(); if (!ParseSuperResParametersAndComputeImageSize()) return false; break; } } if (!frame_header_.found_reference && !ParseFrameSizeAndRenderSize()) { return false; } } else { if (!ParseFrameSizeAndRenderSize()) return false; } if (!ValidateInterFrameSize()) return false; if (frame_header_.force_integer_mv != 0) { frame_header_.allow_high_precision_mv = false; } else { OBU_READ_BIT_OR_FAIL; frame_header_.allow_high_precision_mv = scratch != 0; } OBU_READ_BIT_OR_FAIL; const bool is_filter_switchable = scratch != 0; if (is_filter_switchable) { frame_header_.interpolation_filter = kInterpolationFilterSwitchable; } else { OBU_READ_LITERAL_OR_FAIL(2); frame_header_.interpolation_filter = static_cast(scratch); } OBU_READ_BIT_OR_FAIL; frame_header_.is_motion_mode_switchable = scratch != 0; if (frame_header_.error_resilient_mode || !sequence_header_.enable_ref_frame_mvs) { frame_header_.use_ref_frame_mvs = false; } else { OBU_READ_BIT_OR_FAIL; frame_header_.use_ref_frame_mvs = scratch != 0; } } // At this point, we have parsed the frame and render sizes and computed // the image size, whether it's an intra or inter frame. So we can save // the sizes in the current frame now. if (!current_frame_->SetFrameDimensions(frame_header_)) { LIBGAV1_DLOG(ERROR, "Setting current frame dimensions failed."); return false; } if (!IsIntraFrame(frame_header_.frame_type)) { // Initialize the kReferenceFrameIntra type reference frame information to // simplify the frame type validation in motion field projection. // Set the kReferenceFrameIntra type |order_hint_| to // |frame_header_.order_hint|. This guarantees that in SIMD implementations, // the other reference frame information of the kReferenceFrameIntra type // could be correctly initialized using the following loop with // |frame_header_.order_hint| being the |hint|. ReferenceInfo* const reference_info = current_frame_->reference_info(); reference_info->order_hint[kReferenceFrameIntra] = frame_header_.order_hint; reference_info->relative_distance_from[kReferenceFrameIntra] = 0; reference_info->relative_distance_to[kReferenceFrameIntra] = 0; reference_info->skip_references[kReferenceFrameIntra] = true; reference_info->projection_divisions[kReferenceFrameIntra] = 0; for (int i = kReferenceFrameLast; i <= kNumInterReferenceFrameTypes; ++i) { const auto reference_frame = static_cast(i); const uint8_t hint = decoder_state_.reference_order_hint [frame_header_.reference_frame_index[i - kReferenceFrameLast]]; reference_info->order_hint[reference_frame] = hint; const int relative_distance_from = GetRelativeDistance(hint, frame_header_.order_hint, sequence_header_.order_hint_shift_bits); const int relative_distance_to = GetRelativeDistance(frame_header_.order_hint, hint, sequence_header_.order_hint_shift_bits); reference_info->relative_distance_from[reference_frame] = relative_distance_from; reference_info->relative_distance_to[reference_frame] = relative_distance_to; reference_info->skip_references[reference_frame] = relative_distance_to > kMaxFrameDistance || relative_distance_to <= 0; reference_info->projection_divisions[reference_frame] = reference_info->skip_references[reference_frame] ? 0 : kProjectionMvDivisionLookup[relative_distance_to]; decoder_state_.reference_frame_sign_bias[reference_frame] = relative_distance_from > 0; } } if (frame_header_.enable_cdf_update && !sequence_header_.reduced_still_picture_header) { OBU_READ_BIT_OR_FAIL; frame_header_.enable_frame_end_update_cdf = scratch == 0; } else { frame_header_.enable_frame_end_update_cdf = false; } return true; } bool ObuParser::ParseFrameHeader() { // Section 6.8.1: It is a requirement of bitstream conformance that a // sequence header OBU has been received before a frame header OBU. if (!has_sequence_header_) return false; if (!ParseFrameParameters()) return false; if (frame_header_.show_existing_frame) return true; assert(!obu_headers_.empty()); current_frame_->set_spatial_id(obu_headers_.back().spatial_id); current_frame_->set_temporal_id(obu_headers_.back().temporal_id); bool status = ParseTileInfoSyntax() && ParseQuantizerParameters() && ParseSegmentationParameters(); if (!status) return false; current_frame_->SetSegmentationParameters(frame_header_.segmentation); status = ParseQuantizerIndexDeltaParameters() && ParseLoopFilterDeltaParameters(); if (!status) return false; ComputeSegmentLosslessAndQIndex(); // Section 6.8.2: It is a requirement of bitstream conformance that // delta_q_present is equal to 0 when CodedLossless is equal to 1. if (frame_header_.coded_lossless && frame_header_.delta_q.present) { return false; } status = ParseLoopFilterParameters(); if (!status) return false; current_frame_->SetLoopFilterDeltas(frame_header_.loop_filter); status = ParseCdefParameters() && ParseLoopRestorationParameters() && ParseTxModeSyntax() && ParseFrameReferenceModeSyntax() && ParseSkipModeParameters() && ReadAllowWarpedMotion(); if (!status) return false; int64_t scratch; OBU_READ_BIT_OR_FAIL; frame_header_.reduced_tx_set = scratch != 0; status = ParseGlobalMotionParameters(); if (!status) return false; current_frame_->SetGlobalMotions(frame_header_.global_motion); status = ParseFilmGrainParameters(); if (!status) return false; if (sequence_header_.film_grain_params_present) { current_frame_->set_film_grain_params(frame_header_.film_grain_params); } return true; } bool ObuParser::ParsePadding(const uint8_t* data, size_t size) { // The spec allows a padding OBU to be header-only (i.e., |size| = 0). So // check trailing bits only if |size| > 0. if (size == 0) return true; // The payload of a padding OBU is byte aligned. Therefore the first // trailing byte should be 0x80. See https://crbug.com/aomedia/2393. const int i = GetLastNonzeroByteIndex(data, size); if (i < 0) { LIBGAV1_DLOG(ERROR, "Trailing bit is missing."); return false; } if (data[i] != 0x80) { LIBGAV1_DLOG( ERROR, "The last nonzero byte of the payload data is 0x%x, should be 0x80.", data[i]); return false; } // Skip all bits before the trailing bit. bit_reader_->SkipBytes(i); return true; } bool ObuParser::ParseMetadataScalability() { int64_t scratch; // scalability_mode_idc OBU_READ_LITERAL_OR_FAIL(8); const auto scalability_mode_idc = static_cast(scratch); if (scalability_mode_idc == kScalabilitySS) { // Parse scalability_structure(). // spatial_layers_cnt_minus_1 OBU_READ_LITERAL_OR_FAIL(2); const auto spatial_layers_count = static_cast(scratch) + 1; // spatial_layer_dimensions_present_flag OBU_READ_BIT_OR_FAIL; const auto spatial_layer_dimensions_present_flag = scratch != 0; // spatial_layer_description_present_flag OBU_READ_BIT_OR_FAIL; const auto spatial_layer_description_present_flag = scratch != 0; // temporal_group_description_present_flag OBU_READ_BIT_OR_FAIL; const auto temporal_group_description_present_flag = scratch != 0; // scalability_structure_reserved_3bits OBU_READ_LITERAL_OR_FAIL(3); if (scratch != 0) { LIBGAV1_DLOG(WARNING, "scalability_structure_reserved_3bits is not zero."); } if (spatial_layer_dimensions_present_flag) { for (int i = 0; i < spatial_layers_count; ++i) { // spatial_layer_max_width[i] OBU_READ_LITERAL_OR_FAIL(16); // spatial_layer_max_height[i] OBU_READ_LITERAL_OR_FAIL(16); } } if (spatial_layer_description_present_flag) { for (int i = 0; i < spatial_layers_count; ++i) { // spatial_layer_ref_id[i] OBU_READ_LITERAL_OR_FAIL(8); } } if (temporal_group_description_present_flag) { // temporal_group_size OBU_READ_LITERAL_OR_FAIL(8); const auto temporal_group_size = static_cast(scratch); for (int i = 0; i < temporal_group_size; ++i) { // temporal_group_temporal_id[i] OBU_READ_LITERAL_OR_FAIL(3); // temporal_group_temporal_switching_up_point_flag[i] OBU_READ_BIT_OR_FAIL; // temporal_group_spatial_switching_up_point_flag[i] OBU_READ_BIT_OR_FAIL; // temporal_group_ref_cnt[i] OBU_READ_LITERAL_OR_FAIL(3); const auto temporal_group_ref_count = static_cast(scratch); for (int j = 0; j < temporal_group_ref_count; ++j) { // temporal_group_ref_pic_diff[i][j] OBU_READ_LITERAL_OR_FAIL(8); } } } } return true; } bool ObuParser::ParseMetadataTimecode() { int64_t scratch; // counting_type: should be the same for all pictures in the coded video // sequence. 7..31 are reserved. OBU_READ_LITERAL_OR_FAIL(5); // full_timestamp_flag OBU_READ_BIT_OR_FAIL; const bool full_timestamp_flag = scratch != 0; // discontinuity_flag OBU_READ_BIT_OR_FAIL; // cnt_dropped_flag OBU_READ_BIT_OR_FAIL; // n_frames OBU_READ_LITERAL_OR_FAIL(9); if (full_timestamp_flag) { // seconds_value OBU_READ_LITERAL_OR_FAIL(6); const auto seconds_value = static_cast(scratch); if (seconds_value > 59) { LIBGAV1_DLOG(ERROR, "Invalid seconds_value %d.", seconds_value); return false; } // minutes_value OBU_READ_LITERAL_OR_FAIL(6); const auto minutes_value = static_cast(scratch); if (minutes_value > 59) { LIBGAV1_DLOG(ERROR, "Invalid minutes_value %d.", minutes_value); return false; } // hours_value OBU_READ_LITERAL_OR_FAIL(5); const auto hours_value = static_cast(scratch); if (hours_value > 23) { LIBGAV1_DLOG(ERROR, "Invalid hours_value %d.", hours_value); return false; } } else { // seconds_flag OBU_READ_BIT_OR_FAIL; const bool seconds_flag = scratch != 0; if (seconds_flag) { // seconds_value OBU_READ_LITERAL_OR_FAIL(6); const auto seconds_value = static_cast(scratch); if (seconds_value > 59) { LIBGAV1_DLOG(ERROR, "Invalid seconds_value %d.", seconds_value); return false; } // minutes_flag OBU_READ_BIT_OR_FAIL; const bool minutes_flag = scratch != 0; if (minutes_flag) { // minutes_value OBU_READ_LITERAL_OR_FAIL(6); const auto minutes_value = static_cast(scratch); if (minutes_value > 59) { LIBGAV1_DLOG(ERROR, "Invalid minutes_value %d.", minutes_value); return false; } // hours_flag OBU_READ_BIT_OR_FAIL; const bool hours_flag = scratch != 0; if (hours_flag) { // hours_value OBU_READ_LITERAL_OR_FAIL(5); const auto hours_value = static_cast(scratch); if (hours_value > 23) { LIBGAV1_DLOG(ERROR, "Invalid hours_value %d.", hours_value); return false; } } } } } // time_offset_length: should be the same for all pictures in the coded // video sequence. OBU_READ_LITERAL_OR_FAIL(5); const auto time_offset_length = static_cast(scratch); if (time_offset_length > 0) { // time_offset_value OBU_READ_LITERAL_OR_FAIL(time_offset_length); } // Compute clockTimestamp. Section 6.7.7: // When timing_info_present_flag is equal to 1 and discontinuity_flag is // equal to 0, the value of clockTimestamp shall be greater than or equal // to the value of clockTimestamp for the previous set of clock timestamp // syntax elements in output order. return true; } bool ObuParser::ParseMetadata(const uint8_t* data, size_t size) { const size_t start_offset = bit_reader_->byte_offset(); size_t metadata_type; if (!bit_reader_->ReadUnsignedLeb128(&metadata_type)) { LIBGAV1_DLOG(ERROR, "Could not read metadata_type."); return false; } const size_t metadata_type_size = bit_reader_->byte_offset() - start_offset; if (size < metadata_type_size) { LIBGAV1_DLOG( ERROR, "metadata_type is longer than metadata OBU payload %zu vs %zu.", metadata_type_size, size); return false; } data += metadata_type_size; size -= metadata_type_size; int64_t scratch; switch (metadata_type) { case kMetadataTypeHdrContentLightLevel: { ObuMetadataHdrCll hdr_cll; OBU_READ_LITERAL_OR_FAIL(16); hdr_cll.max_cll = scratch; OBU_READ_LITERAL_OR_FAIL(16); hdr_cll.max_fall = scratch; if (!EnsureCurrentFrameIsNotNull()) return false; current_frame_->set_hdr_cll(hdr_cll); break; } case kMetadataTypeHdrMasteringDisplayColorVolume: { ObuMetadataHdrMdcv hdr_mdcv; for (int i = 0; i < 3; ++i) { OBU_READ_LITERAL_OR_FAIL(16); hdr_mdcv.primary_chromaticity_x[i] = scratch; OBU_READ_LITERAL_OR_FAIL(16); hdr_mdcv.primary_chromaticity_y[i] = scratch; } OBU_READ_LITERAL_OR_FAIL(16); hdr_mdcv.white_point_chromaticity_x = scratch; OBU_READ_LITERAL_OR_FAIL(16); hdr_mdcv.white_point_chromaticity_y = scratch; OBU_READ_LITERAL_OR_FAIL(32); hdr_mdcv.luminance_max = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL(32); hdr_mdcv.luminance_min = static_cast(scratch); if (!EnsureCurrentFrameIsNotNull()) return false; current_frame_->set_hdr_mdcv(hdr_mdcv); break; } case kMetadataTypeScalability: if (!ParseMetadataScalability()) return false; break; case kMetadataTypeItutT35: { ObuMetadataItutT35 itut_t35; OBU_READ_LITERAL_OR_FAIL(8); itut_t35.country_code = static_cast(scratch); ++data; --size; if (itut_t35.country_code == 0xFF) { OBU_READ_LITERAL_OR_FAIL(8); itut_t35.country_code_extension_byte = static_cast(scratch); ++data; --size; } // Read itut_t35.payload_bytes. Section 6.7.2 of the spec says: // itut_t35.payload_bytes shall be bytes containing data registered as // specified in Recommendation ITU-T T.35. // Therefore itut_t35.payload_bytes is byte aligned and the first trailing // byte should be 0x80. Since the exact syntax of itut_t35.payload_bytes // is not defined in the AV1 spec, identify the end of // itut_t35.payload_bytes by searching for the trailing bit. const int i = GetLastNonzeroByteIndex(data, size); if (i < 0) { LIBGAV1_DLOG(ERROR, "Trailing bit is missing."); return false; } if (data[i] != 0x80) { LIBGAV1_DLOG( ERROR, "itut_t35.payload_bytes is not byte aligned. The last nonzero byte " "of the payload data is 0x%x, should be 0x80.", data[i]); return false; } itut_t35.payload_size = i; if (!EnsureCurrentFrameIsNotNull() || !current_frame_->set_itut_t35(itut_t35, data)) { return false; } // Skip all bits before the trailing bit. bit_reader_->SkipBytes(i); break; } case kMetadataTypeTimecode: if (!ParseMetadataTimecode()) return false; break; default: { // metadata_type is equal to a value reserved for future use or a user // private value. // // The Note in Section 5.8.1 says "Decoders should ignore the entire OBU // if they do not understand the metadata_type." Find the trailing bit // and skip all bits before the trailing bit. const int i = GetLastNonzeroByteIndex(data, size); if (i >= 0) { // The last 1 bit in the last nonzero byte is the trailing bit. Skip // all bits before the trailing bit. const int n = CountTrailingZeros(data[i]); bit_reader_->SkipBits(i * 8 + 7 - n); } break; } } return true; } bool ObuParser::AddTileBuffers(int start, int end, size_t total_size, size_t tg_header_size, size_t bytes_consumed_so_far) { // Validate that the tile group start and end are within the allowed range. if (start != next_tile_group_start_ || start > end || end >= frame_header_.tile_info.tile_count) { LIBGAV1_DLOG(ERROR, "Invalid tile group start %d or end %d: expected tile group " "start %d, tile_count %d.", start, end, next_tile_group_start_, frame_header_.tile_info.tile_count); return false; } next_tile_group_start_ = end + 1; if (total_size < tg_header_size) { LIBGAV1_DLOG(ERROR, "total_size (%zu) is less than tg_header_size (%zu).)", total_size, tg_header_size); return false; } size_t bytes_left = total_size - tg_header_size; const uint8_t* data = data_ + bytes_consumed_so_far + tg_header_size; for (int tile_number = start; tile_number <= end; ++tile_number) { size_t tile_size = 0; if (tile_number != end) { RawBitReader bit_reader(data, bytes_left); if (!bit_reader.ReadLittleEndian(frame_header_.tile_info.tile_size_bytes, &tile_size)) { LIBGAV1_DLOG(ERROR, "Could not read tile size for tile #%d", tile_number); return false; } ++tile_size; data += frame_header_.tile_info.tile_size_bytes; bytes_left -= frame_header_.tile_info.tile_size_bytes; if (tile_size > bytes_left) { LIBGAV1_DLOG(ERROR, "Invalid tile size %zu for tile #%d", tile_size, tile_number); return false; } } else { tile_size = bytes_left; if (tile_size == 0) { LIBGAV1_DLOG(ERROR, "Invalid tile size %zu for tile #%d", tile_size, tile_number); return false; } } // The memory for this has been allocated in ParseTileInfoSyntax(). So it is // safe to use push_back_unchecked here. tile_buffers_.push_back_unchecked({data, tile_size}); data += tile_size; bytes_left -= tile_size; } bit_reader_->SkipBytes(total_size - tg_header_size); return true; } bool ObuParser::ParseTileGroup(size_t size, size_t bytes_consumed_so_far) { const TileInfo* const tile_info = &frame_header_.tile_info; const size_t start_offset = bit_reader_->byte_offset(); const int tile_bits = tile_info->tile_columns_log2 + tile_info->tile_rows_log2; if (tile_bits == 0) { return AddTileBuffers(0, 0, size, 0, bytes_consumed_so_far); } int64_t scratch; OBU_READ_BIT_OR_FAIL; const bool tile_start_and_end_present_flag = scratch != 0; if (!tile_start_and_end_present_flag) { if (!bit_reader_->AlignToNextByte()) { LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits."); return false; } return AddTileBuffers(0, tile_info->tile_count - 1, size, 1, bytes_consumed_so_far); } if (obu_headers_.back().type == kObuFrame) { // 6.10.1: If obu_type is equal to OBU_FRAME, it is a requirement of // bitstream conformance that the value of tile_start_and_end_present_flag // is equal to 0. LIBGAV1_DLOG(ERROR, "tile_start_and_end_present_flag must be 0 in Frame OBU"); return false; } OBU_READ_LITERAL_OR_FAIL(tile_bits); const int start = static_cast(scratch); OBU_READ_LITERAL_OR_FAIL(tile_bits); const int end = static_cast(scratch); if (!bit_reader_->AlignToNextByte()) { LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits."); return false; } const size_t tg_header_size = bit_reader_->byte_offset() - start_offset; return AddTileBuffers(start, end, size, tg_header_size, bytes_consumed_so_far); } bool ObuParser::ParseHeader() { ObuHeader obu_header; int64_t scratch = bit_reader_->ReadBit(); if (scratch != 0) { LIBGAV1_DLOG(ERROR, "forbidden_bit is not zero."); return false; } OBU_READ_LITERAL_OR_FAIL(4); obu_header.type = static_cast(scratch); OBU_READ_BIT_OR_FAIL; const bool extension_flag = scratch != 0; OBU_READ_BIT_OR_FAIL; obu_header.has_size_field = scratch != 0; OBU_READ_BIT_OR_FAIL; // reserved. if (scratch != 0) { LIBGAV1_DLOG(WARNING, "obu_reserved_1bit is not zero."); } obu_header.has_extension = extension_flag; if (extension_flag) { if (extension_disallowed_) { LIBGAV1_DLOG(ERROR, "OperatingPointIdc is 0, but obu_extension_flag is 1."); return false; } OBU_READ_LITERAL_OR_FAIL(3); obu_header.temporal_id = scratch; OBU_READ_LITERAL_OR_FAIL(2); obu_header.spatial_id = scratch; OBU_READ_LITERAL_OR_FAIL(3); // reserved. if (scratch != 0) { LIBGAV1_DLOG(WARNING, "extension_header_reserved_3bits is not zero."); } } else { obu_header.temporal_id = 0; obu_header.spatial_id = 0; } return obu_headers_.push_back(obu_header); } #undef OBU_READ_UVLC_OR_FAIL #undef OBU_READ_LITERAL_OR_FAIL #undef OBU_READ_BIT_OR_FAIL #undef OBU_PARSER_FAIL #undef OBU_LOG_AND_RETURN_FALSE bool ObuParser::InitBitReader(const uint8_t* const data, size_t size) { bit_reader_.reset(new (std::nothrow) RawBitReader(data, size)); return bit_reader_ != nullptr; } bool ObuParser::EnsureCurrentFrameIsNotNull() { if (current_frame_ != nullptr) return true; current_frame_ = buffer_pool_->GetFreeBuffer(); if (current_frame_ == nullptr) { LIBGAV1_DLOG(ERROR, "Could not get current_frame from the buffer pool."); return false; } return true; } bool ObuParser::HasData() const { return size_ > 0; } StatusCode ObuParser::ParseOneFrame(RefCountedBufferPtr* const current_frame) { if (data_ == nullptr || size_ == 0) return kStatusInvalidArgument; assert(current_frame_ == nullptr); // This is used to release any references held in case of parsing failure. RefCountedBufferPtrCleanup current_frame_cleanup(¤t_frame_); const uint8_t* data = data_; size_t size = size_; // Clear everything except the sequence header. obu_headers_.clear(); frame_header_ = {}; tile_buffers_.clear(); next_tile_group_start_ = 0; sequence_header_changed_ = false; bool parsed_one_full_frame = false; bool seen_frame_header = false; const uint8_t* frame_header = nullptr; size_t frame_header_size_in_bits = 0; while (size > 0 && !parsed_one_full_frame) { if (!InitBitReader(data, size)) { LIBGAV1_DLOG(ERROR, "Failed to initialize bit reader."); return kStatusOutOfMemory; } if (!ParseHeader()) { LIBGAV1_DLOG(ERROR, "Failed to parse OBU Header."); return kStatusBitstreamError; } const ObuHeader& obu_header = obu_headers_.back(); if (!obu_header.has_size_field) { LIBGAV1_DLOG( ERROR, "has_size_field is zero. libgav1 does not support such streams."); return kStatusUnimplemented; } const size_t obu_header_size = bit_reader_->byte_offset(); size_t obu_size; if (!bit_reader_->ReadUnsignedLeb128(&obu_size)) { LIBGAV1_DLOG(ERROR, "Could not read OBU size."); return kStatusBitstreamError; } const size_t obu_length_size = bit_reader_->byte_offset() - obu_header_size; if (size - bit_reader_->byte_offset() < obu_size) { LIBGAV1_DLOG(ERROR, "Not enough bits left to parse OBU %zu vs %zu.", size - bit_reader_->bit_offset(), obu_size); return kStatusBitstreamError; } const ObuType obu_type = obu_header.type; if (obu_type != kObuSequenceHeader && obu_type != kObuTemporalDelimiter && has_sequence_header_ && sequence_header_.operating_point_idc[operating_point_] != 0 && obu_header.has_extension && (!InTemporalLayer( sequence_header_.operating_point_idc[operating_point_], obu_header.temporal_id) || !InSpatialLayer(sequence_header_.operating_point_idc[operating_point_], obu_header.spatial_id))) { obu_headers_.pop_back(); bit_reader_->SkipBytes(obu_size); data += bit_reader_->byte_offset(); size -= bit_reader_->byte_offset(); continue; } const size_t obu_start_position = bit_reader_->bit_offset(); // The bit_reader_ is byte aligned after reading obu_header and obu_size. // Therefore the byte offset can be computed as obu_start_position >> 3 // below. assert((obu_start_position & 7) == 0); bool obu_skipped = false; switch (obu_type) { case kObuTemporalDelimiter: break; case kObuSequenceHeader: if (!ParseSequenceHeader(seen_frame_header)) { LIBGAV1_DLOG(ERROR, "Failed to parse SequenceHeader OBU."); return kStatusBitstreamError; } if (sequence_header_.color_config.bitdepth > LIBGAV1_MAX_BITDEPTH) { LIBGAV1_DLOG( ERROR, "Bitdepth %d is not supported. The maximum bitdepth is %d.", sequence_header_.color_config.bitdepth, LIBGAV1_MAX_BITDEPTH); return kStatusUnimplemented; } break; case kObuFrameHeader: if (seen_frame_header) { LIBGAV1_DLOG(ERROR, "Frame header found but frame header was already seen."); return kStatusBitstreamError; } if (!ParseFrameHeader()) { LIBGAV1_DLOG(ERROR, "Failed to parse FrameHeader OBU."); return kStatusBitstreamError; } frame_header = &data[obu_start_position >> 3]; frame_header_size_in_bits = bit_reader_->bit_offset() - obu_start_position; seen_frame_header = true; parsed_one_full_frame = frame_header_.show_existing_frame; break; case kObuRedundantFrameHeader: { if (!seen_frame_header) { LIBGAV1_DLOG(ERROR, "Redundant frame header found but frame header was not " "yet seen."); return kStatusBitstreamError; } const size_t fh_size = (frame_header_size_in_bits + 7) >> 3; if (obu_size < fh_size || memcmp(frame_header, &data[obu_start_position >> 3], fh_size) != 0) { LIBGAV1_DLOG(ERROR, "Redundant frame header differs from frame header."); return kStatusBitstreamError; } bit_reader_->SkipBits(frame_header_size_in_bits); break; } case kObuFrame: { const size_t fh_start_offset = bit_reader_->byte_offset(); if (seen_frame_header) { LIBGAV1_DLOG(ERROR, "Frame header found but frame header was already seen."); return kStatusBitstreamError; } if (!ParseFrameHeader()) { LIBGAV1_DLOG(ERROR, "Failed to parse FrameHeader in Frame OBU."); return kStatusBitstreamError; } // Section 6.8.2: If obu_type is equal to OBU_FRAME, it is a // requirement of bitstream conformance that show_existing_frame is // equal to 0. if (frame_header_.show_existing_frame) { LIBGAV1_DLOG(ERROR, "Frame OBU cannot set show_existing_frame to 1."); return kStatusBitstreamError; } if (!bit_reader_->AlignToNextByte()) { LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits."); return kStatusBitstreamError; } const size_t fh_size = bit_reader_->byte_offset() - fh_start_offset; if (fh_size >= obu_size) { LIBGAV1_DLOG(ERROR, "Frame header size (%zu) >= obu_size (%zu).", fh_size, obu_size); return kStatusBitstreamError; } if (!ParseTileGroup(obu_size - fh_size, size_ - size + bit_reader_->byte_offset())) { LIBGAV1_DLOG(ERROR, "Failed to parse TileGroup in Frame OBU."); return kStatusBitstreamError; } parsed_one_full_frame = true; break; } case kObuTileGroup: if (!ParseTileGroup(obu_size, size_ - size + bit_reader_->byte_offset())) { LIBGAV1_DLOG(ERROR, "Failed to parse TileGroup OBU."); return kStatusBitstreamError; } parsed_one_full_frame = (next_tile_group_start_ == frame_header_.tile_info.tile_count); break; case kObuTileList: LIBGAV1_DLOG(ERROR, "Decoding of tile list OBUs is not supported."); return kStatusUnimplemented; case kObuPadding: if (!ParsePadding(&data[obu_start_position >> 3], obu_size)) { LIBGAV1_DLOG(ERROR, "Failed to parse Padding OBU."); return kStatusBitstreamError; } break; case kObuMetadata: if (!ParseMetadata(&data[obu_start_position >> 3], obu_size)) { LIBGAV1_DLOG(ERROR, "Failed to parse Metadata OBU."); return kStatusBitstreamError; } break; default: // Skip reserved OBUs. Section 6.2.2: Reserved units are for future use // and shall be ignored by AV1 decoder. bit_reader_->SkipBytes(obu_size); obu_skipped = true; break; } if (obu_size > 0 && !obu_skipped && obu_type != kObuFrame && obu_type != kObuTileGroup) { const size_t parsed_obu_size_in_bits = bit_reader_->bit_offset() - obu_start_position; if (obu_size * 8 < parsed_obu_size_in_bits) { LIBGAV1_DLOG( ERROR, "Parsed OBU size (%zu bits) is greater than expected OBU size " "(%zu bytes) obu_type: %d.", parsed_obu_size_in_bits, obu_size, obu_type); return kStatusBitstreamError; } if (!bit_reader_->VerifyAndSkipTrailingBits(obu_size * 8 - parsed_obu_size_in_bits)) { LIBGAV1_DLOG(ERROR, "Error when verifying trailing bits for obu type: %d", obu_type); return kStatusBitstreamError; } } const size_t bytes_consumed = bit_reader_->byte_offset(); const size_t consumed_obu_size = bytes_consumed - obu_length_size - obu_header_size; if (consumed_obu_size != obu_size) { LIBGAV1_DLOG(ERROR, "OBU size (%zu) and consumed size (%zu) does not match for " "obu_type: %d.", obu_size, consumed_obu_size, obu_type); return kStatusBitstreamError; } data += bytes_consumed; size -= bytes_consumed; } if (!parsed_one_full_frame && seen_frame_header) { LIBGAV1_DLOG(ERROR, "The last tile group in the frame was not received."); return kStatusBitstreamError; } data_ = data; size_ = size; *current_frame = std::move(current_frame_); return kStatusOk; } // AV1CodecConfigurationBox specification: // https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox. // static std::unique_ptr ObuParser::GetAV1CodecConfigurationBox( const uint8_t* data, size_t size, size_t* const av1c_size) { if (data == nullptr || av1c_size == nullptr) return nullptr; ObuSequenceHeader sequence_header; size_t sequence_header_offset; size_t sequence_header_size; const StatusCode status = ParseBasicStreamInfo(data, size, &sequence_header, &sequence_header_offset, &sequence_header_size); if (status != kStatusOk) { *av1c_size = 0; return nullptr; } *av1c_size = 4 + sequence_header_size; std::unique_ptr av1c_ptr(new (std::nothrow) uint8_t[*av1c_size]); if (av1c_ptr == nullptr) { *av1c_size = 0; return nullptr; } uint8_t* av1c = av1c_ptr.get(); // unsigned int (1) marker = 1; // unsigned int (7) version = 1; av1c[0] = 0x81; // unsigned int (3) seq_profile; // unsigned int (5) seq_level_idx_0; const uint8_t seq_level_idx_0 = ((sequence_header.level[0].major - 2) << 2) | sequence_header.level[0].minor; av1c[1] = (sequence_header.profile << 5) | seq_level_idx_0; // unsigned int (1) seq_tier_0; // unsigned int (1) high_bitdepth; // unsigned int (1) twelve_bit; // unsigned int (1) monochrome; // unsigned int (1) chroma_subsampling_x; // unsigned int (1) chroma_subsampling_y; // unsigned int (2) chroma_sample_position; const auto high_bitdepth = static_cast(sequence_header.color_config.bitdepth > 8); const auto twelve_bit = static_cast(sequence_header.color_config.bitdepth == 12); av1c[2] = (sequence_header.tier[0] << 7) | (high_bitdepth << 6) | (twelve_bit << 5) | (static_cast(sequence_header.color_config.is_monochrome) << 4) | (sequence_header.color_config.subsampling_x << 3) | (sequence_header.color_config.subsampling_y << 2) | sequence_header.color_config.chroma_sample_position; // unsigned int (3) reserved = 0; // unsigned int (1) initial_presentation_delay_present; // if (initial_presentation_delay_present) { // unsigned int (4) initial_presentation_delay_minus_one; // } else { // unsigned int (4) reserved = 0; // } av1c[3] = 0; // unsigned int (8) configOBUs[]; memcpy(av1c + 4, data + sequence_header_offset, sequence_header_size); return av1c_ptr; } // static StatusCode ObuParser::ParseBasicStreamInfo(const uint8_t* data, size_t size, ObuSequenceHeader* sequence_header, size_t* sequence_header_offset, size_t* sequence_header_size) { DecoderState state; ObuParser parser(nullptr, 0, 0, nullptr, &state); if (!parser.InitBitReader(data, size)) { LIBGAV1_DLOG(ERROR, "Failed to initialize bit reader."); return kStatusOutOfMemory; } while (!parser.bit_reader_->Finished()) { const size_t obu_start_offset = parser.bit_reader_->byte_offset(); if (!parser.ParseHeader()) { LIBGAV1_DLOG(ERROR, "Failed to parse OBU Header."); return kStatusBitstreamError; } const ObuHeader& obu_header = parser.obu_headers_.back(); if (!obu_header.has_size_field) { LIBGAV1_DLOG( ERROR, "has_size_field is zero. libgav1 does not support such streams."); return kStatusUnimplemented; } size_t obu_size; if (!parser.bit_reader_->ReadUnsignedLeb128(&obu_size)) { LIBGAV1_DLOG(ERROR, "Could not read OBU size."); return kStatusBitstreamError; } if (size - parser.bit_reader_->byte_offset() < obu_size) { LIBGAV1_DLOG(ERROR, "Not enough bits left to parse OBU %zu vs %zu.", size - parser.bit_reader_->bit_offset(), obu_size); return kStatusBitstreamError; } if (obu_header.type != kObuSequenceHeader) { parser.obu_headers_.pop_back(); parser.bit_reader_->SkipBytes(obu_size); continue; } const size_t obu_start_position = parser.bit_reader_->bit_offset(); if (!parser.ParseSequenceHeader(false)) { LIBGAV1_DLOG(ERROR, "Failed to parse SequenceHeader OBU."); return kStatusBitstreamError; } const size_t parsed_obu_size_in_bits = parser.bit_reader_->bit_offset() - obu_start_position; const uint64_t obu_size_in_bits = static_cast(obu_size) * 8; if (obu_size_in_bits < parsed_obu_size_in_bits) { LIBGAV1_DLOG( ERROR, "Parsed OBU size (%zu bits) is greater than expected OBU size " "(%zu bytes)..", parsed_obu_size_in_bits, obu_size); return kStatusBitstreamError; } if (!parser.bit_reader_->VerifyAndSkipTrailingBits( static_cast(obu_size_in_bits - parsed_obu_size_in_bits))) { LIBGAV1_DLOG( ERROR, "Error when verifying trailing bits for the sequence header."); return kStatusBitstreamError; } *sequence_header = parser.sequence_header_; *sequence_header_offset = obu_start_offset; *sequence_header_size = parser.bit_reader_->byte_offset() - obu_start_offset; return kStatusOk; } // Sequence header was never found. return kStatusBitstreamError; } } // namespace libgav1