Snap for 6439596 from ba339ef3a3f4b1b9126fa733eb23fea613b01256 to qt-aml-tzdata-release
Change-Id: I37b84430500d24506e251e6a4f93c8d74e661076
diff --git a/README.version b/README.version
new file mode 100644
index 0000000..5d15f7f
--- /dev/null
+++ b/README.version
@@ -0,0 +1,11 @@
+URL: https://chromium.googlesource.com/codecs/libgav1
+Version: cl/267700628
+BugComponent: 324837
+Local Modifications:
+- ab3390a external/libgav1,cosmetics: add license headers
+- backport cl/281117442: Fully use the frame border for reference block.
+- backport cl/289984918: convolve: Use the correct subsampling for ref frames
+- backport cl/289966078: Move initial_display_delay out of OperatingParamet
+- backport cl/290784565: Handle a change of sequence header parameters.
+- backport cl/291222461: Disallow change of sequence header during a frame.
+- backport cl/289910031: obu: Check for size validity in SetTileDataOffset
diff --git a/libgav1/src/decoder_impl.cc b/libgav1/src/decoder_impl.cc
index 9448247..11f2682 100644
--- a/libgav1/src/decoder_impl.cc
+++ b/libgav1/src/decoder_impl.cc
@@ -50,6 +50,27 @@
} // namespace
+void DecoderState::UpdateReferenceFrames(int refresh_frame_flags) {
+ for (int ref_index = 0, mask = refresh_frame_flags; mask != 0;
+ ++ref_index, mask >>= 1) {
+ if ((mask & 1) != 0) {
+ reference_valid[ref_index] = true;
+ reference_frame_id[ref_index] = current_frame_id;
+ reference_frame[ref_index] = current_frame;
+ reference_order_hint[ref_index] = order_hint;
+ }
+ }
+}
+
+void DecoderState::ClearReferenceFrames() {
+ reference_valid = {};
+ reference_frame_id = {};
+ reference_order_hint = {};
+ for (int ref_index = 0; ref_index < kNumReferenceFrameTypes; ++ref_index) {
+ reference_frame[ref_index] = nullptr;
+ }
+}
+
// static
StatusCode DecoderImpl::Create(const DecoderSettings* settings,
std::unique_ptr<DecoderImpl>* output) {
@@ -173,7 +194,7 @@
return status;
}
}
- UpdateReferenceFrames(obu->frame_header().refresh_frame_flags);
+ state_.UpdateReferenceFrames(obu->frame_header().refresh_frame_flags);
if (obu->frame_header().show_frame ||
obu->frame_header().show_existing_frame) {
if (displayable_frame != nullptr) {
@@ -195,11 +216,11 @@
obu->frame_header().refresh_frame_flags == 0) {
// If show_existing_frame is true, then the current frame is a
// previously saved reference frame. If refresh_frame_flags is
- // nonzero, then the UpdateReferenceFrames() call above has saved the
- // current frame as a reference frame. Therefore, if both of these
- // conditions are false, then the current frame is not saved as a
- // reference frame. displayable_frame should hold the only reference
- // to the current frame.
+ // nonzero, then the state_.UpdateReferenceFrames() call above has
+ // saved the current frame as a reference frame. Therefore, if both
+ // of these conditions are false, then the current frame is not
+ // saved as a reference frame. displayable_frame should hold the
+ // only reference to the current frame.
assert(displayable_frame.use_count() == 1);
// Add film grain noise in place.
film_grain_frame = displayable_frame;
@@ -665,16 +686,4 @@
}
}
-void DecoderImpl::UpdateReferenceFrames(int refresh_frame_flags) {
- for (int ref_index = 0, mask = refresh_frame_flags; mask != 0;
- ++ref_index, mask >>= 1) {
- if ((mask & 1) != 0) {
- state_.reference_valid[ref_index] = true;
- state_.reference_frame_id[ref_index] = state_.current_frame_id;
- state_.reference_frame[ref_index] = state_.current_frame;
- state_.reference_order_hint[ref_index] = state_.order_hint;
- }
- }
-}
-
} // namespace libgav1
diff --git a/libgav1/src/decoder_impl.h b/libgav1/src/decoder_impl.h
index 4e4c6b5..e58a0da 100644
--- a/libgav1/src/decoder_impl.h
+++ b/libgav1/src/decoder_impl.h
@@ -41,6 +41,13 @@
};
struct DecoderState {
+ // Section 7.20. Updates frames in the reference_frame array with
+ // current_frame, based on the refresh_frame_flags bitmask.
+ void UpdateReferenceFrames(int refresh_frame_flags);
+
+ // Clears all the reference frames.
+ void ClearReferenceFrames();
+
ObuSequenceHeader sequence_header = {};
// If true, sequence_header is valid.
bool has_sequence_header = false;
@@ -64,8 +71,8 @@
//
// NOTE: When show_existing_frame is false, it is often more convenient to
// just use the order_hint field of the frame header as OrderHint. So this
- // field is mainly used to update the state_.reference_order_hint array in
- // DecoderImpl::UpdateReferenceFrames().
+ // field is mainly used to update the reference_order_hint array in
+ // UpdateReferenceFrames().
uint8_t order_hint = 0;
// reference_frame_sign_bias[i] (a boolean) specifies the intended direction
// of the motion vector in time for each reference frame.
@@ -118,9 +125,6 @@
// is handled in Tile::DecodeBlock().
void SetCurrentFrameSegmentationMap(const ObuFrameHeader& frame_header,
const SegmentationMap* prev_segment_ids);
- // Section 7.20. Updates frames in the state_.reference_frame array with
- // state_.current_frame, based on the refresh_frame_flags bitmask.
- void UpdateReferenceFrames(int refresh_frame_flags);
Queue<EncodedFrame> encoded_frames_;
DecoderState state_;
diff --git a/libgav1/src/obu_parser.cc b/libgav1/src/obu_parser.cc
index 644f1a5..c4b8e94 100644
--- a/libgav1/src/obu_parser.cc
+++ b/libgav1/src/obu_parser.cc
@@ -4,6 +4,7 @@
#include <array>
#include <cassert>
#include <climits>
+#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -60,6 +61,15 @@
} // namespace
+bool ObuSequenceHeader::ParametersChanged(const ObuSequenceHeader& old) const {
+ // Note that the operating_parameters field is not compared per Section 7.5:
+ // Within a particular coded video sequence, the contents of
+ // sequence_header_obu must be bit-identical each time the sequence header
+ // appears except for the contents of operating_parameters_info.
+ return memcmp(this, &old,
+ offsetof(ObuSequenceHeader, operating_parameters)) != 0;
+}
+
// Macros to avoid repeated error checks in the parser code.
#define OBU_LOG_AND_RETURN_FALSE \
do { \
@@ -247,7 +257,7 @@
return true;
}
-bool ObuParser::ParseSequenceHeader() {
+bool ObuParser::ParseSequenceHeader(bool seen_frame_header) {
ObuSequenceHeader sequence_header = {};
int64_t scratch;
OBU_READ_LITERAL_OR_FAIL(3);
@@ -307,8 +317,7 @@
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;
+ sequence_header.initial_display_delay[i] = 1 + scratch;
}
}
}
@@ -400,7 +409,17 @@
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.
+ // Compare new sequence header with old sequence header.
+ if (has_sequence_header_ &&
+ sequence_header.ParametersChanged(sequence_header_)) {
+ // Between the frame header OBU and the last tile group OBU of the frame,
+ // do not allow the sequence header to change.
+ if (seen_frame_header) {
+ LIBGAV1_DLOG(ERROR, "Sequence header changed in the middle of a frame.");
+ return false;
+ }
+ decoder_state_.ClearReferenceFrames();
+ }
sequence_header_ = sequence_header;
has_sequence_header_ = true;
// Section 6.4.1: It is a requirement of bitstream conformance that if
@@ -1944,6 +1963,20 @@
}
}
}
+ // Validate frame_header_.primary_reference_frame.
+ if (frame_header_.primary_reference_frame != kPrimaryReferenceNone) {
+ const int index =
+ frame_header_
+ .reference_frame_index[frame_header_.primary_reference_frame];
+ if (decoder_state_.reference_frame[index] == nullptr) {
+ LIBGAV1_DLOG(ERROR,
+ "primary_ref_frame is %d but ref_frame_idx[%d] (%d) is "
+ "not a decoded frame.",
+ frame_header_.primary_reference_frame,
+ frame_header_.primary_reference_frame, index);
+ return false;
+ }
+ }
if (frame_header_.frame_size_override_flag &&
!frame_header_.error_resilient_mode) {
// Section 5.9.7.
@@ -2114,12 +2147,18 @@
return true;
}
-void ObuParser::SetTileDataOffset(size_t total_size, size_t tg_header_size,
+bool ObuParser::SetTileDataOffset(size_t total_size, size_t tg_header_size,
size_t bytes_consumed_so_far) {
+ if (total_size < tg_header_size) {
+ LIBGAV1_DLOG(ERROR, "total_size (%zu) is less than tg_header_size (%zu).)",
+ total_size, tg_header_size);
+ return false;
+ }
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;
+ return true;
}
bool ObuParser::ParseTileGroup(size_t size, size_t bytes_consumed_so_far) {
@@ -2136,8 +2175,7 @@
tile_group.start = 0;
tile_group.end = 0;
if (!ValidateTileGroup()) return false;
- SetTileDataOffset(size, 0, bytes_consumed_so_far);
- return true;
+ return SetTileDataOffset(size, 0, bytes_consumed_so_far);
}
int64_t scratch;
OBU_READ_BIT_OR_FAIL;
@@ -2150,8 +2188,7 @@
LIBGAV1_DLOG(ERROR, "Byte alignment has non zero bits.");
return false;
}
- SetTileDataOffset(size, 1, bytes_consumed_so_far);
- return true;
+ return SetTileDataOffset(size, 1, bytes_consumed_so_far);
}
if (obu_headers_.back().type == kObuFrame) {
// 6.10.1: If obu_type is equal to OBU_FRAME, it is a requirement of
@@ -2171,8 +2208,7 @@
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;
+ return SetTileDataOffset(size, tg_header_size, bytes_consumed_so_far);
}
bool ObuParser::ParseHeader() {
@@ -2296,7 +2332,7 @@
case kObuTemporalDelimiter:
break;
case kObuSequenceHeader:
- if (!ParseSequenceHeader()) {
+ if (!ParseSequenceHeader(seen_frame_header)) {
LIBGAV1_DLOG(ERROR, "Failed to parse SequenceHeader OBU.");
return false;
}
diff --git a/libgav1/src/obu_parser.h b/libgav1/src/obu_parser.h
index 9d972b1..e331e66 100644
--- a/libgav1/src/obu_parser.h
+++ b/libgav1/src/obu_parser.h
@@ -5,6 +5,7 @@
#include <cstddef>
#include <cstdint>
#include <memory>
+#include <type_traits>
#include "src/decoder_buffer.h"
#include "src/dsp/common.h"
@@ -166,13 +167,25 @@
};
struct OperatingParameters {
- uint8_t initial_display_delay[kMaxOperatingPoints];
uint32_t decoder_buffer_delay[kMaxOperatingPoints];
uint32_t encoder_buffer_delay[kMaxOperatingPoints];
bool low_delay_mode_flag[kMaxOperatingPoints];
};
struct ObuSequenceHeader {
+ // Section 7.5:
+ // Within a particular coded video sequence, the contents of
+ // sequence_header_obu must be bit-identical each time the sequence header
+ // appears except for the contents of operating_parameters_info. A new
+ // coded video sequence is required if the sequence header parameters
+ // change.
+ //
+ // IMPORTANT: ParametersChanged() is implemented with a memcmp() call. For
+ // this to work, this object and the |old| object must be initialized with
+ // an empty brace-enclosed list, which initializes any padding to zero bits.
+ // See https://en.cppreference.com/w/cpp/language/zero_initialization.
+ bool ParametersChanged(const ObuSequenceHeader& old) const;
+
BitstreamProfile profile;
bool still_picture;
bool reduced_still_picture_header;
@@ -213,11 +226,30 @@
bool decoder_model_info_present_flag;
DecoderModelInfo decoder_model_info;
bool decoder_model_present_for_operating_point[kMaxOperatingPoints];
- OperatingParameters operating_parameters;
bool initial_display_delay_present_flag;
+ uint8_t initial_display_delay[kMaxOperatingPoints];
bool film_grain_params_present;
+
+ // IMPORTANT: the operating_parameters member must be at the end of the
+ // struct so that ParametersChanged() can be implemented with a memcmp()
+ // call.
+ OperatingParameters operating_parameters;
};
+// Verify it is safe to use offsetof with ObuSequenceHeader and to use memcmp
+// to compare two ObuSequenceHeader objects.
+static_assert(std::is_standard_layout<ObuSequenceHeader>::value, "");
+// Verify operating_parameters is the last member of ObuSequenceHeader. The
+// second assertion assumes that ObuSequenceHeader has no padding after the
+// operating_parameters field. The first assertion is a sufficient condition
+// for ObuSequenceHeader to have no padding after the operating_parameters
+// field.
+static_assert(alignof(ObuSequenceHeader) == alignof(OperatingParameters), "");
+static_assert(sizeof(ObuSequenceHeader) ==
+ offsetof(ObuSequenceHeader, operating_parameters) +
+ sizeof(OperatingParameters),
+ "");
+
// Loop filter parameters:
//
// If level[0] and level[1] are both equal to 0, the loop filter process is
@@ -477,7 +509,7 @@
bool ParseDecoderModelInfo(ObuSequenceHeader* sequence_header); // 5.5.4.
bool ParseOperatingParameters(ObuSequenceHeader* sequence_header,
int index); // 5.5.5.
- bool ParseSequenceHeader(); // 5.5.1.
+ bool ParseSequenceHeader(bool seen_frame_header); // 5.5.1.
bool ParseFrameParameters(); // 5.9.2, 5.9.7 and 5.9.10.
void MarkInvalidReferenceFrames(); // 5.9.4.
bool ParseFrameSizeAndRenderSize(); // 5.9.5 and 5.9.6.
@@ -530,7 +562,7 @@
// valid, updates next_tile_group_start_ and returns true. Otherwise,
// returns false.
bool ValidateTileGroup();
- void SetTileDataOffset(size_t total_size, size_t tg_header_size,
+ bool SetTileDataOffset(size_t total_size, size_t tg_header_size,
size_t bytes_consumed_so_far);
bool ParseTileGroup(size_t size, size_t bytes_consumed_so_far); // 5.11.1.
diff --git a/libgav1/src/tile.h b/libgav1/src/tile.h
index fd7b7c0..61637cd 100644
--- a/libgav1/src/tile.h
+++ b/libgav1/src/tile.h
@@ -352,7 +352,8 @@
int width, int height, int ref_start_x,
int ref_last_x, int ref_start_y,
int ref_last_y, int start_x, int start_y,
- int step_x, int step_y, int right_border,
+ int step_x, int step_y, int left_border,
+ int right_border, int top_border,
int bottom_border, int* ref_block_start_x,
int* ref_block_start_y, int* ref_block_end_x,
int* ref_block_end_y);
diff --git a/libgav1/src/tile/prediction.cc b/libgav1/src/tile/prediction.cc
index dbf314d..89769fc 100644
--- a/libgav1/src/tile/prediction.cc
+++ b/libgav1/src/tile/prediction.cc
@@ -943,8 +943,9 @@
const int height, const int ref_start_x, const int ref_last_x,
const int ref_start_y, const int ref_last_y, const int start_x,
const int start_y, const int step_x, const int step_y,
- const int right_border, const int bottom_border, int* ref_block_start_x,
- int* ref_block_start_y, int* ref_block_end_x, int* ref_block_end_y) {
+ const int left_border, const int right_border, const int top_border,
+ const int bottom_border, int* ref_block_start_x, int* ref_block_start_y,
+ int* ref_block_end_x, int* ref_block_end_y) {
*ref_block_start_x = GetPixelPositionFromHighScale(start_x, 0, 0);
*ref_block_start_y = GetPixelPositionFromHighScale(start_y, 0, 0);
if (reference_frame_index == -1) {
@@ -964,11 +965,11 @@
kSubPixelTaps;
*ref_block_end_y = *ref_block_start_y + block_height - 1;
}
- const bool extend_left = *ref_block_start_x < ref_start_x;
- const bool extend_right = *ref_block_end_x > (ref_last_x + right_border);
- const bool extend_top = *ref_block_start_y < ref_start_y;
- const bool extend_bottom = *ref_block_end_y > (ref_last_y + bottom_border);
- return extend_left || extend_right || extend_top || extend_bottom;
+ // Determines if we need to extend beyond the left/right/top/bottom border.
+ return *ref_block_start_x < (ref_start_x - left_border) ||
+ *ref_block_end_x > (ref_last_x + right_border) ||
+ *ref_block_start_y < (ref_start_y - top_border) ||
+ *ref_block_end_y > (ref_last_y + bottom_border);
}
// Builds a block as the input for convolve, by copying the content of
@@ -1080,10 +1081,16 @@
: reference_frames_[reference_frame_index]->frame_height();
const int ref_start_x = 0;
const int ref_last_x =
- ((reference_upscaled_width + subsampling_x) >> subsampling_x) - 1;
+ SubsampledValue(
+ reference_upscaled_width,
+ (plane == kPlaneY) ? 0 : reference_buffer->subsampling_x()) -
+ 1;
const int ref_start_y = 0;
const int ref_last_y =
- ((reference_height + subsampling_y) >> subsampling_y) - 1;
+ SubsampledValue(
+ reference_height,
+ (plane == kPlaneY) ? 0 : reference_buffer->subsampling_y()) -
+ 1;
const bool is_scaled = (reference_frame_index != -1) &&
(frame_header_.width != reference_upscaled_width ||
@@ -1098,7 +1105,9 @@
bool extend_block = GetReferenceBlockPosition(
reference_frame_index, is_scaled, width, height, ref_start_x, ref_last_x,
ref_start_y, ref_last_y, start_x, start_y, step_x, step_y,
+ reference_buffer->left_border(plane),
reference_buffer->right_border(plane),
+ reference_buffer->top_border(plane),
reference_buffer->bottom_border(plane), &ref_block_start_x,
&ref_block_start_y, &ref_block_end_x, &ref_block_end_y);
const uint8_t* block_start = nullptr;
diff --git a/libgav1/src/utils/common.h b/libgav1/src/utils/common.h
index 9803364..b6d3f01 100644
--- a/libgav1/src/utils/common.h
+++ b/libgav1/src/utils/common.h
@@ -321,6 +321,10 @@
left_tx_size > kTransformSize8x32));
}
+constexpr int SubsampledValue(int value, int subsampling) {
+ return (subsampling == 0) ? value : DivideBy2(value + 1);
+}
+
} // namespace libgav1
#endif // LIBGAV1_SRC_UTILS_COMMON_H_