xref: /aosp_15_r20/external/libgav1/src/loop_restoration_info.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1*09537850SAkhilesh Sanikop // Copyright 2019 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop //      http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop 
15*09537850SAkhilesh Sanikop #include "src/loop_restoration_info.h"
16*09537850SAkhilesh Sanikop 
17*09537850SAkhilesh Sanikop #include <algorithm>
18*09537850SAkhilesh Sanikop #include <array>
19*09537850SAkhilesh Sanikop #include <cassert>
20*09537850SAkhilesh Sanikop #include <cstddef>
21*09537850SAkhilesh Sanikop #include <cstdint>
22*09537850SAkhilesh Sanikop #include <memory>
23*09537850SAkhilesh Sanikop #include <new>
24*09537850SAkhilesh Sanikop 
25*09537850SAkhilesh Sanikop #include "src/utils/common.h"
26*09537850SAkhilesh Sanikop #include "src/utils/logging.h"
27*09537850SAkhilesh Sanikop 
28*09537850SAkhilesh Sanikop namespace libgav1 {
29*09537850SAkhilesh Sanikop namespace {
30*09537850SAkhilesh Sanikop 
31*09537850SAkhilesh Sanikop // Controls how self guided deltas are read.
32*09537850SAkhilesh Sanikop constexpr int kSgrProjReadControl = 4;
33*09537850SAkhilesh Sanikop // Maps the restoration type encoded in the compressed headers (restoration_type
34*09537850SAkhilesh Sanikop // element in the spec) of the bitstream to LoopRestorationType. This is used
35*09537850SAkhilesh Sanikop // only when the restoration type in the frame header is
36*09537850SAkhilesh Sanikop // LoopRestorationTypeSwitchable.
37*09537850SAkhilesh Sanikop constexpr LoopRestorationType kBitstreamRestorationTypeMap[] = {
38*09537850SAkhilesh Sanikop     kLoopRestorationTypeNone, kLoopRestorationTypeWiener,
39*09537850SAkhilesh Sanikop     kLoopRestorationTypeSgrProj};
40*09537850SAkhilesh Sanikop 
CountLeadingZeroCoefficients(const int16_t * const filter)41*09537850SAkhilesh Sanikop inline int CountLeadingZeroCoefficients(const int16_t* const filter) {
42*09537850SAkhilesh Sanikop   int number_zero_coefficients = 0;
43*09537850SAkhilesh Sanikop   if (filter[0] == 0) {
44*09537850SAkhilesh Sanikop     number_zero_coefficients++;
45*09537850SAkhilesh Sanikop     if (filter[1] == 0) {
46*09537850SAkhilesh Sanikop       number_zero_coefficients++;
47*09537850SAkhilesh Sanikop       if (filter[2] == 0) {
48*09537850SAkhilesh Sanikop         number_zero_coefficients++;
49*09537850SAkhilesh Sanikop       }
50*09537850SAkhilesh Sanikop     }
51*09537850SAkhilesh Sanikop   }
52*09537850SAkhilesh Sanikop   return number_zero_coefficients;
53*09537850SAkhilesh Sanikop }
54*09537850SAkhilesh Sanikop 
55*09537850SAkhilesh Sanikop }  // namespace
56*09537850SAkhilesh Sanikop 
Reset(const LoopRestoration * const loop_restoration,uint32_t width,uint32_t height,int8_t subsampling_x,int8_t subsampling_y,bool is_monochrome)57*09537850SAkhilesh Sanikop bool LoopRestorationInfo::Reset(const LoopRestoration* const loop_restoration,
58*09537850SAkhilesh Sanikop                                 uint32_t width, uint32_t height,
59*09537850SAkhilesh Sanikop                                 int8_t subsampling_x, int8_t subsampling_y,
60*09537850SAkhilesh Sanikop                                 bool is_monochrome) {
61*09537850SAkhilesh Sanikop   loop_restoration_ = loop_restoration;
62*09537850SAkhilesh Sanikop   subsampling_x_ = subsampling_x;
63*09537850SAkhilesh Sanikop   subsampling_y_ = subsampling_y;
64*09537850SAkhilesh Sanikop 
65*09537850SAkhilesh Sanikop   const int num_planes = is_monochrome ? kMaxPlanesMonochrome : kMaxPlanes;
66*09537850SAkhilesh Sanikop   int total_num_units = 0;
67*09537850SAkhilesh Sanikop   for (int plane = kPlaneY; plane < num_planes; ++plane) {
68*09537850SAkhilesh Sanikop     if (loop_restoration_->type[plane] == kLoopRestorationTypeNone) {
69*09537850SAkhilesh Sanikop       plane_needs_filtering_[plane] = false;
70*09537850SAkhilesh Sanikop       continue;
71*09537850SAkhilesh Sanikop     }
72*09537850SAkhilesh Sanikop     plane_needs_filtering_[plane] = true;
73*09537850SAkhilesh Sanikop     const int plane_width =
74*09537850SAkhilesh Sanikop         (plane == kPlaneY) ? width : SubsampledValue(width, subsampling_x_);
75*09537850SAkhilesh Sanikop     const int plane_height =
76*09537850SAkhilesh Sanikop         (plane == kPlaneY) ? height : SubsampledValue(height, subsampling_y_);
77*09537850SAkhilesh Sanikop     num_horizontal_units_[plane] =
78*09537850SAkhilesh Sanikop         std::max(1, RightShiftWithRounding(
79*09537850SAkhilesh Sanikop                         plane_width, loop_restoration_->unit_size_log2[plane]));
80*09537850SAkhilesh Sanikop     num_vertical_units_[plane] = std::max(
81*09537850SAkhilesh Sanikop         1, RightShiftWithRounding(plane_height,
82*09537850SAkhilesh Sanikop                                   loop_restoration_->unit_size_log2[plane]));
83*09537850SAkhilesh Sanikop     num_units_[plane] =
84*09537850SAkhilesh Sanikop         num_horizontal_units_[plane] * num_vertical_units_[plane];
85*09537850SAkhilesh Sanikop     total_num_units += num_units_[plane];
86*09537850SAkhilesh Sanikop   }
87*09537850SAkhilesh Sanikop   // Allocate the RestorationUnitInfo arrays for all planes in a single heap
88*09537850SAkhilesh Sanikop   // allocation and divide up the buffer into arrays of the right sizes.
89*09537850SAkhilesh Sanikop   if (!loop_restoration_info_buffer_.Resize(total_num_units)) {
90*09537850SAkhilesh Sanikop     return false;
91*09537850SAkhilesh Sanikop   }
92*09537850SAkhilesh Sanikop   RestorationUnitInfo* loop_restoration_info =
93*09537850SAkhilesh Sanikop       loop_restoration_info_buffer_.get();
94*09537850SAkhilesh Sanikop   for (int plane = kPlaneY; plane < num_planes; ++plane) {
95*09537850SAkhilesh Sanikop     if (loop_restoration_->type[plane] == kLoopRestorationTypeNone) {
96*09537850SAkhilesh Sanikop       continue;
97*09537850SAkhilesh Sanikop     }
98*09537850SAkhilesh Sanikop     loop_restoration_info_[plane] = loop_restoration_info;
99*09537850SAkhilesh Sanikop     loop_restoration_info += num_units_[plane];
100*09537850SAkhilesh Sanikop   }
101*09537850SAkhilesh Sanikop   return true;
102*09537850SAkhilesh Sanikop }
103*09537850SAkhilesh Sanikop 
PopulateUnitInfoForSuperBlock(Plane plane,BlockSize block_size,bool is_superres_scaled,uint8_t superres_scale_denominator,int row4x4,int column4x4,LoopRestorationUnitInfo * const unit_info) const104*09537850SAkhilesh Sanikop bool LoopRestorationInfo::PopulateUnitInfoForSuperBlock(
105*09537850SAkhilesh Sanikop     Plane plane, BlockSize block_size, bool is_superres_scaled,
106*09537850SAkhilesh Sanikop     uint8_t superres_scale_denominator, int row4x4, int column4x4,
107*09537850SAkhilesh Sanikop     LoopRestorationUnitInfo* const unit_info) const {
108*09537850SAkhilesh Sanikop   assert(unit_info != nullptr);
109*09537850SAkhilesh Sanikop   if (!plane_needs_filtering_[plane]) return false;
110*09537850SAkhilesh Sanikop   const int numerator_column =
111*09537850SAkhilesh Sanikop       is_superres_scaled ? superres_scale_denominator : 1;
112*09537850SAkhilesh Sanikop   const int pixel_column_start =
113*09537850SAkhilesh Sanikop       RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_);
114*09537850SAkhilesh Sanikop   const int pixel_column_end = RowOrColumn4x4ToPixel(
115*09537850SAkhilesh Sanikop       column4x4 + kNum4x4BlocksWide[block_size], plane, subsampling_x_);
116*09537850SAkhilesh Sanikop   const int unit_row_log2 = loop_restoration_->unit_size_log2[plane];
117*09537850SAkhilesh Sanikop   const int denominator_column_log2 =
118*09537850SAkhilesh Sanikop       unit_row_log2 + (is_superres_scaled ? 3 : 0);
119*09537850SAkhilesh Sanikop   const int pixel_row_start =
120*09537850SAkhilesh Sanikop       RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_);
121*09537850SAkhilesh Sanikop   const int pixel_row_end = RowOrColumn4x4ToPixel(
122*09537850SAkhilesh Sanikop       row4x4 + kNum4x4BlocksHigh[block_size], plane, subsampling_y_);
123*09537850SAkhilesh Sanikop   unit_info->column_start = RightShiftWithCeiling(
124*09537850SAkhilesh Sanikop       pixel_column_start * numerator_column, denominator_column_log2);
125*09537850SAkhilesh Sanikop   unit_info->column_end = RightShiftWithCeiling(
126*09537850SAkhilesh Sanikop       pixel_column_end * numerator_column, denominator_column_log2);
127*09537850SAkhilesh Sanikop   unit_info->row_start = RightShiftWithCeiling(pixel_row_start, unit_row_log2);
128*09537850SAkhilesh Sanikop   unit_info->row_end = RightShiftWithCeiling(pixel_row_end, unit_row_log2);
129*09537850SAkhilesh Sanikop   unit_info->column_end =
130*09537850SAkhilesh Sanikop       std::min(unit_info->column_end, num_horizontal_units_[plane]);
131*09537850SAkhilesh Sanikop   unit_info->row_end = std::min(unit_info->row_end, num_vertical_units_[plane]);
132*09537850SAkhilesh Sanikop   return true;
133*09537850SAkhilesh Sanikop }
134*09537850SAkhilesh Sanikop 
ReadUnitCoefficients(EntropyDecoder * const reader,SymbolDecoderContext * const symbol_decoder_context,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)135*09537850SAkhilesh Sanikop void LoopRestorationInfo::ReadUnitCoefficients(
136*09537850SAkhilesh Sanikop     EntropyDecoder* const reader,
137*09537850SAkhilesh Sanikop     SymbolDecoderContext* const symbol_decoder_context, Plane plane,
138*09537850SAkhilesh Sanikop     int unit_id,
139*09537850SAkhilesh Sanikop     std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
140*09537850SAkhilesh Sanikop   LoopRestorationType unit_restoration_type = kLoopRestorationTypeNone;
141*09537850SAkhilesh Sanikop   if (loop_restoration_->type[plane] == kLoopRestorationTypeSwitchable) {
142*09537850SAkhilesh Sanikop     unit_restoration_type = kBitstreamRestorationTypeMap
143*09537850SAkhilesh Sanikop         [reader->ReadSymbol<kRestorationTypeSymbolCount>(
144*09537850SAkhilesh Sanikop             symbol_decoder_context->restoration_type_cdf)];
145*09537850SAkhilesh Sanikop   } else if (loop_restoration_->type[plane] == kLoopRestorationTypeWiener) {
146*09537850SAkhilesh Sanikop     const bool use_wiener =
147*09537850SAkhilesh Sanikop         reader->ReadSymbol(symbol_decoder_context->use_wiener_cdf);
148*09537850SAkhilesh Sanikop     if (use_wiener) unit_restoration_type = kLoopRestorationTypeWiener;
149*09537850SAkhilesh Sanikop   } else if (loop_restoration_->type[plane] == kLoopRestorationTypeSgrProj) {
150*09537850SAkhilesh Sanikop     const bool use_sgrproj =
151*09537850SAkhilesh Sanikop         reader->ReadSymbol(symbol_decoder_context->use_sgrproj_cdf);
152*09537850SAkhilesh Sanikop     if (use_sgrproj) unit_restoration_type = kLoopRestorationTypeSgrProj;
153*09537850SAkhilesh Sanikop   }
154*09537850SAkhilesh Sanikop   loop_restoration_info_[plane][unit_id].type = unit_restoration_type;
155*09537850SAkhilesh Sanikop 
156*09537850SAkhilesh Sanikop   if (unit_restoration_type == kLoopRestorationTypeWiener) {
157*09537850SAkhilesh Sanikop     ReadWienerInfo(reader, plane, unit_id, reference_unit_info);
158*09537850SAkhilesh Sanikop   } else if (unit_restoration_type == kLoopRestorationTypeSgrProj) {
159*09537850SAkhilesh Sanikop     ReadSgrProjInfo(reader, plane, unit_id, reference_unit_info);
160*09537850SAkhilesh Sanikop   }
161*09537850SAkhilesh Sanikop }
162*09537850SAkhilesh Sanikop 
ReadWienerInfo(EntropyDecoder * const reader,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)163*09537850SAkhilesh Sanikop void LoopRestorationInfo::ReadWienerInfo(
164*09537850SAkhilesh Sanikop     EntropyDecoder* const reader, Plane plane, int unit_id,
165*09537850SAkhilesh Sanikop     std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
166*09537850SAkhilesh Sanikop   for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
167*09537850SAkhilesh Sanikop     if (plane != kPlaneY) {
168*09537850SAkhilesh Sanikop       loop_restoration_info_[plane][unit_id].wiener_info.filter[i][0] = 0;
169*09537850SAkhilesh Sanikop     }
170*09537850SAkhilesh Sanikop     int sum = 0;
171*09537850SAkhilesh Sanikop     for (int j = static_cast<int>(plane != kPlaneY); j < kNumWienerCoefficients;
172*09537850SAkhilesh Sanikop          ++j) {
173*09537850SAkhilesh Sanikop       const int8_t wiener_min = kWienerTapsMin[j];
174*09537850SAkhilesh Sanikop       const int8_t wiener_max = kWienerTapsMax[j];
175*09537850SAkhilesh Sanikop       const int control = j + 1;
176*09537850SAkhilesh Sanikop       int value;
177*09537850SAkhilesh Sanikop       if (!reader->DecodeSignedSubexpWithReference(
178*09537850SAkhilesh Sanikop               wiener_min, wiener_max + 1,
179*09537850SAkhilesh Sanikop               (*reference_unit_info)[plane].wiener_info.filter[i][j], control,
180*09537850SAkhilesh Sanikop               &value)) {
181*09537850SAkhilesh Sanikop         LIBGAV1_DLOG(
182*09537850SAkhilesh Sanikop             ERROR,
183*09537850SAkhilesh Sanikop             "Error decoding Wiener filter coefficients: plane %d, unit_id %d",
184*09537850SAkhilesh Sanikop             static_cast<int>(plane), unit_id);
185*09537850SAkhilesh Sanikop         return;
186*09537850SAkhilesh Sanikop       }
187*09537850SAkhilesh Sanikop       loop_restoration_info_[plane][unit_id].wiener_info.filter[i][j] = value;
188*09537850SAkhilesh Sanikop       (*reference_unit_info)[plane].wiener_info.filter[i][j] = value;
189*09537850SAkhilesh Sanikop       sum += value;
190*09537850SAkhilesh Sanikop     }
191*09537850SAkhilesh Sanikop     loop_restoration_info_[plane][unit_id].wiener_info.filter[i][3] =
192*09537850SAkhilesh Sanikop         128 - 2 * sum;
193*09537850SAkhilesh Sanikop     loop_restoration_info_[plane][unit_id]
194*09537850SAkhilesh Sanikop         .wiener_info.number_leading_zero_coefficients[i] =
195*09537850SAkhilesh Sanikop         CountLeadingZeroCoefficients(
196*09537850SAkhilesh Sanikop             loop_restoration_info_[plane][unit_id].wiener_info.filter[i]);
197*09537850SAkhilesh Sanikop   }
198*09537850SAkhilesh Sanikop }
199*09537850SAkhilesh Sanikop 
ReadSgrProjInfo(EntropyDecoder * const reader,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)200*09537850SAkhilesh Sanikop void LoopRestorationInfo::ReadSgrProjInfo(
201*09537850SAkhilesh Sanikop     EntropyDecoder* const reader, Plane plane, int unit_id,
202*09537850SAkhilesh Sanikop     std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
203*09537850SAkhilesh Sanikop   const int sgr_proj_index =
204*09537850SAkhilesh Sanikop       static_cast<int>(reader->ReadLiteral(kSgrProjParamsBits));
205*09537850SAkhilesh Sanikop   loop_restoration_info_[plane][unit_id].sgr_proj_info.index = sgr_proj_index;
206*09537850SAkhilesh Sanikop   for (int i = 0; i < 2; ++i) {
207*09537850SAkhilesh Sanikop     const uint8_t radius = kSgrProjParams[sgr_proj_index][i * 2];
208*09537850SAkhilesh Sanikop     const int8_t multiplier_min = kSgrProjMultiplierMin[i];
209*09537850SAkhilesh Sanikop     const int8_t multiplier_max = kSgrProjMultiplierMax[i];
210*09537850SAkhilesh Sanikop     int multiplier;
211*09537850SAkhilesh Sanikop     if (radius != 0) {
212*09537850SAkhilesh Sanikop       if (!reader->DecodeSignedSubexpWithReference(
213*09537850SAkhilesh Sanikop               multiplier_min, multiplier_max + 1,
214*09537850SAkhilesh Sanikop               (*reference_unit_info)[plane].sgr_proj_info.multiplier[i],
215*09537850SAkhilesh Sanikop               kSgrProjReadControl, &multiplier)) {
216*09537850SAkhilesh Sanikop         LIBGAV1_DLOG(ERROR,
217*09537850SAkhilesh Sanikop                      "Error decoding Self-guided filter coefficients: plane "
218*09537850SAkhilesh Sanikop                      "%d, unit_id %d",
219*09537850SAkhilesh Sanikop                      static_cast<int>(plane), unit_id);
220*09537850SAkhilesh Sanikop         return;
221*09537850SAkhilesh Sanikop       }
222*09537850SAkhilesh Sanikop     } else {
223*09537850SAkhilesh Sanikop       // The range of (*reference_unit_info)[plane].sgr_proj_info.multiplier[0]
224*09537850SAkhilesh Sanikop       // from DecodeSignedSubexpWithReference() is [-96, 31], the default is
225*09537850SAkhilesh Sanikop       // -32, making Clip3(128 - 31, -32, 95) unnecessary.
226*09537850SAkhilesh Sanikop       static constexpr int kMultiplier[2] = {0, 95};
227*09537850SAkhilesh Sanikop       multiplier = kMultiplier[i];
228*09537850SAkhilesh Sanikop       assert(
229*09537850SAkhilesh Sanikop           i == 0 ||
230*09537850SAkhilesh Sanikop           Clip3((1 << kSgrProjPrecisionBits) -
231*09537850SAkhilesh Sanikop                     (*reference_unit_info)[plane].sgr_proj_info.multiplier[0],
232*09537850SAkhilesh Sanikop                 multiplier_min, multiplier_max) == kMultiplier[1]);
233*09537850SAkhilesh Sanikop     }
234*09537850SAkhilesh Sanikop     loop_restoration_info_[plane][unit_id].sgr_proj_info.multiplier[i] =
235*09537850SAkhilesh Sanikop         multiplier;
236*09537850SAkhilesh Sanikop     (*reference_unit_info)[plane].sgr_proj_info.multiplier[i] = multiplier;
237*09537850SAkhilesh Sanikop   }
238*09537850SAkhilesh Sanikop }
239*09537850SAkhilesh Sanikop 
240*09537850SAkhilesh Sanikop }  // namespace libgav1
241