diff options
Diffstat (limited to 'src/loop_restoration_info.cc')
-rw-r--r-- | src/loop_restoration_info.cc | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/loop_restoration_info.cc b/src/loop_restoration_info.cc new file mode 100644 index 0000000..2dba57d --- /dev/null +++ b/src/loop_restoration_info.cc @@ -0,0 +1,240 @@ +// Copyright 2019 The libgav1 Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/loop_restoration_info.h" + +#include <algorithm> +#include <array> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <new> + +#include "src/utils/common.h" +#include "src/utils/logging.h" + +namespace libgav1 { +namespace { + +// Controls how self guided deltas are read. +constexpr int kSgrProjReadControl = 4; +// Maps the restoration type encoded in the compressed headers (restoration_type +// element in the spec) of the bitstream to LoopRestorationType. This is used +// only when the restoration type in the frame header is +// LoopRestorationTypeSwitchable. +constexpr LoopRestorationType kBitstreamRestorationTypeMap[] = { + kLoopRestorationTypeNone, kLoopRestorationTypeWiener, + kLoopRestorationTypeSgrProj}; + +inline int CountLeadingZeroCoefficients(const int16_t* const filter) { + int number_zero_coefficients = 0; + if (filter[0] == 0) { + number_zero_coefficients++; + if (filter[1] == 0) { + number_zero_coefficients++; + if (filter[2] == 0) { + number_zero_coefficients++; + } + } + } + return number_zero_coefficients; +} + +} // namespace + +bool LoopRestorationInfo::Reset(const LoopRestoration* const loop_restoration, + uint32_t width, uint32_t height, + int8_t subsampling_x, int8_t subsampling_y, + bool is_monochrome) { + loop_restoration_ = loop_restoration; + subsampling_x_ = subsampling_x; + subsampling_y_ = subsampling_y; + + const int num_planes = is_monochrome ? kMaxPlanesMonochrome : kMaxPlanes; + int total_num_units = 0; + for (int plane = kPlaneY; plane < num_planes; ++plane) { + if (loop_restoration_->type[plane] == kLoopRestorationTypeNone) { + plane_needs_filtering_[plane] = false; + continue; + } + plane_needs_filtering_[plane] = true; + const int plane_width = + (plane == kPlaneY) ? width : SubsampledValue(width, subsampling_x_); + const int plane_height = + (plane == kPlaneY) ? height : SubsampledValue(height, subsampling_y_); + num_horizontal_units_[plane] = + std::max(1, RightShiftWithRounding( + plane_width, loop_restoration_->unit_size_log2[plane])); + num_vertical_units_[plane] = std::max( + 1, RightShiftWithRounding(plane_height, + loop_restoration_->unit_size_log2[plane])); + num_units_[plane] = + num_horizontal_units_[plane] * num_vertical_units_[plane]; + total_num_units += num_units_[plane]; + } + // Allocate the RestorationUnitInfo arrays for all planes in a single heap + // allocation and divide up the buffer into arrays of the right sizes. + if (!loop_restoration_info_buffer_.Resize(total_num_units)) { + return false; + } + RestorationUnitInfo* loop_restoration_info = + loop_restoration_info_buffer_.get(); + for (int plane = kPlaneY; plane < num_planes; ++plane) { + if (loop_restoration_->type[plane] == kLoopRestorationTypeNone) { + continue; + } + loop_restoration_info_[plane] = loop_restoration_info; + loop_restoration_info += num_units_[plane]; + } + return true; +} + +bool LoopRestorationInfo::PopulateUnitInfoForSuperBlock( + Plane plane, BlockSize block_size, bool is_superres_scaled, + uint8_t superres_scale_denominator, int row4x4, int column4x4, + LoopRestorationUnitInfo* const unit_info) const { + assert(unit_info != nullptr); + if (!plane_needs_filtering_[plane]) return false; + const int numerator_column = + is_superres_scaled ? superres_scale_denominator : 1; + const int pixel_column_start = + RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_); + const int pixel_column_end = RowOrColumn4x4ToPixel( + column4x4 + kNum4x4BlocksWide[block_size], plane, subsampling_x_); + const int unit_row_log2 = loop_restoration_->unit_size_log2[plane]; + const int denominator_column_log2 = + unit_row_log2 + (is_superres_scaled ? 3 : 0); + const int pixel_row_start = + RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_); + const int pixel_row_end = RowOrColumn4x4ToPixel( + row4x4 + kNum4x4BlocksHigh[block_size], plane, subsampling_y_); + unit_info->column_start = RightShiftWithCeiling( + pixel_column_start * numerator_column, denominator_column_log2); + unit_info->column_end = RightShiftWithCeiling( + pixel_column_end * numerator_column, denominator_column_log2); + unit_info->row_start = RightShiftWithCeiling(pixel_row_start, unit_row_log2); + unit_info->row_end = RightShiftWithCeiling(pixel_row_end, unit_row_log2); + unit_info->column_end = + std::min(unit_info->column_end, num_horizontal_units_[plane]); + unit_info->row_end = std::min(unit_info->row_end, num_vertical_units_[plane]); + return true; +} + +void LoopRestorationInfo::ReadUnitCoefficients( + DaalaBitReader* const reader, + SymbolDecoderContext* const symbol_decoder_context, Plane plane, + int unit_id, + std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) { + LoopRestorationType unit_restoration_type = kLoopRestorationTypeNone; + if (loop_restoration_->type[plane] == kLoopRestorationTypeSwitchable) { + unit_restoration_type = kBitstreamRestorationTypeMap + [reader->ReadSymbol<kRestorationTypeSymbolCount>( + symbol_decoder_context->restoration_type_cdf)]; + } else if (loop_restoration_->type[plane] == kLoopRestorationTypeWiener) { + const bool use_wiener = + reader->ReadSymbol(symbol_decoder_context->use_wiener_cdf); + if (use_wiener) unit_restoration_type = kLoopRestorationTypeWiener; + } else if (loop_restoration_->type[plane] == kLoopRestorationTypeSgrProj) { + const bool use_sgrproj = + reader->ReadSymbol(symbol_decoder_context->use_sgrproj_cdf); + if (use_sgrproj) unit_restoration_type = kLoopRestorationTypeSgrProj; + } + loop_restoration_info_[plane][unit_id].type = unit_restoration_type; + + if (unit_restoration_type == kLoopRestorationTypeWiener) { + ReadWienerInfo(reader, plane, unit_id, reference_unit_info); + } else if (unit_restoration_type == kLoopRestorationTypeSgrProj) { + ReadSgrProjInfo(reader, plane, unit_id, reference_unit_info); + } +} + +void LoopRestorationInfo::ReadWienerInfo( + DaalaBitReader* const reader, Plane plane, int unit_id, + std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) { + for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) { + if (plane != kPlaneY) { + loop_restoration_info_[plane][unit_id].wiener_info.filter[i][0] = 0; + } + int sum = 0; + for (int j = static_cast<int>(plane != kPlaneY); j < kNumWienerCoefficients; + ++j) { + const int8_t wiener_min = kWienerTapsMin[j]; + const int8_t wiener_max = kWienerTapsMax[j]; + const int control = j + 1; + int value; + if (!reader->DecodeSignedSubexpWithReference( + wiener_min, wiener_max + 1, + (*reference_unit_info)[plane].wiener_info.filter[i][j], control, + &value)) { + LIBGAV1_DLOG( + ERROR, + "Error decoding Wiener filter coefficients: plane %d, unit_id %d", + static_cast<int>(plane), unit_id); + return; + } + loop_restoration_info_[plane][unit_id].wiener_info.filter[i][j] = value; + (*reference_unit_info)[plane].wiener_info.filter[i][j] = value; + sum += value; + } + loop_restoration_info_[plane][unit_id].wiener_info.filter[i][3] = + 128 - 2 * sum; + loop_restoration_info_[plane][unit_id] + .wiener_info.number_leading_zero_coefficients[i] = + CountLeadingZeroCoefficients( + loop_restoration_info_[plane][unit_id].wiener_info.filter[i]); + } +} + +void LoopRestorationInfo::ReadSgrProjInfo( + DaalaBitReader* const reader, Plane plane, int unit_id, + std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) { + const int sgr_proj_index = + static_cast<int>(reader->ReadLiteral(kSgrProjParamsBits)); + loop_restoration_info_[plane][unit_id].sgr_proj_info.index = sgr_proj_index; + for (int i = 0; i < 2; ++i) { + const uint8_t radius = kSgrProjParams[sgr_proj_index][i * 2]; + const int8_t multiplier_min = kSgrProjMultiplierMin[i]; + const int8_t multiplier_max = kSgrProjMultiplierMax[i]; + int multiplier; + if (radius != 0) { + if (!reader->DecodeSignedSubexpWithReference( + multiplier_min, multiplier_max + 1, + (*reference_unit_info)[plane].sgr_proj_info.multiplier[i], + kSgrProjReadControl, &multiplier)) { + LIBGAV1_DLOG(ERROR, + "Error decoding Self-guided filter coefficients: plane " + "%d, unit_id %d", + static_cast<int>(plane), unit_id); + return; + } + } else { + // The range of (*reference_unit_info)[plane].sgr_proj_info.multiplier[0] + // from DecodeSignedSubexpWithReference() is [-96, 31], the default is + // -32, making Clip3(128 - 31, -32, 95) unnecessary. + static constexpr int kMultiplier[2] = {0, 95}; + multiplier = kMultiplier[i]; + assert( + i == 0 || + Clip3((1 << kSgrProjPrecisionBits) - + (*reference_unit_info)[plane].sgr_proj_info.multiplier[0], + multiplier_min, multiplier_max) == kMultiplier[1]); + } + loop_restoration_info_[plane][unit_id].sgr_proj_info.multiplier[i] = + multiplier; + (*reference_unit_info)[plane].sgr_proj_info.multiplier[i] = multiplier; + } +} + +} // namespace libgav1 |