| #include "src/obu_parser.h" |
| |
| #include <algorithm> |
| #include <array> |
| #include <cassert> |
| #include <climits> |
| #include <cstdint> |
| #include <cstring> |
| |
| #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 { |
| |
| // This is set to 0 since we only support one layer. This should be part of |
| // DecoderSettings if we support more than one layer. |
| constexpr int kOperatingPoint = 0; |
| |
| // 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; |
| } |
| |
| } // namespace |
| |
| // 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 auto high_bitdepth = static_cast<bool>(scratch); |
| if (sequence_header->profile >= kProfile2 && high_bitdepth) { |
| OBU_READ_BIT_OR_FAIL; |
| const auto is_twelve_bit = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| const auto color_description_present_flag = static_cast<bool>(scratch); |
| if (color_description_present_flag) { |
| OBU_READ_LITERAL_OR_FAIL(8); |
| color_config->color_primaries = static_cast<ColorPrimaries>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(8); |
| color_config->transfer_characteristics = |
| static_cast<TransferCharacteristics>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(8); |
| color_config->matrix_coefficients = |
| static_cast<MatrixCoefficients>(scratch); |
| } else { |
| color_config->color_primaries = kColorPrimaryUnspecified; |
| color_config->transfer_characteristics = kTransferCharacteristicUnspecified; |
| color_config->matrix_coefficients = kMatrixCoefficientUnspecified; |
| } |
| if (color_config->is_monochrome) { |
| OBU_READ_BIT_OR_FAIL; |
| color_config->color_range = 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_primaries == kColorPrimaryBt709 && |
| color_config->transfer_characteristics == kTransferCharacteristicSrgb && |
| color_config->matrix_coefficients == kMatrixCoefficientIdentity) { |
| color_config->color_range = 1; |
| color_config->subsampling_x = 0; |
| color_config->subsampling_y = 0; |
| } else { |
| OBU_READ_BIT_OR_FAIL; |
| color_config->color_range = 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<ChromaSamplePosition>(scratch); |
| } |
| } |
| OBU_READ_BIT_OR_FAIL; |
| color_config->separate_uv_delta_q = static_cast<bool>(scratch); |
| } |
| if (color_config->matrix_coefficients == kMatrixCoefficientIdentity && |
| (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 = static_cast<bool>(scratch); |
| 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<uint32_t>(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<uint32_t>(scratch); |
| if (info->time_scale == 0) { |
| LIBGAV1_DLOG(ERROR, "time_scale is 0."); |
| return false; |
| } |
| OBU_READ_BIT_OR_FAIL; |
| info->equal_picture_interval = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| 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<uint32_t>(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] = |
| static_cast<bool>(scratch); |
| 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<uint32_t>(scratch); |
| OBU_READ_LITERAL_OR_FAIL( |
| sequence_header->decoder_model_info.encoder_decoder_buffer_delay_length); |
| params->encoder_buffer_delay[index] = static_cast<uint32_t>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| params->low_delay_mode_flag[index] = static_cast<bool>(scratch); |
| return true; |
| } |
| |
| bool ObuParser::ParseSequenceHeader() { |
| ObuSequenceHeader sequence_header = {}; |
| int64_t scratch; |
| OBU_READ_LITERAL_OR_FAIL(3); |
| if (scratch >= kMaxProfiles) { |
| LIBGAV1_DLOG(ERROR, "Invalid profile: %d.", static_cast<int>(scratch)); |
| return false; |
| } |
| sequence_header.profile = static_cast<BitstreamProfile>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.still_picture = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.reduced_still_picture_header = static_cast<bool>(scratch); |
| 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 auto initial_display_delay_present_flag = static_cast<bool>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(5); |
| sequence_header.operating_points = static_cast<int>(1 + scratch); |
| for (int i = 0; i < sequence_header.operating_points; ++i) { |
| OBU_READ_LITERAL_OR_FAIL(12); |
| sequence_header.operating_point_idc[i] = static_cast<int>(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 (static_cast<bool>(scratch)) { |
| OBU_READ_LITERAL_OR_FAIL(4); |
| sequence_header.operating_parameters.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<int32_t>(1 + scratch); |
| OBU_READ_LITERAL_OR_FAIL(sequence_header.frame_height_bits); |
| sequence_header.max_frame_height = static_cast<int32_t>(1 + scratch); |
| if (!sequence_header.reduced_still_picture_header) { |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.frame_id_numbers_present = static_cast<bool>(scratch); |
| } |
| 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 = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_filter_intra = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_intra_edge_filter = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_masked_compound = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_warped_motion = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_dual_filter = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_order_hint = static_cast<bool>(scratch); |
| if (sequence_header.enable_order_hint) { |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_jnt_comp = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_ref_frame_mvs = static_cast<bool>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.choose_screen_content_tools = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| 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; |
| } |
| } |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_superres = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_cdef = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.enable_restoration = static_cast<bool>(scratch); |
| if (!ParseColorConfig(&sequence_header)) return false; |
| OBU_READ_BIT_OR_FAIL; |
| sequence_header.film_grain_params_present = static_cast<bool>(scratch); |
| // TODO(wtc): Compare new sequence header with old sequence header. |
| sequence_header_ = sequence_header; |
| 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[kOperatingPoint] == 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_valid[i] = false; |
| } |
| } else { |
| if (reference_frame_id > decoder_state_.current_frame_id && |
| reference_frame_id < lower_bound) { |
| decoder_state_.reference_valid[i] = false; |
| } |
| } |
| } |
| } |
| |
| 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<int32_t>(1 + scratch); |
| OBU_READ_LITERAL_OR_FAIL(sequence_header_.frame_height_bits); |
| frame_header_.height = static_cast<int32_t>(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 = static_cast<bool>(scratch); |
| if (frame_header_.render_and_frame_size_different) { |
| OBU_READ_LITERAL_OR_FAIL(16); |
| frame_header_.render_width = static_cast<int32_t>(1 + scratch); |
| OBU_READ_LITERAL_OR_FAIL(16); |
| frame_header_.render_height = static_cast<int32_t>(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; |
| bool use_superres = false; |
| if (sequence_header_.enable_superres) { |
| OBU_READ_BIT_OR_FAIL; |
| use_superres = static_cast<bool>(scratch); |
| } |
| if (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_valid[i] = false; |
| } |
| } |
| return true; |
| } |
| |
| // static |
| int ObuParser::FindLatestBackwardReference( |
| const int current_frame_hint, |
| const std::array<int, kNumReferenceFrameTypes>& shifted_order_hints, |
| const std::array<bool, kNumReferenceFrameTypes>& 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<int, kNumReferenceFrameTypes>& shifted_order_hints, |
| const std::array<bool, kNumReferenceFrameTypes>& 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<int, kNumReferenceFrameTypes>& shifted_order_hints, |
| const std::array<bool, kNumReferenceFrameTypes>& 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<int, kNumReferenceFrameTypes>& 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<bool, kNumReferenceFrameTypes> used_frame; |
| used_frame.fill(false); |
| used_frame[last_frame_idx] = true; |
| used_frame[gold_frame_idx] = true; |
| |
| 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<int, kNumReferenceFrameTypes> shifted_order_hints; |
| for (int i = 0; i < kNumReferenceFrameTypes; ++i) { |
| const int reference_hint = decoder_state_.reference_order_hint[i]; |
| const int relative_distance = GetRelativeDistance( |
| reference_hint, frame_header_.order_hint, |
| sequence_header_.enable_order_hint, sequence_header_.order_hint_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 = static_cast<bool>(scratch); |
| if (loop_filter->delta_enabled) { |
| OBU_READ_BIT_OR_FAIL; |
| const auto loop_filter_delta_update = static_cast<bool>(scratch); |
| if (loop_filter_delta_update) { |
| for (auto& ref_delta : loop_filter->ref_deltas) { |
| OBU_READ_BIT_OR_FAIL; |
| const auto update_ref_delta = static_cast<bool>(scratch); |
| 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 auto update_mode_delta = static_cast<bool>(scratch); |
| 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; |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool ObuParser::ParseDeltaQuantizer(int8_t* const delta) { |
| int64_t scratch; |
| *delta = 0; |
| OBU_READ_BIT_OR_FAIL; |
| const auto delta_coded = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| } |
| 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 = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| if (segmentation->update_map) { |
| OBU_READ_BIT_OR_FAIL; |
| segmentation->temporal_update = static_cast<bool>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| segmentation->update_data = static_cast<bool>(scratch); |
| 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] = static_cast<bool>(scratch); |
| if (segmentation->feature_enabled[i][j]) { |
| if (Segmentation::FeatureSigned(static_cast<SegmentFeature>(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 { |
| OBU_READ_LITERAL_OR_FAIL(kSegmentationFeatureBits[j]); |
| segmentation->feature_data[i][j] = Clip3( |
| static_cast<int>(scratch), 0, kSegmentationFeatureMaxValues[j]); |
| } |
| 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 = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| } |
| 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 = static_cast<bool>(scratch); |
| } |
| } |
| 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() { |
| if (frame_header_.coded_lossless || frame_header_.allow_intrabc || |
| !sequence_header_.enable_cdef) { |
| frame_header_.cdef.damping = 3; |
| return true; |
| } |
| Cdef* const cdef = &frame_header_.cdef; |
| int64_t scratch; |
| OBU_READ_LITERAL_OR_FAIL(2); |
| cdef->damping = scratch + 3; |
| 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; |
| OBU_READ_LITERAL_OR_FAIL(2); |
| cdef->y_secondary_strength[i] = scratch; |
| if (cdef->y_secondary_strength[i] == 3) ++cdef->y_secondary_strength[i]; |
| if (sequence_header_.color_config.is_monochrome) continue; |
| OBU_READ_LITERAL_OR_FAIL(4); |
| cdef->uv_primary_strength[i] = scratch; |
| OBU_READ_LITERAL_OR_FAIL(2); |
| cdef->uv_secondary_strength[i] = scratch; |
| if (cdef->uv_secondary_strength[i] == 3) ++cdef->uv_secondary_strength[i]; |
| } |
| 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<LoopRestorationType>(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[kPlaneY] = |
| kLoopRestorationTileSizeMax >> (2 - 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[kPlaneU] = |
| loop_restoration->unit_size[kPlaneV] = |
| loop_restoration->unit_size[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 = static_cast<bool>(scratch); |
| } |
| 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 int reference_hint = |
| decoder_state_ |
| .reference_order_hint[frame_header_.reference_frame_index[i]]; |
| const int relative_distance = GetRelativeDistance( |
| reference_hint, frame_header_.order_hint, |
| sequence_header_.enable_order_hint, sequence_header_.order_hint_bits); |
| if (relative_distance < 0) { |
| if (forward_index < 0 || |
| GetRelativeDistance(reference_hint, forward_hint, |
| sequence_header_.enable_order_hint, |
| sequence_header_.order_hint_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_.enable_order_hint, |
| sequence_header_.order_hint_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<ReferenceFrameType>( |
| kReferenceFrameLast + std::min(forward_index, backward_index)); |
| frame_header_.skip_mode_frame[1] = static_cast<ReferenceFrameType>( |
| 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 int reference_hint = |
| decoder_state_ |
| .reference_order_hint[frame_header_.reference_frame_index[i]]; |
| if (GetRelativeDistance(reference_hint, forward_hint, |
| sequence_header_.enable_order_hint, |
| sequence_header_.order_hint_bits) < 0) { |
| if (second_forward_index < 0 || |
| GetRelativeDistance(reference_hint, second_forward_hint, |
| sequence_header_.enable_order_hint, |
| sequence_header_.order_hint_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<ReferenceFrameType>( |
| kReferenceFrameLast + std::min(forward_index, second_forward_index)); |
| frame_header_.skip_mode_frame[1] = static_cast<ReferenceFrameType>( |
| 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 = static_cast<bool>(scratch); |
| return true; |
| } |
| |
| // Sets frame_header_.global_motion[ref].params[index]. |
| bool ObuParser::ParseGlobalParamSyntax( |
| int ref, int index, |
| const std::array<GlobalMotion, kNumReferenceFrameTypes>& |
| 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<int>(!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<GlobalMotion, kNumReferenceFrameTypes>* 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 auto is_global = static_cast<bool>(scratch); |
| if (is_global) { |
| OBU_READ_BIT_OR_FAIL; |
| const auto is_rot_zoom = static_cast<bool>(scratch); |
| if (is_rot_zoom) { |
| global_motion->type = kGlobalMotionTransformationTypeRotZoom; |
| } else { |
| OBU_READ_BIT_OR_FAIL; |
| const auto is_translation = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| 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<int>(scratch); |
| film_grain_params.update_grain = true; |
| if (frame_header_.frame_type == kFrameInter) { |
| OBU_READ_BIT_OR_FAIL; |
| film_grain_params.update_grain = static_cast<bool>(scratch); |
| } |
| if (!film_grain_params.update_grain) { |
| OBU_READ_LITERAL_OR_FAIL(3); |
| film_grain_params.reference_index = static_cast<int>(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 = static_cast<bool>(scratch); |
| } |
| 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<int>(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<int>(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<int>(scratch) - 128; |
| } |
| } |
| OBU_READ_LITERAL_OR_FAIL(2); |
| film_grain_params.auto_regression_shift = scratch + 6; |
| OBU_READ_LITERAL_OR_FAIL(2); |
| film_grain_params.grain_scale_shift = static_cast<int>(scratch); |
| if (film_grain_params.num_u_points > 0) { |
| OBU_READ_LITERAL_OR_FAIL(8); |
| film_grain_params.u_multiplier = static_cast<int>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(8); |
| film_grain_params.u_luma_multiplier = static_cast<int>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(9); |
| film_grain_params.u_offset = static_cast<int>(scratch); |
| } |
| if (film_grain_params.num_v_points > 0) { |
| OBU_READ_LITERAL_OR_FAIL(8); |
| film_grain_params.v_multiplier = static_cast<int>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(8); |
| film_grain_params.v_luma_multiplier = static_cast<int>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(9); |
| film_grain_params.v_offset = static_cast<int>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| film_grain_params.overlap_flag = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| film_grain_params.clip_to_restricted_range = static_cast<bool>(scratch); |
| 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<int>(kMaxTileColumns))); |
| const int maxlog2_tile_rows = |
| CeilLog2(std::min(sb_rows, static_cast<int>(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 = static_cast<bool>(scratch); |
| 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<int>(sb_max_tile_width)); |
| int sb_size; |
| if (!bit_reader_->DecodeUniform(max_width, &sb_size)) { |
| LIBGAV1_DLOG(ERROR, "Not enough bits."); |
| return false; |
| } |
| ++sb_size; |
| widest_tile_sb = std::max(sb_size, widest_tile_sb); |
| sb_start += sb_size; |
| } |
| 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); |
| int sb_size; |
| if (!bit_reader_->DecodeUniform(max_height, &sb_size)) { |
| LIBGAV1_DLOG(ERROR, "Not enough bits."); |
| return false; |
| } |
| ++sb_size; |
| sb_start += sb_size; |
| } |
| 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; |
| 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<int16_t>(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 = static_cast<bool>(scratch); |
| return true; |
| } |
| |
| bool ObuParser::ParseFrameParameters() { |
| int64_t scratch; |
| if (sequence_header_.reduced_still_picture_header) { |
| frame_header_.show_frame = true; |
| } else { |
| OBU_READ_BIT_OR_FAIL; |
| frame_header_.show_existing_frame = static_cast<bool>(scratch); |
| 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<uint32_t>(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<uint16_t>(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. |
| if (frame_header_.display_frame_id != |
| decoder_state_ |
| .reference_frame_id[frame_header_.frame_to_show] || |
| !decoder_state_.reference_valid[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. |
| decoder_state_.current_frame = |
| decoder_state_.reference_frame[frame_header_.frame_to_show]; |
| if (decoder_state_.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 (!decoder_state_.current_frame->showable_frame()) { |
| LIBGAV1_DLOG(ERROR, "Buffer %d does not contain a showable frame", |
| frame_header_.frame_to_show); |
| return false; |
| } |
| if (decoder_state_.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. |
| decoder_state_.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; |
| } |
| OBU_READ_LITERAL_OR_FAIL(2); |
| frame_header_.frame_type = static_cast<FrameType>(scratch); |
| decoder_state_.current_frame->set_frame_type(frame_header_.frame_type); |
| OBU_READ_BIT_OR_FAIL; |
| frame_header_.show_frame = static_cast<bool>(scratch); |
| 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<uint32_t>(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 = static_cast<bool>(scratch); |
| } |
| decoder_state_.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 = static_cast<bool>(scratch); |
| } |
| } |
| if (frame_header_.frame_type == kFrameKey && frame_header_.show_frame) { |
| decoder_state_.reference_valid.fill(false); |
| decoder_state_.reference_order_hint.fill(0); |
| decoder_state_.current_frame->ClearOrderHints(); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| frame_header_.enable_cdf_update = !static_cast<bool>(scratch); |
| if (sequence_header_.force_screen_content_tools == |
| kSelectScreenContentTools) { |
| OBU_READ_BIT_OR_FAIL; |
| frame_header_.allow_screen_content_tools = static_cast<bool>(scratch); |
| } else { |
| frame_header_.allow_screen_content_tools = |
| static_cast<bool>(sequence_header_.force_screen_content_tools); |
| } |
| 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<uint16_t>(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) && |
| 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 = static_cast<bool>(scratch); |
| } |
| 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 auto buffer_removal_time_present = static_cast<bool>(scratch); |
| 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<uint32_t>(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 = static_cast<bool>(scratch); |
| } |
| } 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 = static_cast<bool>(scratch); |
| 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; |
| } |
| // Check if the inter frame requests a nonexistent reference, whether or |
| // not frame_refs_short_signaling is used. |
| assert(frame_header_.reference_frame_index[i] >= 0); |
| if (decoder_state_ |
| .reference_frame[frame_header_.reference_frame_index[i]] == |
| nullptr) { |
| LIBGAV1_DLOG(ERROR, "ref_frame_idx[%d] (%d) is not a decoded frame.", i, |
| frame_header_.reference_frame_index[i]); |
| 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<int>(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 ] ] ... |
| // |
| // Section 6.8.2: It is a requirement of bitstream conformance that |
| // RefValid[ ref_frame_idx[ i ] ] is equal to 1, ... |
| if (frame_header_.expected_frame_id[i] != |
| decoder_state_.reference_frame_id |
| [frame_header_.reference_frame_index[i]] || |
| !decoder_state_ |
| .reference_valid[frame_header_.reference_frame_index[i]]) { |
| LIBGAV1_DLOG(ERROR, |
| "Reference buffer %d has a frame id number mismatch.", |
| frame_header_.reference_frame_index[i]); |
| 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 = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| const auto is_filter_switchable = static_cast<bool>(scratch); |
| if (is_filter_switchable) { |
| frame_header_.interpolation_filter = kInterpolationFilterSwitchable; |
| } else { |
| OBU_READ_LITERAL_OR_FAIL(2); |
| frame_header_.interpolation_filter = |
| static_cast<InterpolationFilter>(scratch); |
| } |
| OBU_READ_BIT_OR_FAIL; |
| frame_header_.is_motion_mode_switchable = static_cast<bool>(scratch); |
| 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 = static_cast<bool>(scratch); |
| } |
| } |
| // 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 (!decoder_state_.current_frame->SetFrameDimensions(frame_header_)) { |
| LIBGAV1_DLOG(ERROR, "Setting current frame dimensions failed."); |
| return false; |
| } |
| if (!IsIntraFrame(frame_header_.frame_type)) { |
| for (int i = 0; i < kNumInterReferenceFrameTypes; ++i) { |
| const auto reference_frame = |
| static_cast<ReferenceFrameType>(kReferenceFrameLast + i); |
| const uint8_t hint = |
| decoder_state_ |
| .reference_order_hint[frame_header_.reference_frame_index[i]]; |
| decoder_state_.current_frame->set_order_hint(reference_frame, hint); |
| decoder_state_.reference_frame_sign_bias[reference_frame] = |
| GetRelativeDistance(hint, frame_header_.order_hint, |
| sequence_header_.enable_order_hint, |
| sequence_header_.order_hint_bits) > 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 = !static_cast<bool>(scratch); |
| } 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; |
| bool status = ParseTileInfoSyntax() && ParseQuantizerParameters() && |
| ParseSegmentationParameters(); |
| if (!status) return false; |
| decoder_state_.current_frame->SetSegmentationParameters( |
| frame_header_.segmentation); |
| status = |
| ParseQuantizerIndexDeltaParameters() && ParseLoopFilterDeltaParameters(); |
| if (!status) return false; |
| ComputeSegmentLosslessAndQIndex(); |
| status = ParseLoopFilterParameters(); |
| if (!status) return false; |
| decoder_state_.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 = static_cast<bool>(scratch); |
| status = ParseGlobalMotionParameters(); |
| if (!status) return false; |
| decoder_state_.current_frame->SetGlobalMotions(frame_header_.global_motion); |
| status = ParseFilmGrainParameters(); |
| if (!status) return false; |
| if (sequence_header_.film_grain_params_present) { |
| decoder_state_.current_frame->set_film_grain_params( |
| frame_header_.film_grain_params); |
| } |
| return true; |
| } |
| |
| bool ObuParser::ParseMetadata(size_t size) { |
| int64_t scratch; |
| OBU_READ_LITERAL_OR_FAIL(16); |
| size -= 2; |
| const auto type = static_cast<MetadataType>(scratch); |
| switch (type) { |
| case kMetadataTypeHdrContentLightLevel: |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.max_cll = scratch; |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.max_fall = scratch; |
| break; |
| case kMetadataTypeHdrMasteringDisplayColorVolume: |
| for (int i = 0; i < 3; ++i) { |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.primary_chromaticity_x[i] = scratch; |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.primary_chromaticity_y[i] = scratch; |
| } |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.white_point_chromaticity_x = scratch; |
| OBU_READ_LITERAL_OR_FAIL(16); |
| metadata_.white_point_chromaticity_y = scratch; |
| OBU_READ_LITERAL_OR_FAIL(32); |
| metadata_.luminance_max = static_cast<uint32_t>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(32); |
| metadata_.luminance_min = static_cast<uint32_t>(scratch); |
| break; |
| default: |
| LIBGAV1_DLOG(ERROR, "Unknown metadata type: %u", type); |
| return false; |
| } |
| return true; |
| } |
| |
| bool ObuParser::ValidateTileGroup() { |
| const auto& tile_group = tile_groups_.back(); |
| if (tile_group.start != next_tile_group_start_ || |
| tile_group.start > tile_group.end || |
| tile_group.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.", |
| tile_group.start, tile_group.end, next_tile_group_start_, |
| frame_header_.tile_info.tile_count); |
| return false; |
| } |
| next_tile_group_start_ = tile_group.end + 1; |
| return true; |
| } |
| |
| void ObuParser::SetTileDataOffset(size_t total_size, size_t tg_header_size, |
| size_t bytes_consumed_so_far) { |
| auto& tile_group = tile_groups_.back(); |
| tile_group.data_size = total_size - tg_header_size; |
| tile_group.data_offset = bytes_consumed_so_far + tg_header_size; |
| tile_group.data = data_ + tile_group.data_offset; |
| } |
| |
| 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_groups_.emplace_back()) { |
| LIBGAV1_DLOG(ERROR, "Could not add an element to tile_groups_."); |
| return false; |
| } |
| auto& tile_group = tile_groups_.back(); |
| if (tile_bits == 0) { |
| tile_group.start = 0; |
| tile_group.end = 0; |
| if (!ValidateTileGroup()) return false; |
| SetTileDataOffset(size, 0, bytes_consumed_so_far); |
| return true; |
| } |
| int64_t scratch; |
| OBU_READ_BIT_OR_FAIL; |
| const auto tile_start_and_end_present_flag = static_cast<bool>(scratch); |
| if (!tile_start_and_end_present_flag) { |
| tile_group.start = 0; |
| tile_group.end = tile_info->tile_count - 1; |
| if (!ValidateTileGroup()) return false; |
| if (!bit_reader_->AlignToNextByte()) { |
| LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits."); |
| return false; |
| } |
| SetTileDataOffset(size, 1, bytes_consumed_so_far); |
| return true; |
| } |
| 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); |
| tile_group.start = static_cast<int>(scratch); |
| OBU_READ_LITERAL_OR_FAIL(tile_bits); |
| tile_group.end = static_cast<int>(scratch); |
| if (!ValidateTileGroup()) return false; |
| 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; |
| SetTileDataOffset(size, tg_header_size, bytes_consumed_so_far); |
| return true; |
| } |
| |
| 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<libgav1::ObuType>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| const auto extension_flag = static_cast<bool>(scratch); |
| OBU_READ_BIT_OR_FAIL; |
| const auto has_size_field = static_cast<bool>(scratch); |
| if (!has_size_field) { |
| LIBGAV1_DLOG( |
| ERROR, |
| "has_size_field is zero. libgav1 does not support such streams."); |
| return false; |
| } |
| OBU_READ_BIT_OR_FAIL; // reserved. |
| if (scratch != 0) { |
| LIBGAV1_DLOG(ERROR, "obu_reserved_1bit is not zero."); |
| return false; |
| } |
| 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(ERROR, "extension_header_reserved_3bits is not zero."); |
| return false; |
| } |
| } 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::HasData() const { return size_ > 0; } |
| |
| bool ObuParser::ParseOneFrame() { |
| if (data_ == nullptr || size_ == 0) return false; |
| const uint8_t* data = data_; |
| size_t size = size_; |
| |
| // Clear everything except the sequence header. |
| obu_headers_.clear(); |
| frame_header_ = {}; |
| tile_groups_.clear(); |
| next_tile_group_start_ = 0; |
| // TODO(b/120903866): |metadata_| must be reset here. |
| |
| 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 false; |
| } |
| if (!ParseHeader()) { |
| LIBGAV1_DLOG(ERROR, "Failed to parse OBU Header."); |
| return false; |
| } |
| 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 false; |
| } |
| 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 false; |
| } |
| |
| const ObuHeader& obu_header = obu_headers_.back(); |
| const ObuType obu_type = obu_header.type; |
| if (obu_type != kObuSequenceHeader && obu_type != kObuTemporalDelimiter && |
| has_sequence_header_ && |
| sequence_header_.operating_point_idc[kOperatingPoint] != 0 && |
| obu_header.has_extension && |
| (!InTemporalLayer(sequence_header_.operating_point_idc[kOperatingPoint], |
| obu_header.temporal_id) || |
| !InSpatialLayer(sequence_header_.operating_point_idc[kOperatingPoint], |
| 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(); |
| bool obu_skipped = false; |
| switch (obu_type) { |
| case kObuTemporalDelimiter: |
| break; |
| case kObuSequenceHeader: |
| if (!ParseSequenceHeader()) { |
| LIBGAV1_DLOG(ERROR, "Failed to parse SequenceHeader OBU."); |
| return false; |
| } |
| break; |
| case kObuFrameHeader: |
| if (seen_frame_header) { |
| LIBGAV1_DLOG(ERROR, |
| "Frame header found but frame header was already seen."); |
| return false; |
| } |
| if (!ParseFrameHeader()) { |
| LIBGAV1_DLOG(ERROR, "Failed to parse FrameHeader OBU."); |
| return false; |
| } |
| 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 false; |
| } |
| 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 false; |
| } |
| 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 false; |
| } |
| if (!ParseFrameHeader()) { |
| LIBGAV1_DLOG(ERROR, "Failed to parse FrameHeader in Frame OBU."); |
| return false; |
| } |
| // 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 false; |
| } |
| if (!bit_reader_->AlignToNextByte()) { |
| LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits."); |
| return false; |
| } |
| 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 false; |
| } |
| if (!ParseTileGroup(obu_size - fh_size, |
| size_ - size + bit_reader_->byte_offset())) { |
| LIBGAV1_DLOG(ERROR, "Failed to parse TileGroup in Frame OBU."); |
| return false; |
| } |
| bit_reader_->SkipBytes(tile_groups_.back().data_size); |
| 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 false; |
| } |
| bit_reader_->SkipBytes(tile_groups_.back().data_size); |
| parsed_one_full_frame = |
| (tile_groups_.back().end == frame_header_.tile_info.tile_count - 1); |
| break; |
| case kObuTileList: |
| LIBGAV1_DLOG(ERROR, "Decoding of tile list OBUs is not supported."); |
| return false; |
| case kObuPadding: |
| // TODO(b/120903866): Fix ParseMetadata() and then invoke that for the |
| // kObuMetadata case. |
| case kObuMetadata: |
| bit_reader_->SkipBytes(obu_size); |
| obu_skipped = true; |
| 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 false; |
| } |
| 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 false; |
| } |
| } |
| 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 false; |
| } |
| 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 false; |
| } |
| data_ = data; |
| size_ = size; |
| return true; |
| } |
| |
| } // namespace libgav1 |