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 =
74 (plane == kPlaneY) ? width : SubsampledValue(width, subsampling_x_);
75 const int plane_height =
76 (plane == kPlaneY) ? height : SubsampledValue(height, subsampling_y_);
77 num_horizontal_units_[plane] =
78 std::max(1, RightShiftWithRounding(
79 plane_width, loop_restoration_->unit_size_log2[plane]));
80 num_vertical_units_[plane] = std::max(
81 1, RightShiftWithRounding(plane_height,
82 loop_restoration_->unit_size_log2[plane]));
83 num_units_[plane] =
84 num_horizontal_units_[plane] * num_vertical_units_[plane];
85 total_num_units += num_units_[plane];
86 }
87 // Allocate the RestorationUnitInfo arrays for all planes in a single heap
88 // allocation and divide up the buffer into arrays of the right sizes.
89 if (!loop_restoration_info_buffer_.Resize(total_num_units)) {
90 return false;
91 }
92 RestorationUnitInfo* loop_restoration_info =
93 loop_restoration_info_buffer_.get();
94 for (int plane = kPlaneY; plane < num_planes; ++plane) {
95 if (loop_restoration_->type[plane] == kLoopRestorationTypeNone) {
96 continue;
97 }
98 loop_restoration_info_[plane] = loop_restoration_info;
99 loop_restoration_info += num_units_[plane];
100 }
101 return true;
102 }
103
PopulateUnitInfoForSuperBlock(Plane plane,BlockSize block_size,bool is_superres_scaled,uint8_t superres_scale_denominator,int row4x4,int column4x4,LoopRestorationUnitInfo * const unit_info) const104 bool LoopRestorationInfo::PopulateUnitInfoForSuperBlock(
105 Plane plane, BlockSize block_size, bool is_superres_scaled,
106 uint8_t superres_scale_denominator, int row4x4, int column4x4,
107 LoopRestorationUnitInfo* const unit_info) const {
108 assert(unit_info != nullptr);
109 if (!plane_needs_filtering_[plane]) return false;
110 const int numerator_column =
111 is_superres_scaled ? superres_scale_denominator : 1;
112 const int pixel_column_start =
113 RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_);
114 const int pixel_column_end = RowOrColumn4x4ToPixel(
115 column4x4 + kNum4x4BlocksWide[block_size], plane, subsampling_x_);
116 const int unit_row_log2 = loop_restoration_->unit_size_log2[plane];
117 const int denominator_column_log2 =
118 unit_row_log2 + (is_superres_scaled ? 3 : 0);
119 const int pixel_row_start =
120 RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_);
121 const int pixel_row_end = RowOrColumn4x4ToPixel(
122 row4x4 + kNum4x4BlocksHigh[block_size], plane, subsampling_y_);
123 unit_info->column_start = RightShiftWithCeiling(
124 pixel_column_start * numerator_column, denominator_column_log2);
125 unit_info->column_end = RightShiftWithCeiling(
126 pixel_column_end * numerator_column, denominator_column_log2);
127 unit_info->row_start = RightShiftWithCeiling(pixel_row_start, unit_row_log2);
128 unit_info->row_end = RightShiftWithCeiling(pixel_row_end, unit_row_log2);
129 unit_info->column_end =
130 std::min(unit_info->column_end, num_horizontal_units_[plane]);
131 unit_info->row_end = std::min(unit_info->row_end, num_vertical_units_[plane]);
132 return true;
133 }
134
ReadUnitCoefficients(DaalaBitReader * const reader,SymbolDecoderContext * const symbol_decoder_context,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)135 void LoopRestorationInfo::ReadUnitCoefficients(
136 DaalaBitReader* const reader,
137 SymbolDecoderContext* const symbol_decoder_context, Plane plane,
138 int unit_id,
139 std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
140 LoopRestorationType unit_restoration_type = kLoopRestorationTypeNone;
141 if (loop_restoration_->type[plane] == kLoopRestorationTypeSwitchable) {
142 unit_restoration_type = kBitstreamRestorationTypeMap
143 [reader->ReadSymbol<kRestorationTypeSymbolCount>(
144 symbol_decoder_context->restoration_type_cdf)];
145 } else if (loop_restoration_->type[plane] == kLoopRestorationTypeWiener) {
146 const bool use_wiener =
147 reader->ReadSymbol(symbol_decoder_context->use_wiener_cdf);
148 if (use_wiener) unit_restoration_type = kLoopRestorationTypeWiener;
149 } else if (loop_restoration_->type[plane] == kLoopRestorationTypeSgrProj) {
150 const bool use_sgrproj =
151 reader->ReadSymbol(symbol_decoder_context->use_sgrproj_cdf);
152 if (use_sgrproj) unit_restoration_type = kLoopRestorationTypeSgrProj;
153 }
154 loop_restoration_info_[plane][unit_id].type = unit_restoration_type;
155
156 if (unit_restoration_type == kLoopRestorationTypeWiener) {
157 ReadWienerInfo(reader, plane, unit_id, reference_unit_info);
158 } else if (unit_restoration_type == kLoopRestorationTypeSgrProj) {
159 ReadSgrProjInfo(reader, plane, unit_id, reference_unit_info);
160 }
161 }
162
ReadWienerInfo(DaalaBitReader * const reader,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)163 void LoopRestorationInfo::ReadWienerInfo(
164 DaalaBitReader* const reader, Plane plane, int unit_id,
165 std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
166 for (int i = WienerInfo::kVertical; i <= WienerInfo::kHorizontal; ++i) {
167 if (plane != kPlaneY) {
168 loop_restoration_info_[plane][unit_id].wiener_info.filter[i][0] = 0;
169 }
170 int sum = 0;
171 for (int j = static_cast<int>(plane != kPlaneY); j < kNumWienerCoefficients;
172 ++j) {
173 const int8_t wiener_min = kWienerTapsMin[j];
174 const int8_t wiener_max = kWienerTapsMax[j];
175 const int control = j + 1;
176 int value;
177 if (!reader->DecodeSignedSubexpWithReference(
178 wiener_min, wiener_max + 1,
179 (*reference_unit_info)[plane].wiener_info.filter[i][j], control,
180 &value)) {
181 LIBGAV1_DLOG(
182 ERROR,
183 "Error decoding Wiener filter coefficients: plane %d, unit_id %d",
184 static_cast<int>(plane), unit_id);
185 return;
186 }
187 loop_restoration_info_[plane][unit_id].wiener_info.filter[i][j] = value;
188 (*reference_unit_info)[plane].wiener_info.filter[i][j] = value;
189 sum += value;
190 }
191 loop_restoration_info_[plane][unit_id].wiener_info.filter[i][3] =
192 128 - 2 * sum;
193 loop_restoration_info_[plane][unit_id]
194 .wiener_info.number_leading_zero_coefficients[i] =
195 CountLeadingZeroCoefficients(
196 loop_restoration_info_[plane][unit_id].wiener_info.filter[i]);
197 }
198 }
199
ReadSgrProjInfo(DaalaBitReader * const reader,Plane plane,int unit_id,std::array<RestorationUnitInfo,kMaxPlanes> * const reference_unit_info)200 void LoopRestorationInfo::ReadSgrProjInfo(
201 DaalaBitReader* const reader, Plane plane, int unit_id,
202 std::array<RestorationUnitInfo, kMaxPlanes>* const reference_unit_info) {
203 const int sgr_proj_index =
204 static_cast<int>(reader->ReadLiteral(kSgrProjParamsBits));
205 loop_restoration_info_[plane][unit_id].sgr_proj_info.index = sgr_proj_index;
206 for (int i = 0; i < 2; ++i) {
207 const uint8_t radius = kSgrProjParams[sgr_proj_index][i * 2];
208 const int8_t multiplier_min = kSgrProjMultiplierMin[i];
209 const int8_t multiplier_max = kSgrProjMultiplierMax[i];
210 int multiplier;
211 if (radius != 0) {
212 if (!reader->DecodeSignedSubexpWithReference(
213 multiplier_min, multiplier_max + 1,
214 (*reference_unit_info)[plane].sgr_proj_info.multiplier[i],
215 kSgrProjReadControl, &multiplier)) {
216 LIBGAV1_DLOG(ERROR,
217 "Error decoding Self-guided filter coefficients: plane "
218 "%d, unit_id %d",
219 static_cast<int>(plane), unit_id);
220 return;
221 }
222 } else {
223 // The range of (*reference_unit_info)[plane].sgr_proj_info.multiplier[0]
224 // from DecodeSignedSubexpWithReference() is [-96, 31], the default is
225 // -32, making Clip3(128 - 31, -32, 95) unnecessary.
226 static constexpr int kMultiplier[2] = {0, 95};
227 multiplier = kMultiplier[i];
228 assert(
229 i == 0 ||
230 Clip3((1 << kSgrProjPrecisionBits) -
231 (*reference_unit_info)[plane].sgr_proj_info.multiplier[0],
232 multiplier_min, multiplier_max) == kMultiplier[1]);
233 }
234 loop_restoration_info_[plane][unit_id].sgr_proj_info.multiplier[i] =
235 multiplier;
236 (*reference_unit_info)[plane].sgr_proj_info.multiplier[i] = multiplier;
237 }
238 }
239
240 } // namespace libgav1
241