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