diff options
author | Boyuan Yang <byang@debian.org> | 2021-11-07 08:50:20 -0500 |
---|---|---|
committer | Boyuan Yang <byang@debian.org> | 2021-11-07 08:50:20 -0500 |
commit | 513fcf1cd0dca1a6cbef9ff6e38e22237e75ba44 (patch) | |
tree | 249280ac94eb2b871de89cd1b166fff4ee00ab09 /src/tile | |
parent | 3c21ceac2f6a5adfab07d3d458880561543d0a31 (diff) | |
parent | 320ef65362608ee1148c299d8d5d7618af34e470 (diff) | |
download | libgav1-513fcf1cd0dca1a6cbef9ff6e38e22237e75ba44.tar.gz libgav1-513fcf1cd0dca1a6cbef9ff6e38e22237e75ba44.tar.bz2 libgav1-513fcf1cd0dca1a6cbef9ff6e38e22237e75ba44.zip |
Update upstream source from tag 'upstream/0.17.0'
Update to upstream version '0.17.0'
with Debian dir 5b612b6a2d67788b0c85bac59e50edc1545bfd7e
Diffstat (limited to 'src/tile')
-rw-r--r-- | src/tile/bitstream/mode_info.cc | 382 | ||||
-rw-r--r-- | src/tile/bitstream/palette.cc | 64 | ||||
-rw-r--r-- | src/tile/bitstream/transform_size.cc | 12 | ||||
-rw-r--r-- | src/tile/prediction.cc | 54 | ||||
-rw-r--r-- | src/tile/tile.cc | 142 |
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. |