aboutsummaryrefslogtreecommitdiff
path: root/src/tile
diff options
context:
space:
mode:
authorBoyuan Yang <byang@debian.org>2021-11-07 08:50:18 -0500
committerBoyuan Yang <byang@debian.org>2021-11-07 08:50:18 -0500
commit320ef65362608ee1148c299d8d5d7618af34e470 (patch)
treec47911c219d1e35b8b0771e9e0176eff0e0d08ec /src/tile
parent2381d803c76105f44717d75f089ec37f51e5cfe4 (diff)
downloadlibgav1-320ef65362608ee1148c299d8d5d7618af34e470.tar.gz
libgav1-320ef65362608ee1148c299d8d5d7618af34e470.tar.bz2
libgav1-320ef65362608ee1148c299d8d5d7618af34e470.zip
New upstream version 0.17.0
Diffstat (limited to 'src/tile')
-rw-r--r--src/tile/bitstream/mode_info.cc382
-rw-r--r--src/tile/bitstream/palette.cc64
-rw-r--r--src/tile/bitstream/transform_size.cc12
-rw-r--r--src/tile/prediction.cc54
-rw-r--r--src/tile/tile.cc142
5 files changed, 415 insertions, 239 deletions
diff --git a/src/tile/bitstream/mode_info.cc b/src/tile/bitstream/mode_info.cc
index 0b22eb0..cb7b311 100644
--- a/src/tile/bitstream/mode_info.cc
+++ b/src/tile/bitstream/mode_info.cc
@@ -185,19 +185,22 @@ int GetReferenceContext(const Tile::Block& block,
} // namespace
bool Tile::ReadSegmentId(const Block& block) {
+ // These two asserts ensure that current_frame_.segmentation_map() is not
+ // nullptr.
+ assert(frame_header_.segmentation.enabled);
+ assert(frame_header_.segmentation.update_map);
+ const SegmentationMap& map = *current_frame_.segmentation_map();
int top_left = -1;
if (block.top_available[kPlaneY] && block.left_available[kPlaneY]) {
- top_left =
- block_parameters_holder_.Find(block.row4x4 - 1, block.column4x4 - 1)
- ->segment_id;
+ top_left = map.segment_id(block.row4x4 - 1, block.column4x4 - 1);
}
int top = -1;
if (block.top_available[kPlaneY]) {
- top = block.bp_top->segment_id;
+ top = map.segment_id(block.row4x4 - 1, block.column4x4);
}
int left = -1;
if (block.left_available[kPlaneY]) {
- left = block.bp_left->segment_id;
+ left = map.segment_id(block.row4x4, block.column4x4 - 1);
}
int pred;
if (top == -1) {
@@ -209,7 +212,7 @@ bool Tile::ReadSegmentId(const Block& block) {
}
BlockParameters& bp = *block.bp;
if (bp.skip) {
- bp.segment_id = pred;
+ bp.prediction_parameters->segment_id = pred;
return true;
}
int context = 0;
@@ -224,17 +227,18 @@ bool Tile::ReadSegmentId(const Block& block) {
symbol_decoder_context_.segment_id_cdf[context];
const int encoded_segment_id =
reader_.ReadSymbol<kMaxSegments>(segment_id_cdf);
- bp.segment_id =
+ bp.prediction_parameters->segment_id =
DecodeSegmentId(encoded_segment_id, pred,
frame_header_.segmentation.last_active_segment_id + 1);
// Check the bitstream conformance requirement in Section 6.10.8 of the spec.
- if (bp.segment_id < 0 ||
- bp.segment_id > frame_header_.segmentation.last_active_segment_id) {
+ if (bp.prediction_parameters->segment_id < 0 ||
+ bp.prediction_parameters->segment_id >
+ frame_header_.segmentation.last_active_segment_id) {
LIBGAV1_DLOG(
ERROR,
"Corrupted segment_ids: encoded %d, last active %d, postprocessed %d",
encoded_segment_id, frame_header_.segmentation.last_active_segment_id,
- bp.segment_id);
+ bp.prediction_parameters->segment_id);
return false;
}
return true;
@@ -243,7 +247,7 @@ bool Tile::ReadSegmentId(const Block& block) {
bool Tile::ReadIntraSegmentId(const Block& block) {
BlockParameters& bp = *block.bp;
if (!frame_header_.segmentation.enabled) {
- bp.segment_id = 0;
+ bp.prediction_parameters->segment_id = 0;
return true;
}
return ReadSegmentId(block);
@@ -252,8 +256,8 @@ bool Tile::ReadIntraSegmentId(const Block& block) {
void Tile::ReadSkip(const Block& block) {
BlockParameters& bp = *block.bp;
if (frame_header_.segmentation.segment_id_pre_skip &&
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureSkip)) {
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureSkip)) {
bp.skip = true;
return;
}
@@ -268,51 +272,53 @@ void Tile::ReadSkip(const Block& block) {
bp.skip = reader_.ReadSymbol(skip_cdf);
}
-void Tile::ReadSkipMode(const Block& block) {
+bool Tile::ReadSkipMode(const Block& block) {
BlockParameters& bp = *block.bp;
if (!frame_header_.skip_mode_present ||
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureSkip) ||
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureReferenceFrame) ||
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureGlobalMv) ||
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureSkip) ||
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id,
+ kSegmentFeatureReferenceFrame) ||
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureGlobalMv) ||
IsBlockDimension4(block.size)) {
- bp.skip_mode = false;
- return;
+ return false;
}
const int context =
(block.left_available[kPlaneY]
- ? static_cast<int>(block.bp_left->skip_mode)
+ ? static_cast<int>(left_context_.skip_mode[block.left_context_index])
: 0) +
- (block.top_available[kPlaneY] ? static_cast<int>(block.bp_top->skip_mode)
- : 0);
- bp.skip_mode =
- reader_.ReadSymbol(symbol_decoder_context_.skip_mode_cdf[context]);
+ (block.top_available[kPlaneY]
+ ? static_cast<int>(
+ block.top_context->skip_mode[block.top_context_index])
+ : 0);
+ return reader_.ReadSymbol(symbol_decoder_context_.skip_mode_cdf[context]);
}
void Tile::ReadCdef(const Block& block) {
BlockParameters& bp = *block.bp;
if (bp.skip || frame_header_.coded_lossless ||
- !sequence_header_.enable_cdef || frame_header_.allow_intrabc) {
+ !sequence_header_.enable_cdef || frame_header_.allow_intrabc ||
+ frame_header_.cdef.bits == 0) {
return;
}
- const int cdef_size4x4 = kNum4x4BlocksWide[kBlock64x64];
- const int cdef_mask4x4 = ~(cdef_size4x4 - 1);
- const int row4x4 = block.row4x4 & cdef_mask4x4;
- const int column4x4 = block.column4x4 & cdef_mask4x4;
- const int row = DivideBy16(row4x4);
- const int column = DivideBy16(column4x4);
- if (cdef_index_[row][column] == -1) {
- cdef_index_[row][column] =
- frame_header_.cdef.bits > 0
- ? static_cast<int16_t>(reader_.ReadLiteral(frame_header_.cdef.bits))
- : 0;
- for (int i = row4x4; i < row4x4 + block.height4x4; i += cdef_size4x4) {
- for (int j = column4x4; j < column4x4 + block.width4x4;
- j += cdef_size4x4) {
- cdef_index_[DivideBy16(i)][DivideBy16(j)] = cdef_index_[row][column];
- }
+ int8_t* const cdef_index =
+ &cdef_index_[DivideBy16(block.row4x4)][DivideBy16(block.column4x4)];
+ int stride = cdef_index_.columns();
+ if (cdef_index[0] == -1) {
+ cdef_index[0] =
+ static_cast<int8_t>(reader_.ReadLiteral(frame_header_.cdef.bits));
+ if (block.size == kBlock128x128) {
+ // This condition is shorthand for block.width4x4 > 16 && block.height4x4
+ // > 16.
+ cdef_index[1] = cdef_index[0];
+ cdef_index[stride] = cdef_index[0];
+ cdef_index[stride + 1] = cdef_index[0];
+ } else if (block.width4x4 > 16) {
+ cdef_index[1] = cdef_index[0];
+ } else if (block.height4x4 > 16) {
+ cdef_index[stride] = cdef_index[0];
}
}
}
@@ -328,7 +334,7 @@ int Tile::ReadAndClipDelta(uint16_t* const cdf, int delta_small, int scale,
abs = abs_remaining_bits + (1 << remaining_bit_count) + 1;
}
if (abs != 0) {
- const bool sign = static_cast<bool>(reader_.ReadBit());
+ const bool sign = reader_.ReadBit() != 0;
const int scaled_abs = abs << scale;
const int reduced_delta = sign ? -scaled_abs : scaled_abs;
value += reduced_delta;
@@ -404,8 +410,9 @@ void Tile::ReadIntraAngleInfo(const Block& block, PlaneType plane_type) {
PredictionParameters& prediction_parameters =
*block.bp->prediction_parameters;
prediction_parameters.angle_delta[plane_type] = 0;
- const PredictionMode mode =
- (plane_type == kPlaneTypeY) ? bp.y_mode : bp.uv_mode;
+ const PredictionMode mode = (plane_type == kPlaneTypeY)
+ ? bp.y_mode
+ : bp.prediction_parameters->uv_mode;
if (IsBlockSmallerThan8x8(block.size) || !IsDirectionalMode(mode)) return;
uint16_t* const cdf =
symbol_decoder_context_.angle_delta_cdf[mode - kPredictionModeVertical];
@@ -445,7 +452,8 @@ void Tile::ReadCflAlpha(const Block& block) {
void Tile::ReadPredictionModeUV(const Block& block) {
BlockParameters& bp = *block.bp;
bool chroma_from_luma_allowed;
- if (frame_header_.segmentation.lossless[bp.segment_id]) {
+ if (frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id]) {
chroma_from_luma_allowed = block.residual_size[kPlaneU] == kBlock4x4;
} else {
chroma_from_luma_allowed = IsBlockDimensionLessThan64(block.size);
@@ -454,10 +462,10 @@ void Tile::ReadPredictionModeUV(const Block& block) {
symbol_decoder_context_
.uv_mode_cdf[static_cast<int>(chroma_from_luma_allowed)][bp.y_mode];
if (chroma_from_luma_allowed) {
- bp.uv_mode = static_cast<PredictionMode>(
+ bp.prediction_parameters->uv_mode = static_cast<PredictionMode>(
reader_.ReadSymbol<kIntraPredictionModesUV>(cdf));
} else {
- bp.uv_mode = static_cast<PredictionMode>(
+ bp.prediction_parameters->uv_mode = static_cast<PredictionMode>(
reader_.ReadSymbol<kIntraPredictionModesUV - 1>(cdf));
}
}
@@ -528,7 +536,7 @@ void Tile::ReadFilterIntraModeInfo(const Block& block) {
*block.bp->prediction_parameters;
prediction_parameters.use_filter_intra = false;
if (!sequence_header_.enable_filter_intra || bp.y_mode != kPredictionModeDc ||
- bp.palette_mode_info.size[kPlaneTypeY] != 0 ||
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] != 0 ||
!IsBlockDimensionLessThan64(block.size)) {
return;
}
@@ -548,7 +556,7 @@ bool Tile::DecodeIntraModeInfo(const Block& block) {
!ReadIntraSegmentId(block)) {
return false;
}
- bp.skip_mode = false;
+ SetCdfContextSkipMode(block, false);
ReadSkip(block);
if (!frame_header_.segmentation.segment_id_pre_skip &&
!ReadIntraSegmentId(block)) {
@@ -572,12 +580,14 @@ bool Tile::DecodeIntraModeInfo(const Block& block) {
bp.reference_frame[0] = kReferenceFrameIntra;
bp.reference_frame[1] = kReferenceFrameNone;
bp.y_mode = kPredictionModeDc;
- bp.uv_mode = kPredictionModeDc;
+ bp.prediction_parameters->uv_mode = kPredictionModeDc;
+ SetCdfContextUVMode(block);
prediction_parameters.motion_mode = kMotionModeSimple;
prediction_parameters.compound_prediction_type =
kCompoundPredictionTypeAverage;
- bp.palette_mode_info.size[kPlaneTypeY] = 0;
- bp.palette_mode_info.size[kPlaneTypeUV] = 0;
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] = 0;
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeUV] = 0;
+ SetCdfContextPaletteSize(block);
bp.interpolation_filter[0] = kInterpolationFilterBilinear;
bp.interpolation_filter[1] = kInterpolationFilterBilinear;
MvContexts dummy_mode_contexts;
@@ -608,59 +618,73 @@ int8_t Tile::ComputePredictedSegmentId(const Block& block) const {
return id;
}
+void Tile::SetCdfContextUsePredictedSegmentId(const Block& block,
+ bool use_predicted_segment_id) {
+ memset(left_context_.use_predicted_segment_id + block.left_context_index,
+ static_cast<int>(use_predicted_segment_id), block.height4x4);
+ memset(block.top_context->use_predicted_segment_id + block.top_context_index,
+ static_cast<int>(use_predicted_segment_id), block.width4x4);
+}
+
bool Tile::ReadInterSegmentId(const Block& block, bool pre_skip) {
BlockParameters& bp = *block.bp;
if (!frame_header_.segmentation.enabled) {
- bp.segment_id = 0;
+ bp.prediction_parameters->segment_id = 0;
return true;
}
if (!frame_header_.segmentation.update_map) {
- bp.segment_id = ComputePredictedSegmentId(block);
+ bp.prediction_parameters->segment_id = ComputePredictedSegmentId(block);
return true;
}
if (pre_skip) {
if (!frame_header_.segmentation.segment_id_pre_skip) {
- bp.segment_id = 0;
+ bp.prediction_parameters->segment_id = 0;
return true;
}
} else if (bp.skip) {
- bp.use_predicted_segment_id = false;
+ SetCdfContextUsePredictedSegmentId(block, false);
return ReadSegmentId(block);
}
if (frame_header_.segmentation.temporal_update) {
const int context =
(block.left_available[kPlaneY]
- ? static_cast<int>(block.bp_left->use_predicted_segment_id)
+ ? static_cast<int>(
+ left_context_
+ .use_predicted_segment_id[block.left_context_index])
: 0) +
(block.top_available[kPlaneY]
- ? static_cast<int>(block.bp_top->use_predicted_segment_id)
+ ? static_cast<int>(
+ block.top_context
+ ->use_predicted_segment_id[block.top_context_index])
: 0);
- bp.use_predicted_segment_id = reader_.ReadSymbol(
+ const bool use_predicted_segment_id = reader_.ReadSymbol(
symbol_decoder_context_.use_predicted_segment_id_cdf[context]);
- if (bp.use_predicted_segment_id) {
- bp.segment_id = ComputePredictedSegmentId(block);
+ SetCdfContextUsePredictedSegmentId(block, use_predicted_segment_id);
+ if (use_predicted_segment_id) {
+ bp.prediction_parameters->segment_id = ComputePredictedSegmentId(block);
return true;
}
}
return ReadSegmentId(block);
}
-void Tile::ReadIsInter(const Block& block) {
+void Tile::ReadIsInter(const Block& block, bool skip_mode) {
BlockParameters& bp = *block.bp;
- if (bp.skip_mode) {
+ if (skip_mode) {
bp.is_inter = true;
return;
}
- if (frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureReferenceFrame)) {
- bp.is_inter =
- frame_header_.segmentation
- .feature_data[bp.segment_id][kSegmentFeatureReferenceFrame] !=
- kReferenceFrameIntra;
+ if (frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id,
+ kSegmentFeatureReferenceFrame)) {
+ bp.is_inter = frame_header_.segmentation
+ .feature_data[bp.prediction_parameters->segment_id]
+ [kSegmentFeatureReferenceFrame] !=
+ kReferenceFrameIntra;
return;
}
- if (frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureGlobalMv)) {
+ if (frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureGlobalMv)) {
bp.is_inter = true;
return;
}
@@ -678,6 +702,49 @@ void Tile::ReadIsInter(const Block& block) {
reader_.ReadSymbol(symbol_decoder_context_.is_inter_cdf[context]);
}
+void Tile::SetCdfContextPaletteSize(const Block& block) {
+ const PaletteModeInfo& palette_mode_info =
+ block.bp->prediction_parameters->palette_mode_info;
+ for (int plane_type = kPlaneTypeY; plane_type <= kPlaneTypeUV; ++plane_type) {
+ memset(left_context_.palette_size[plane_type] + block.left_context_index,
+ palette_mode_info.size[plane_type], block.height4x4);
+ memset(
+ block.top_context->palette_size[plane_type] + block.top_context_index,
+ palette_mode_info.size[plane_type], block.width4x4);
+ if (palette_mode_info.size[plane_type] == 0) continue;
+ for (int i = block.left_context_index;
+ i < block.left_context_index + block.height4x4; ++i) {
+ memcpy(left_context_.palette_color[i][plane_type],
+ palette_mode_info.color[plane_type],
+ kMaxPaletteSize * sizeof(palette_mode_info.color[0][0]));
+ }
+ for (int i = block.top_context_index;
+ i < block.top_context_index + block.width4x4; ++i) {
+ memcpy(block.top_context->palette_color[i][plane_type],
+ palette_mode_info.color[plane_type],
+ kMaxPaletteSize * sizeof(palette_mode_info.color[0][0]));
+ }
+ }
+}
+
+void Tile::SetCdfContextUVMode(const Block& block) {
+ // BlockCdfContext.uv_mode is only used to compute is_smooth_prediction for
+ // the intra edge upsamplers in the subsequent blocks. They have some special
+ // rules for subsampled UV planes. For subsampled UV planes, update left
+ // context only if current block contains the last odd column and update top
+ // context only if current block contains the last odd row.
+ if (subsampling_x_[kPlaneU] == 0 || (block.column4x4 & 1) == 1 ||
+ block.width4x4 > 1) {
+ memset(left_context_.uv_mode + block.left_context_index,
+ block.bp->prediction_parameters->uv_mode, block.height4x4);
+ }
+ if (subsampling_y_[kPlaneU] == 0 || (block.row4x4 & 1) == 1 ||
+ block.height4x4 > 1) {
+ memset(block.top_context->uv_mode + block.top_context_index,
+ block.bp->prediction_parameters->uv_mode, block.width4x4);
+ }
+}
+
bool Tile::ReadIntraBlockModeInfo(const Block& block, bool intra_y_mode) {
BlockParameters& bp = *block.bp;
bp.reference_frame[0] = kReferenceFrameIntra;
@@ -686,12 +753,39 @@ bool Tile::ReadIntraBlockModeInfo(const Block& block, bool intra_y_mode) {
ReadIntraAngleInfo(block, kPlaneTypeY);
if (block.HasChroma()) {
ReadPredictionModeUV(block);
- if (bp.uv_mode == kPredictionModeChromaFromLuma) {
+ if (bp.prediction_parameters->uv_mode == kPredictionModeChromaFromLuma) {
ReadCflAlpha(block);
}
+ if (block.left_available[kPlaneU]) {
+ const int smooth_row =
+ block.row4x4 + (~block.row4x4 & subsampling_y_[kPlaneU]);
+ const int smooth_column =
+ block.column4x4 - 1 - (block.column4x4 & subsampling_x_[kPlaneU]);
+ const BlockParameters& bp_left =
+ *block_parameters_holder_.Find(smooth_row, smooth_column);
+ bp.prediction_parameters->chroma_left_uses_smooth_prediction =
+ (bp_left.reference_frame[0] <= kReferenceFrameIntra) &&
+ kPredictionModeSmoothMask.Contains(
+ left_context_.uv_mode[CdfContextIndex(smooth_row)]);
+ }
+ if (block.top_available[kPlaneU]) {
+ const int smooth_row =
+ block.row4x4 - 1 - (block.row4x4 & subsampling_y_[kPlaneU]);
+ const int smooth_column =
+ block.column4x4 + (~block.column4x4 & subsampling_x_[kPlaneU]);
+ const BlockParameters& bp_top =
+ *block_parameters_holder_.Find(smooth_row, smooth_column);
+ bp.prediction_parameters->chroma_top_uses_smooth_prediction =
+ (bp_top.reference_frame[0] <= kReferenceFrameIntra) &&
+ kPredictionModeSmoothMask.Contains(
+ top_context_.get()[SuperBlockColumnIndex(smooth_column)]
+ .uv_mode[CdfContextIndex(smooth_column)]);
+ }
+ SetCdfContextUVMode(block);
ReadIntraAngleInfo(block, kPlaneTypeUV);
}
ReadPaletteModeInfo(block);
+ SetCdfContextPaletteSize(block);
ReadFilterIntraModeInfo(block);
return true;
}
@@ -808,25 +902,27 @@ uint16_t* Tile::GetReferenceCdf(
return symbol_decoder_context_.compound_reference_cdf[type][context][index];
}
-void Tile::ReadReferenceFrames(const Block& block) {
+void Tile::ReadReferenceFrames(const Block& block, bool skip_mode) {
BlockParameters& bp = *block.bp;
- if (bp.skip_mode) {
+ if (skip_mode) {
bp.reference_frame[0] = frame_header_.skip_mode_frame[0];
bp.reference_frame[1] = frame_header_.skip_mode_frame[1];
return;
}
- if (frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureReferenceFrame)) {
+ if (frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id,
+ kSegmentFeatureReferenceFrame)) {
bp.reference_frame[0] = static_cast<ReferenceFrameType>(
frame_header_.segmentation
- .feature_data[bp.segment_id][kSegmentFeatureReferenceFrame]);
+ .feature_data[bp.prediction_parameters->segment_id]
+ [kSegmentFeatureReferenceFrame]);
bp.reference_frame[1] = kReferenceFrameNone;
return;
}
- if (frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureSkip) ||
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureGlobalMv)) {
+ if (frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureSkip) ||
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureGlobalMv)) {
bp.reference_frame[0] = kReferenceFrameLast;
bp.reference_frame[1] = kReferenceFrameNone;
return;
@@ -927,16 +1023,17 @@ void Tile::ReadReferenceFrames(const Block& block) {
}
void Tile::ReadInterPredictionModeY(const Block& block,
- const MvContexts& mode_contexts) {
+ const MvContexts& mode_contexts,
+ bool skip_mode) {
BlockParameters& bp = *block.bp;
- if (bp.skip_mode) {
+ if (skip_mode) {
bp.y_mode = kPredictionModeNearestNearestMv;
return;
}
- if (frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureSkip) ||
- frame_header_.segmentation.FeatureActive(bp.segment_id,
- kSegmentFeatureGlobalMv)) {
+ if (frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureSkip) ||
+ frame_header_.segmentation.FeatureActive(
+ bp.prediction_parameters->segment_id, kSegmentFeatureGlobalMv)) {
bp.y_mode = kPredictionModeGlobalMv;
return;
}
@@ -995,13 +1092,14 @@ void Tile::ReadRefMvIndex(const Block& block) {
}
}
-void Tile::ReadInterIntraMode(const Block& block, bool is_compound) {
+void Tile::ReadInterIntraMode(const Block& block, bool is_compound,
+ bool skip_mode) {
BlockParameters& bp = *block.bp;
PredictionParameters& prediction_parameters =
*block.bp->prediction_parameters;
prediction_parameters.inter_intra_mode = kNumInterIntraModes;
prediction_parameters.is_wedge_inter_intra = false;
- if (bp.skip_mode || !sequence_header_.enable_interintra_compound ||
+ if (skip_mode || !sequence_header_.enable_interintra_compound ||
is_compound || !kIsInterIntraModeAllowedMask.Contains(block.size)) {
return;
}
@@ -1031,13 +1129,14 @@ void Tile::ReadInterIntraMode(const Block& block, bool is_compound) {
prediction_parameters.wedge_sign = 0;
}
-void Tile::ReadMotionMode(const Block& block, bool is_compound) {
+void Tile::ReadMotionMode(const Block& block, bool is_compound,
+ bool skip_mode) {
BlockParameters& bp = *block.bp;
PredictionParameters& prediction_parameters =
*block.bp->prediction_parameters;
const auto global_motion_type =
frame_header_.global_motion[bp.reference_frame[0]].type;
- if (bp.skip_mode || !frame_header_.is_motion_mode_switchable ||
+ if (skip_mode || !frame_header_.is_motion_mode_switchable ||
IsBlockDimension4(block.size) ||
(frame_header_.force_integer_mv == 0 &&
(bp.y_mode == kPredictionModeGlobalMv ||
@@ -1073,14 +1172,17 @@ uint16_t* Tile::GetIsExplicitCompoundTypeCdf(const Block& block) {
int context = 0;
if (block.top_available[kPlaneY]) {
if (!block.IsTopSingle()) {
- context += static_cast<int>(block.bp_top->is_explicit_compound_type);
+ context += static_cast<int>(
+ block.top_context
+ ->is_explicit_compound_type[block.top_context_index]);
} else if (block.TopReference(0) == kReferenceFrameAlternate) {
context += 3;
}
}
if (block.left_available[kPlaneY]) {
if (!block.IsLeftSingle()) {
- context += static_cast<int>(block.bp_left->is_explicit_compound_type);
+ context += static_cast<int>(
+ left_context_.is_explicit_compound_type[block.left_context_index]);
} else if (block.LeftReference(0) == kReferenceFrameAlternate) {
context += 3;
}
@@ -1099,14 +1201,16 @@ uint16_t* Tile::GetIsCompoundTypeAverageCdf(const Block& block) {
int context = (forward == backward) ? 3 : 0;
if (block.top_available[kPlaneY]) {
if (!block.IsTopSingle()) {
- context += static_cast<int>(block.bp_top->is_compound_type_average);
+ context += static_cast<int>(
+ block.top_context->is_compound_type_average[block.top_context_index]);
} else if (block.TopReference(0) == kReferenceFrameAlternate) {
++context;
}
}
if (block.left_available[kPlaneY]) {
if (!block.IsLeftSingle()) {
- context += static_cast<int>(block.bp_left->is_compound_type_average);
+ context += static_cast<int>(
+ left_context_.is_compound_type_average[block.left_context_index]);
} else if (block.LeftReference(0) == kReferenceFrameAlternate) {
++context;
}
@@ -1114,23 +1218,25 @@ uint16_t* Tile::GetIsCompoundTypeAverageCdf(const Block& block) {
return symbol_decoder_context_.is_compound_type_average_cdf[context];
}
-void Tile::ReadCompoundType(const Block& block, bool is_compound) {
- BlockParameters& bp = *block.bp;
- bp.is_explicit_compound_type = false;
- bp.is_compound_type_average = true;
+void Tile::ReadCompoundType(const Block& block, bool is_compound,
+ bool skip_mode,
+ bool* const is_explicit_compound_type,
+ bool* const is_compound_type_average) {
+ *is_explicit_compound_type = false;
+ *is_compound_type_average = true;
PredictionParameters& prediction_parameters =
*block.bp->prediction_parameters;
- if (bp.skip_mode) {
+ if (skip_mode) {
prediction_parameters.compound_prediction_type =
kCompoundPredictionTypeAverage;
return;
}
if (is_compound) {
if (sequence_header_.enable_masked_compound) {
- bp.is_explicit_compound_type =
+ *is_explicit_compound_type =
reader_.ReadSymbol(GetIsExplicitCompoundTypeCdf(block));
}
- if (bp.is_explicit_compound_type) {
+ if (*is_explicit_compound_type) {
if (kIsWedgeCompoundModeAllowed.Contains(block.size)) {
// Only kCompoundPredictionTypeWedge and
// kCompoundPredictionTypeDiffWeighted are signaled explicitly.
@@ -1143,11 +1249,11 @@ void Tile::ReadCompoundType(const Block& block, bool is_compound) {
}
} else {
if (sequence_header_.enable_jnt_comp) {
- bp.is_compound_type_average =
+ *is_compound_type_average =
reader_.ReadSymbol(GetIsCompoundTypeAverageCdf(block));
prediction_parameters.compound_prediction_type =
- bp.is_compound_type_average ? kCompoundPredictionTypeAverage
- : kCompoundPredictionTypeDistance;
+ *is_compound_type_average ? kCompoundPredictionTypeAverage
+ : kCompoundPredictionTypeDistance;
} else {
prediction_parameters.compound_prediction_type =
kCompoundPredictionTypeAverage;
@@ -1162,8 +1268,7 @@ void Tile::ReadCompoundType(const Block& block, bool is_compound) {
prediction_parameters.wedge_sign = static_cast<int>(reader_.ReadBit());
} else if (prediction_parameters.compound_prediction_type ==
kCompoundPredictionTypeDiffWeighted) {
- prediction_parameters.mask_is_inverse =
- static_cast<bool>(reader_.ReadBit());
+ prediction_parameters.mask_is_inverse = reader_.ReadBit() != 0;
}
return;
}
@@ -1209,7 +1314,7 @@ uint16_t* Tile::GetInterpolationFilterCdf(const Block& block, int direction) {
return symbol_decoder_context_.interpolation_filter_cdf[context];
}
-void Tile::ReadInterpolationFilter(const Block& block) {
+void Tile::ReadInterpolationFilter(const Block& block, bool skip_mode) {
BlockParameters& bp = *block.bp;
if (frame_header_.interpolation_filter != kInterpolationFilterSwitchable) {
static_assert(
@@ -1222,7 +1327,7 @@ void Tile::ReadInterpolationFilter(const Block& block) {
return;
}
bool interpolation_filter_present = true;
- if (bp.skip_mode ||
+ if (skip_mode ||
block.bp->prediction_parameters->motion_mode == kMotionModeLocalWarp) {
interpolation_filter_present = false;
} else if (!IsBlockDimension4(block.size) &&
@@ -1251,31 +1356,58 @@ void Tile::ReadInterpolationFilter(const Block& block) {
}
}
-bool Tile::ReadInterBlockModeInfo(const Block& block) {
+void Tile::SetCdfContextCompoundType(const Block& block,
+ bool is_explicit_compound_type,
+ bool is_compound_type_average) {
+ memset(left_context_.is_explicit_compound_type + block.left_context_index,
+ static_cast<int>(is_explicit_compound_type), block.height4x4);
+ memset(left_context_.is_compound_type_average + block.left_context_index,
+ static_cast<int>(is_compound_type_average), block.height4x4);
+ memset(block.top_context->is_explicit_compound_type + block.top_context_index,
+ static_cast<int>(is_explicit_compound_type), block.width4x4);
+ memset(block.top_context->is_compound_type_average + block.top_context_index,
+ static_cast<int>(is_compound_type_average), block.width4x4);
+}
+
+bool Tile::ReadInterBlockModeInfo(const Block& block, bool skip_mode) {
BlockParameters& bp = *block.bp;
- bp.palette_mode_info.size[kPlaneTypeY] = 0;
- bp.palette_mode_info.size[kPlaneTypeUV] = 0;
- ReadReferenceFrames(block);
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] = 0;
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeUV] = 0;
+ SetCdfContextPaletteSize(block);
+ ReadReferenceFrames(block, skip_mode);
const bool is_compound = bp.reference_frame[1] > kReferenceFrameIntra;
MvContexts mode_contexts;
FindMvStack(block, is_compound, &mode_contexts);
- ReadInterPredictionModeY(block, mode_contexts);
+ ReadInterPredictionModeY(block, mode_contexts, skip_mode);
ReadRefMvIndex(block);
if (!AssignInterMv(block, is_compound)) return false;
- ReadInterIntraMode(block, is_compound);
- ReadMotionMode(block, is_compound);
- ReadCompoundType(block, is_compound);
- ReadInterpolationFilter(block);
+ ReadInterIntraMode(block, is_compound, skip_mode);
+ ReadMotionMode(block, is_compound, skip_mode);
+ bool is_explicit_compound_type;
+ bool is_compound_type_average;
+ ReadCompoundType(block, is_compound, skip_mode, &is_explicit_compound_type,
+ &is_compound_type_average);
+ SetCdfContextCompoundType(block, is_explicit_compound_type,
+ is_compound_type_average);
+ ReadInterpolationFilter(block, skip_mode);
return true;
}
+void Tile::SetCdfContextSkipMode(const Block& block, bool skip_mode) {
+ memset(left_context_.skip_mode + block.left_context_index,
+ static_cast<int>(skip_mode), block.height4x4);
+ memset(block.top_context->skip_mode + block.top_context_index,
+ static_cast<int>(skip_mode), block.width4x4);
+}
+
bool Tile::DecodeInterModeInfo(const Block& block) {
BlockParameters& bp = *block.bp;
block.bp->prediction_parameters->use_intra_block_copy = false;
bp.skip = false;
if (!ReadInterSegmentId(block, /*pre_skip=*/true)) return false;
- ReadSkipMode(block);
- if (bp.skip_mode) {
+ bool skip_mode = ReadSkipMode(block);
+ SetCdfContextSkipMode(block, skip_mode);
+ if (skip_mode) {
bp.skip = true;
} else {
ReadSkip(block);
@@ -1290,8 +1422,8 @@ bool Tile::DecodeInterModeInfo(const Block& block) {
ReadLoopFilterDelta(block);
read_deltas_ = false;
}
- ReadIsInter(block);
- return bp.is_inter ? ReadInterBlockModeInfo(block)
+ ReadIsInter(block, skip_mode);
+ return bp.is_inter ? ReadInterBlockModeInfo(block, skip_mode)
: ReadIntraBlockModeInfo(block, /*intra_y_mode=*/false);
}
diff --git a/src/tile/bitstream/palette.cc b/src/tile/bitstream/palette.cc
index 41b42d6..27e5110 100644
--- a/src/tile/bitstream/palette.cc
+++ b/src/tile/bitstream/palette.cc
@@ -35,20 +35,23 @@ int Tile::GetPaletteCache(const Block& block, PlaneType plane_type,
uint16_t* const cache) {
const int top_size =
(block.top_available[kPlaneY] && Mod64(MultiplyBy4(block.row4x4)) != 0)
- ? block.bp_top->palette_mode_info.size[plane_type]
+ ? block.top_context->palette_size[plane_type][block.top_context_index]
+ : 0;
+ const int left_size =
+ block.left_available[kPlaneY]
+ ? left_context_.palette_size[plane_type][block.left_context_index]
: 0;
- const int left_size = block.left_available[kPlaneY]
- ? block.bp_left->palette_mode_info.size[plane_type]
- : 0;
if (left_size == 0 && top_size == 0) return 0;
// Merge the left and top colors in sorted order and store them in |cache|.
- uint16_t dummy[1];
- const uint16_t* top = (top_size > 0)
- ? block.bp_top->palette_mode_info.color[plane_type]
- : dummy;
+ uint16_t empty_palette[1];
+ const uint16_t* top =
+ (top_size > 0) ? block.top_context
+ ->palette_color[block.top_context_index][plane_type]
+ : empty_palette;
const uint16_t* left =
- (left_size > 0) ? block.bp_left->palette_mode_info.color[plane_type]
- : dummy;
+ (left_size > 0)
+ ? left_context_.palette_color[block.left_context_index][plane_type]
+ : empty_palette;
std::merge(top, top + top_size, left, left + left_size, cache);
// Deduplicate the entries in |cache| and return the number of unique
// entries.
@@ -61,8 +64,10 @@ void Tile::ReadPaletteColors(const Block& block, Plane plane) {
uint16_t cache[2 * kMaxPaletteSize];
const int n = GetPaletteCache(block, plane_type, cache);
BlockParameters& bp = *block.bp;
- const uint8_t palette_size = bp.palette_mode_info.size[plane_type];
- uint16_t* const palette_color = bp.palette_mode_info.color[plane];
+ const uint8_t palette_size =
+ bp.prediction_parameters->palette_mode_info.size[plane_type];
+ uint16_t* const palette_color =
+ bp.prediction_parameters->palette_mode_info.color[plane];
const int8_t bitdepth = sequence_header_.color_config.bitdepth;
int index = 0;
for (int i = 0; i < n && index < palette_size; ++i) {
@@ -101,7 +106,8 @@ void Tile::ReadPaletteColors(const Block& block, Plane plane) {
std::inplace_merge(palette_color, palette_color + merge_pivot,
palette_color + palette_size);
if (plane_type == kPlaneTypeUV) {
- uint16_t* const palette_color_v = bp.palette_mode_info.color[kPlaneV];
+ uint16_t* const palette_color_v =
+ bp.prediction_parameters->palette_mode_info.color[kPlaneV];
if (reader_.ReadBit() != 0) { // delta_encode_palette_colors_v.
const int bits = bitdepth - 4 + static_cast<int>(reader_.ReadLiteral(2));
palette_color_v[0] = reader_.ReadLiteral(bitdepth);
@@ -130,8 +136,8 @@ void Tile::ReadPaletteColors(const Block& block, Plane plane) {
void Tile::ReadPaletteModeInfo(const Block& block) {
BlockParameters& bp = *block.bp;
- bp.palette_mode_info.size[kPlaneTypeY] = 0;
- bp.palette_mode_info.size[kPlaneTypeUV] = 0;
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] = 0;
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeUV] = 0;
if (IsBlockSmallerThan8x8(block.size) || block.size > kBlock64x64 ||
!frame_header_.allow_screen_content_tools) {
return;
@@ -140,29 +146,32 @@ void Tile::ReadPaletteModeInfo(const Block& block) {
k4x4WidthLog2[block.size] + k4x4HeightLog2[block.size] - 2;
if (bp.y_mode == kPredictionModeDc) {
const int context =
- static_cast<int>(block.top_available[kPlaneY] &&
- block.bp_top->palette_mode_info.size[kPlaneTypeY] >
- 0) +
- static_cast<int>(block.left_available[kPlaneY] &&
- block.bp_left->palette_mode_info.size[kPlaneTypeY] >
- 0);
+ static_cast<int>(
+ block.top_available[kPlaneY] &&
+ block.top_context
+ ->palette_size[kPlaneTypeY][block.top_context_index] > 0) +
+ static_cast<int>(
+ block.left_available[kPlaneY] &&
+ left_context_.palette_size[kPlaneTypeY][block.left_context_index] >
+ 0);
const bool has_palette_y = reader_.ReadSymbol(
symbol_decoder_context_.has_palette_y_cdf[block_size_context][context]);
if (has_palette_y) {
- bp.palette_mode_info.size[kPlaneTypeY] =
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] =
kMinPaletteSize +
reader_.ReadSymbol<kPaletteSizeSymbolCount>(
symbol_decoder_context_.palette_y_size_cdf[block_size_context]);
ReadPaletteColors(block, kPlaneY);
}
}
- if (block.HasChroma() && bp.uv_mode == kPredictionModeDc) {
- const int context =
- static_cast<int>(bp.palette_mode_info.size[kPlaneTypeY] > 0);
+ if (block.HasChroma() &&
+ bp.prediction_parameters->uv_mode == kPredictionModeDc) {
+ const int context = static_cast<int>(
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeY] > 0);
const bool has_palette_uv =
reader_.ReadSymbol(symbol_decoder_context_.has_palette_uv_cdf[context]);
if (has_palette_uv) {
- bp.palette_mode_info.size[kPlaneTypeUV] =
+ bp.prediction_parameters->palette_mode_info.size[kPlaneTypeUV] =
kMinPaletteSize +
reader_.ReadSymbol<kPaletteSizeSymbolCount>(
symbol_decoder_context_.palette_uv_size_cdf[block_size_context]);
@@ -244,7 +253,8 @@ void Tile::PopulatePaletteColorContexts(
}
bool Tile::ReadPaletteTokens(const Block& block) {
- const PaletteModeInfo& palette_mode_info = block.bp->palette_mode_info;
+ const PaletteModeInfo& palette_mode_info =
+ block.bp->prediction_parameters->palette_mode_info;
PredictionParameters& prediction_parameters =
*block.bp->prediction_parameters;
for (int plane_type = kPlaneTypeY;
diff --git a/src/tile/bitstream/transform_size.cc b/src/tile/bitstream/transform_size.cc
index b79851d..7197400 100644
--- a/src/tile/bitstream/transform_size.cc
+++ b/src/tile/bitstream/transform_size.cc
@@ -95,7 +95,8 @@ int Tile::GetLeftTransformHeight(const Block& block, int row4x4, int column4x4,
TransformSize Tile::ReadFixedTransformSize(const Block& block) {
BlockParameters& bp = *block.bp;
- if (frame_header_.segmentation.lossless[bp.segment_id]) {
+ if (frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id]) {
return kTransformSize4x4;
}
const TransformSize max_rect_tx_size = kMaxTransformSizeRectangle[block.size];
@@ -189,8 +190,6 @@ void Tile::ReadVariableTransformTree(const Block& block, int row4x4,
memset(&inter_transform_sizes_[node.y + i][node.x], node.tx_size,
tx_width4x4);
}
- block_parameters_holder_.Find(node.y, node.x)->transform_size =
- node.tx_size;
} while (!stack.Empty());
}
@@ -198,7 +197,8 @@ void Tile::DecodeTransformSize(const Block& block) {
BlockParameters& bp = *block.bp;
if (frame_header_.tx_mode == kTxModeSelect && block.size > kBlock4x4 &&
bp.is_inter && !bp.skip &&
- !frame_header_.segmentation.lossless[bp.segment_id]) {
+ !frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id]) {
const TransformSize max_tx_size = kMaxTransformSizeRectangle[block.size];
const int tx_width4x4 = kTransformWidth4x4[max_tx_size];
const int tx_height4x4 = kTransformHeight4x4[max_tx_size];
@@ -210,10 +210,10 @@ void Tile::DecodeTransformSize(const Block& block) {
}
}
} else {
- bp.transform_size = ReadFixedTransformSize(block);
+ const TransformSize transform_size = ReadFixedTransformSize(block);
for (int row = block.row4x4; row < block.row4x4 + block.height4x4; ++row) {
static_assert(sizeof(TransformSize) == 1, "");
- memset(&inter_transform_sizes_[row][block.column4x4], bp.transform_size,
+ memset(&inter_transform_sizes_[row][block.column4x4], transform_size,
block.width4x4);
}
}
diff --git a/src/tile/prediction.cc b/src/tile/prediction.cc
index c5560a6..bba5a69 100644
--- a/src/tile/prediction.cc
+++ b/src/tile/prediction.cc
@@ -226,8 +226,8 @@ void Tile::IntraPrediction(const Block& block, Plane plane, int x, int y,
bool has_left, bool has_top, bool has_top_right,
bool has_bottom_left, PredictionMode mode,
TransformSize tx_size) {
- const int width = 1 << kTransformWidthLog2[tx_size];
- const int height = 1 << kTransformHeightLog2[tx_size];
+ const int width = kTransformWidth[tx_size];
+ const int height = kTransformHeight[tx_size];
const int x_shift = subsampling_x_[plane];
const int y_shift = subsampling_y_[plane];
const int max_x = (MultiplyBy4(frame_header_.columns4x4) >> x_shift) - 1;
@@ -386,36 +386,21 @@ template void Tile::IntraPrediction<uint16_t>(const Block& block, Plane plane,
TransformSize tx_size);
#endif
-constexpr BitMaskSet kPredictionModeSmoothMask(kPredictionModeSmooth,
- kPredictionModeSmoothHorizontal,
- kPredictionModeSmoothVertical);
-
-bool Tile::IsSmoothPrediction(int row, int column, Plane plane) const {
- const BlockParameters& bp = *block_parameters_holder_.Find(row, column);
- PredictionMode mode;
+int Tile::GetIntraEdgeFilterType(const Block& block, Plane plane) const {
+ bool top;
+ bool left;
if (plane == kPlaneY) {
- mode = bp.y_mode;
+ top = block.top_available[kPlaneY] &&
+ kPredictionModeSmoothMask.Contains(block.bp_top->y_mode);
+ left = block.left_available[kPlaneY] &&
+ kPredictionModeSmoothMask.Contains(block.bp_left->y_mode);
} else {
- if (bp.reference_frame[0] > kReferenceFrameIntra) return false;
- mode = bp.uv_mode;
- }
- return kPredictionModeSmoothMask.Contains(mode);
-}
-
-int Tile::GetIntraEdgeFilterType(const Block& block, Plane plane) const {
- const int subsampling_x = subsampling_x_[plane];
- const int subsampling_y = subsampling_y_[plane];
- if (block.top_available[plane]) {
- const int row = block.row4x4 - 1 - (block.row4x4 & subsampling_y);
- const int column = block.column4x4 + (~block.column4x4 & subsampling_x);
- if (IsSmoothPrediction(row, column, plane)) return 1;
+ top = block.top_available[plane] &&
+ block.bp->prediction_parameters->chroma_top_uses_smooth_prediction;
+ left = block.left_available[plane] &&
+ block.bp->prediction_parameters->chroma_left_uses_smooth_prediction;
}
- if (block.left_available[plane]) {
- const int row = block.row4x4 + (~block.row4x4 & subsampling_y);
- const int column = block.column4x4 - 1 - (block.column4x4 & subsampling_x);
- if (IsSmoothPrediction(row, column, plane)) return 1;
- }
- return 0;
+ return static_cast<int>(top || left);
}
template <typename Pixel>
@@ -510,7 +495,8 @@ void Tile::PalettePrediction(const Block& block, const Plane plane,
const int y, const TransformSize tx_size) {
const int tx_width = kTransformWidth[tx_size];
const int tx_height = kTransformHeight[tx_size];
- const uint16_t* const palette = block.bp->palette_mode_info.color[plane];
+ const uint16_t* const palette =
+ block.bp->prediction_parameters->palette_mode_info.color[plane];
const PlaneType plane_type = GetPlaneType(plane);
const int x4 = MultiplyBy4(x);
const int y4 = MultiplyBy4(y);
@@ -695,7 +681,7 @@ GlobalMotion* Tile::GetWarpParams(
? global_motion_params->type
: kNumGlobalMotionTransformationTypes;
const bool is_global_valid =
- IsGlobalMvBlock(block.bp->is_global_mv_block, global_motion_type) &&
+ IsGlobalMvBlock(*block.bp, global_motion_type) &&
SetupShear(global_motion_params);
// Valid global motion type implies reference type can't be intra.
assert(!is_global_valid || reference_type != kReferenceFrameIntra);
@@ -1028,6 +1014,7 @@ bool Tile::GetReferenceBlockPosition(
(((height - 1) * step_y + (1 << kScaleSubPixelBits) - 1) >>
kScaleSubPixelBits) +
kSubPixelTaps;
+ *ref_block_end_x += kConvolveScaleBorderRight - kConvolveBorderRight;
ref_block_end_y = *ref_block_start_y + block_height - 1;
}
// Determines if we need to extend beyond the left/right/top/bottom border.
@@ -1206,11 +1193,12 @@ bool Tile::BlockInterPrediction(
(ref_block_start_x + kConvolveBorderLeftTop) * pixel_size;
}
} else {
+ const int border_right =
+ is_scaled ? kConvolveScaleBorderRight : kConvolveBorderRight;
// The block width can be at most 2 times as much as current
// block's width because of scaling.
auto block_extended_width = Align<ptrdiff_t>(
- (2 * width + kConvolveBorderLeftTop + kConvolveBorderRight) *
- pixel_size,
+ (2 * width + kConvolveBorderLeftTop + border_right) * pixel_size,
kMaxAlignment);
convolve_buffer_stride = block.scratch_buffer->convolve_block_buffer_stride;
#if LIBGAV1_MAX_BITDEPTH >= 10
diff --git a/src/tile/tile.cc b/src/tile/tile.cc
index 9699517..5070bb6 100644
--- a/src/tile/tile.cc
+++ b/src/tile/tile.cc
@@ -463,6 +463,7 @@ Tile::Tile(int tile_number, const uint8_t* const data, size_t size,
: 1),
current_frame_(*current_frame),
cdef_index_(frame_scratch_buffer->cdef_index),
+ cdef_skip_(frame_scratch_buffer->cdef_skip),
inter_transform_sizes_(frame_scratch_buffer->inter_transform_sizes),
thread_pool_(thread_pool),
residual_buffer_pool_(frame_scratch_buffer->residual_buffer_pool.get()),
@@ -541,16 +542,6 @@ Tile::Tile(int tile_number, const uint8_t* const data, size_t size,
buffer_[plane].Reset(Align(buffer.height(plane), max_tx_length),
buffer.stride(plane),
post_filter_.GetUnfilteredBuffer(plane));
- const int plane_height =
- SubsampledValue(frame_header_.height, subsampling_y_[plane]);
- deblock_row_limit_[plane] =
- std::min(frame_header_.rows4x4, DivideBy4(plane_height + 3)
- << subsampling_y_[plane]);
- const int plane_width =
- SubsampledValue(frame_header_.width, subsampling_x_[plane]);
- deblock_column_limit_[plane] =
- std::min(frame_header_.columns4x4, DivideBy4(plane_width + 3)
- << subsampling_x_[plane]);
}
}
@@ -598,6 +589,10 @@ bool Tile::Init() {
column4x4_end_, &motion_field_);
}
ResetLoopRestorationParams();
+ if (!top_context_.Resize(superblock_columns_)) {
+ LIBGAV1_DLOG(ERROR, "Allocation of top_context_ failed.");
+ return false;
+ }
return true;
}
@@ -1019,7 +1014,8 @@ TransformType Tile::ComputeTransformType(const Block& block, Plane plane,
int block_y) {
const BlockParameters& bp = *block.bp;
const TransformSize tx_size_square_max = kTransformSizeSquareMax[tx_size];
- if (frame_header_.segmentation.lossless[bp.segment_id] ||
+ if (frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id] ||
tx_size_square_max == kTransformSize64x64) {
return kTransformTypeDctDct;
}
@@ -1034,7 +1030,7 @@ TransformType Tile::ComputeTransformType(const Block& block, Plane plane,
const int y4 = std::max(block.row4x4, block_y << subsampling_y_[kPlaneU]);
tx_type = transform_types_[y4 - block.row4x4][x4 - block.column4x4];
} else {
- tx_type = kModeToTransformType[bp.uv_mode];
+ tx_type = kModeToTransformType[bp.prediction_parameters->uv_mode];
}
return kTransformTypeInSetMask[tx_set].Contains(tx_type)
? tx_type
@@ -1048,7 +1044,8 @@ void Tile::ReadTransformType(const Block& block, int x4, int y4,
TransformType tx_type = kTransformTypeDctDct;
if (tx_set != kTransformSetDctOnly &&
- frame_header_.segmentation.qindex[bp.segment_id] > 0) {
+ frame_header_.segmentation.qindex[bp.prediction_parameters->segment_id] >
+ 0) {
const int cdf_index = SymbolDecoderContext::TxTypeIndex(tx_set);
const int cdf_tx_size_index =
TransformSizeToSquareTransformIndex(kTransformSizeSquareMin[tx_size]);
@@ -1309,7 +1306,7 @@ bool Tile::ReadSignAndApplyDequantization(
int length = 0;
bool golomb_length_bit = false;
do {
- golomb_length_bit = static_cast<bool>(reader_.ReadBit());
+ golomb_length_bit = reader_.ReadBit() != 0;
++length;
if (length > 20) {
LIBGAV1_DLOG(ERROR, "Invalid golomb_length %d", length);
@@ -1454,7 +1451,7 @@ int Tile::ReadTransformCoefficients(const Block& block, Plane plane,
for (int i = 1; i < eob_pt - 2; ++i) {
assert(eob_pt - i >= 3);
assert(eob_pt <= kEobPt1024SymbolCount);
- if (static_cast<bool>(reader_.ReadBit())) {
+ if (reader_.ReadBit() != 0) {
eob += 1 << (eob_pt - i - 3);
}
}
@@ -1500,15 +1497,17 @@ int Tile::ReadTransformCoefficients(const Block& block, Plane plane,
coeff_base_range_cdf, residual, level_buffer);
}
const int max_value = (1 << (7 + sequence_header_.color_config.bitdepth)) - 1;
- const int current_quantizer_index = GetQIndex(
- frame_header_.segmentation, bp.segment_id, current_quantizer_index_);
+ const int current_quantizer_index =
+ GetQIndex(frame_header_.segmentation,
+ bp.prediction_parameters->segment_id, current_quantizer_index_);
const int dc_q_value = quantizer_.GetDcValue(plane, current_quantizer_index);
const int ac_q_value = quantizer_.GetAcValue(plane, current_quantizer_index);
const int shift = kQuantizationShift[tx_size];
const uint8_t* const quantizer_matrix =
(frame_header_.quantizer.use_matrix &&
*tx_type < kTransformTypeIdentityIdentity &&
- !frame_header_.segmentation.lossless[bp.segment_id] &&
+ !frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id] &&
frame_header_.quantizer.matrix_level[plane] < 15)
? quantizer_matrix_[frame_header_.quantizer.matrix_level[plane]]
[plane_type][adjusted_tx_size]
@@ -1587,15 +1586,17 @@ bool Tile::TransformBlock(const Block& block, Plane plane, int base_x,
const bool do_decode = mode == kProcessingModeDecodeOnly ||
mode == kProcessingModeParseAndDecode;
if (do_decode && !bp.is_inter) {
- if (bp.palette_mode_info.size[GetPlaneType(plane)] > 0) {
+ if (bp.prediction_parameters->palette_mode_info.size[GetPlaneType(plane)] >
+ 0) {
CALL_BITDEPTH_FUNCTION(PalettePrediction, block, plane, start_x, start_y,
x, y, tx_size);
} else {
const PredictionMode mode =
- (plane == kPlaneY)
- ? bp.y_mode
- : (bp.uv_mode == kPredictionModeChromaFromLuma ? kPredictionModeDc
- : bp.uv_mode);
+ (plane == kPlaneY) ? bp.y_mode
+ : (bp.prediction_parameters->uv_mode ==
+ kPredictionModeChromaFromLuma
+ ? kPredictionModeDc
+ : bp.prediction_parameters->uv_mode);
const int tr_row4x4 = (sub_block_row4x4 >> subsampling_y);
const int tr_column4x4 =
(sub_block_column4x4 >> subsampling_x) + step_x + 1;
@@ -1609,7 +1610,8 @@ bool Tile::TransformBlock(const Block& block, Plane plane, int base_x,
block.scratch_buffer->block_decoded[plane][tr_row4x4][tr_column4x4],
block.scratch_buffer->block_decoded[plane][bl_row4x4][bl_column4x4],
mode, tx_size);
- if (plane != kPlaneY && bp.uv_mode == kPredictionModeChromaFromLuma) {
+ if (plane != kPlaneY &&
+ bp.prediction_parameters->uv_mode == kPredictionModeChromaFromLuma) {
CALL_BITDEPTH_FUNCTION(ChromaFromLumaPrediction, block, plane, start_x,
start_y, tx_size);
}
@@ -1738,14 +1740,16 @@ void Tile::ReconstructBlock(const Block& block, Plane plane, int start_x,
buffer_[plane].rows(), buffer_[plane].columns() / sizeof(uint16_t),
reinterpret_cast<uint16_t*>(&buffer_[plane][0][0]));
Reconstruct(dsp_, tx_type, tx_size,
- frame_header_.segmentation.lossless[block.bp->segment_id],
+ frame_header_.segmentation
+ .lossless[block.bp->prediction_parameters->segment_id],
reinterpret_cast<int32_t*>(*block.residual), start_x, start_y,
&buffer, non_zero_coeff_count);
} else // NOLINT
#endif
{
Reconstruct(dsp_, tx_type, tx_size,
- frame_header_.segmentation.lossless[block.bp->segment_id],
+ frame_header_.segmentation
+ .lossless[block.bp->prediction_parameters->segment_id],
reinterpret_cast<int16_t*>(*block.residual), start_x, start_y,
&buffer_[plane], non_zero_coeff_count);
}
@@ -1772,12 +1776,15 @@ bool Tile::Residual(const Block& block, ProcessingMode mode) {
// kTransformSize4x4. So we can simply use |bp.transform_size| here as
// the Y plane's transform size (part of Section 5.11.37 in the spec).
const TransformSize tx_size =
- (plane == kPlaneY) ? bp.transform_size : bp.uv_transform_size;
+ (plane == kPlaneY)
+ ? inter_transform_sizes_[block.row4x4][block.column4x4]
+ : bp.uv_transform_size;
const BlockSize plane_size =
kPlaneResidualSize[size_chunk4x4][subsampling_x][subsampling_y];
assert(plane_size != kBlockInvalid);
if (bp.is_inter &&
- !frame_header_.segmentation.lossless[bp.segment_id] &&
+ !frame_header_.segmentation
+ .lossless[bp.prediction_parameters->segment_id] &&
plane == kPlaneY) {
const int row_chunk4x4 = block.row4x4 + MultiplyBy16(chunk_y);
const int column_chunk4x4 = block.column4x4 + MultiplyBy16(chunk_x);
@@ -2112,15 +2119,53 @@ void Tile::PopulateDeblockFilterLevel(const Block& block) {
for (int i = 0; i < kFrameLfCount; ++i) {
if (delta_lf_all_zero_) {
bp.deblock_filter_level[i] = post_filter_.GetZeroDeltaDeblockFilterLevel(
- bp.segment_id, i, bp.reference_frame[0], mode_id);
+ bp.prediction_parameters->segment_id, i, bp.reference_frame[0],
+ mode_id);
} else {
bp.deblock_filter_level[i] =
- deblock_filter_levels_[bp.segment_id][i][bp.reference_frame[0]]
- [mode_id];
+ deblock_filter_levels_[bp.prediction_parameters->segment_id][i]
+ [bp.reference_frame[0]][mode_id];
}
}
}
+void Tile::PopulateCdefSkip(const Block& block) {
+ if (!post_filter_.DoCdef() || block.bp->skip ||
+ (frame_header_.cdef.bits > 0 &&
+ cdef_index_[DivideBy16(block.row4x4)][DivideBy16(block.column4x4)] ==
+ -1)) {
+ return;
+ }
+ // The rest of this function is an efficient version of the following code:
+ // for (int y = block.row4x4; y < block.row4x4 + block.height4x4; y++) {
+ // for (int x = block.column4x4; y < block.column4x4 + block.width4x4;
+ // x++) {
+ // const uint8_t mask = uint8_t{1} << ((x >> 1) & 0x7);
+ // cdef_skip_[y >> 1][x >> 4] |= mask;
+ // }
+ // }
+
+ // For all block widths other than 32, the mask will fit in uint8_t. For
+ // block width == 32, the mask is always 0xFFFF.
+ const int bw4 =
+ std::max(DivideBy2(block.width4x4) + (block.column4x4 & 1), 1);
+ const uint8_t mask = (block.width4x4 == 32)
+ ? 0xFF
+ : (uint8_t{0xFF} >> (8 - bw4))
+ << (DivideBy2(block.column4x4) & 0x7);
+ uint8_t* cdef_skip = &cdef_skip_[block.row4x4 >> 1][block.column4x4 >> 4];
+ const int stride = cdef_skip_.columns();
+ int row = 0;
+ do {
+ *cdef_skip |= mask;
+ if (block.width4x4 == 32) {
+ *(cdef_skip + 1) = 0xFF;
+ }
+ cdef_skip += stride;
+ row += 2;
+ } while (row < block.height4x4);
+}
+
bool Tile::ProcessBlock(int row4x4, int column4x4, BlockSize block_size,
TileScratchBuffer* const scratch_buffer,
ResidualPtr* residual) {
@@ -2150,7 +2195,7 @@ bool Tile::ProcessBlock(int row4x4, int column4x4, BlockSize block_size,
return false;
}
BlockParameters& bp = *bp_ptr;
- Block block(*this, block_size, row4x4, column4x4, scratch_buffer, residual);
+ Block block(this, block_size, row4x4, column4x4, scratch_buffer, residual);
bp.size = block_size;
bp.prediction_parameters =
split_parse_and_decode_ ? std::unique_ptr<PredictionParameters>(
@@ -2158,17 +2203,16 @@ bool Tile::ProcessBlock(int row4x4, int column4x4, BlockSize block_size,
: std::move(prediction_parameters_);
if (bp.prediction_parameters == nullptr) return false;
if (!DecodeModeInfo(block)) return false;
- bp.is_global_mv_block = (bp.y_mode == kPredictionModeGlobalMv ||
- bp.y_mode == kPredictionModeGlobalGlobalMv) &&
- !IsBlockDimension4(bp.size);
PopulateDeblockFilterLevel(block);
if (!ReadPaletteTokens(block)) return false;
DecodeTransformSize(block);
// Part of Section 5.11.37 in the spec (implemented as a simple lookup).
- bp.uv_transform_size = frame_header_.segmentation.lossless[bp.segment_id]
- ? kTransformSize4x4
- : kUVTransformSize[block.residual_size[kPlaneU]];
+ bp.uv_transform_size =
+ frame_header_.segmentation.lossless[bp.prediction_parameters->segment_id]
+ ? kTransformSize4x4
+ : kUVTransformSize[block.residual_size[kPlaneU]];
if (bp.skip) ResetEntropyContext(block);
+ PopulateCdefSkip(block);
if (split_parse_and_decode_) {
if (!Residual(block, kProcessingModeParseOnly)) return false;
} else {
@@ -2177,22 +2221,24 @@ bool Tile::ProcessBlock(int row4x4, int column4x4, BlockSize block_size,
return false;
}
}
- // If frame_header_.segmentation.enabled is false, bp.segment_id is 0 for all
- // blocks. We don't need to call save bp.segment_id in the current frame
- // because the current frame's segmentation map will be cleared to all 0s.
+ // If frame_header_.segmentation.enabled is false,
+ // bp.prediction_parameters->segment_id is 0 for all blocks. We don't need to
+ // call save bp.prediction_parameters->segment_id in the current frame because
+ // the current frame's segmentation map will be cleared to all 0s.
//
// If frame_header_.segmentation.enabled is true and
// frame_header_.segmentation.update_map is false, we will copy the previous
// frame's segmentation map to the current frame. So we don't need to call
- // save bp.segment_id in the current frame.
+ // save bp.prediction_parameters->segment_id in the current frame.
if (frame_header_.segmentation.enabled &&
frame_header_.segmentation.update_map) {
const int x_limit = std::min(frame_header_.columns4x4 - column4x4,
static_cast<int>(block.width4x4));
const int y_limit = std::min(frame_header_.rows4x4 - row4x4,
static_cast<int>(block.height4x4));
- current_frame_.segmentation_map()->FillBlock(row4x4, column4x4, x_limit,
- y_limit, bp.segment_id);
+ current_frame_.segmentation_map()->FillBlock(
+ row4x4, column4x4, x_limit, y_limit,
+ bp.prediction_parameters->segment_id);
}
StoreMotionFieldMvsIntoCurrentFrame(block);
if (!split_parse_and_decode_) {
@@ -2208,7 +2254,7 @@ bool Tile::DecodeBlock(int row4x4, int column4x4, BlockSize block_size,
column4x4 >= frame_header_.columns4x4) {
return true;
}
- Block block(*this, block_size, row4x4, column4x4, scratch_buffer, residual);
+ Block block(this, block_size, row4x4, column4x4, scratch_buffer, residual);
if (!ComputePrediction(block) ||
!Residual(block, kProcessingModeDecodeOnly)) {
return false;
@@ -2382,7 +2428,7 @@ void Tile::ResetLoopRestorationParams() {
}
void Tile::ResetCdef(const int row4x4, const int column4x4) {
- if (!sequence_header_.enable_cdef) return;
+ if (frame_header_.cdef.bits == 0) return;
const int row = DivideBy16(row4x4);
const int column = DivideBy16(column4x4);
cdef_index_[row][column] = -1;
@@ -2562,8 +2608,8 @@ void Tile::StoreMotionFieldMvsIntoCurrentFrame(const Block& block) {
// Must make a local copy so that StoreMotionFieldMvs() knows there is no
// overlap between load and store.
const MotionVector mv_to_store = bp.mv.mv[i];
- const int mv_row = std::abs(mv_to_store.mv[MotionVector::kRow]);
- const int mv_column = std::abs(mv_to_store.mv[MotionVector::kColumn]);
+ const int mv_row = std::abs(mv_to_store.mv[0]);
+ const int mv_column = std::abs(mv_to_store.mv[1]);
if (reference_frame_to_store > kReferenceFrameIntra &&
// kRefMvsLimit equals 0x07FF, so we can first bitwise OR the two
// absolute values and then compare with kRefMvsLimit to save a branch.