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/reconstruction.h"
16
17 #include <algorithm>
18 #include <cassert>
19 #include <cstdint>
20
21 #include "src/utils/common.h"
22
23 namespace libgav1 {
24 namespace {
25
26 // Maps TransformType to dsp::Transform1d for the row transforms.
27 constexpr dsp::Transform1d kRowTransform[kNumTransformTypes] = {
28 dsp::kTransform1dDct, dsp::kTransform1dAdst,
29 dsp::kTransform1dDct, dsp::kTransform1dAdst,
30 dsp::kTransform1dAdst, dsp::kTransform1dDct,
31 dsp::kTransform1dAdst, dsp::kTransform1dAdst,
32 dsp::kTransform1dAdst, dsp::kTransform1dIdentity,
33 dsp::kTransform1dIdentity, dsp::kTransform1dDct,
34 dsp::kTransform1dIdentity, dsp::kTransform1dAdst,
35 dsp::kTransform1dIdentity, dsp::kTransform1dAdst};
36
37 // Maps TransformType to dsp::Transform1d for the column transforms.
38 constexpr dsp::Transform1d kColumnTransform[kNumTransformTypes] = {
39 dsp::kTransform1dDct, dsp::kTransform1dDct,
40 dsp::kTransform1dAdst, dsp::kTransform1dAdst,
41 dsp::kTransform1dDct, dsp::kTransform1dAdst,
42 dsp::kTransform1dAdst, dsp::kTransform1dAdst,
43 dsp::kTransform1dAdst, dsp::kTransform1dIdentity,
44 dsp::kTransform1dDct, dsp::kTransform1dIdentity,
45 dsp::kTransform1dAdst, dsp::kTransform1dIdentity,
46 dsp::kTransform1dAdst, dsp::kTransform1dIdentity};
47
GetTransform1dSize(int size_log2)48 dsp::Transform1dSize GetTransform1dSize(int size_log2) {
49 return static_cast<dsp::Transform1dSize>(size_log2 - 2);
50 }
51
52 // Returns the number of rows to process based on |non_zero_coeff_count|. The
53 // transform loops process either 4 or a multiple of 8 rows. Use the
54 // TransformClass derived from |tx_type| to determine the scan order.
55 template <int tx_width>
GetNumRows(TransformType tx_type,int tx_height,int non_zero_coeff_count)56 int GetNumRows(TransformType tx_type, int tx_height, int non_zero_coeff_count) {
57 const TransformClass tx_class = GetTransformClass(tx_type);
58
59 switch (tx_class) {
60 case kTransformClass2D:
61 if (tx_width == 4) {
62 if (non_zero_coeff_count <= 13) return 4;
63 if (non_zero_coeff_count <= 29) return 8;
64 }
65 if (tx_width == 8) {
66 if (non_zero_coeff_count <= 10) return 4;
67 if ((non_zero_coeff_count <= 14) & (tx_height > 8)) return 4;
68 if (non_zero_coeff_count <= 43) return 8;
69 if ((non_zero_coeff_count <= 107) & (tx_height > 16)) return 16;
70 if ((non_zero_coeff_count <= 171) & (tx_height > 16)) return 24;
71 }
72 if (tx_width == 16) {
73 if (non_zero_coeff_count <= 10) return 4;
74 if ((non_zero_coeff_count <= 14) & (tx_height > 16)) return 4;
75 if (non_zero_coeff_count <= 36) return 8;
76 if ((non_zero_coeff_count <= 44) & (tx_height > 16)) return 8;
77 if ((non_zero_coeff_count <= 151) & (tx_height > 16)) return 16;
78 if ((non_zero_coeff_count <= 279) & (tx_height > 16)) return 24;
79 }
80 if (tx_width == 32) {
81 if (non_zero_coeff_count <= 10) return 4;
82 if (non_zero_coeff_count <= 36) return 8;
83 if ((non_zero_coeff_count <= 136) & (tx_height > 16)) return 16;
84 if ((non_zero_coeff_count <= 300) & (tx_height > 16)) return 24;
85 }
86 break;
87
88 case kTransformClassHorizontal:
89 if (non_zero_coeff_count <= 4) return 4;
90 if (non_zero_coeff_count <= 8) return 8;
91 if ((non_zero_coeff_count <= 16) & (tx_height > 16)) return 16;
92 if ((non_zero_coeff_count <= 24) & (tx_height > 16)) return 24;
93 break;
94
95 default:
96 assert(tx_class == kTransformClassVertical);
97 if (tx_width == 4) {
98 if (non_zero_coeff_count <= 16) return 4;
99 if (non_zero_coeff_count <= 32) return 8;
100 }
101 if (tx_width == 8) {
102 if (non_zero_coeff_count <= 32) return 4;
103 if (non_zero_coeff_count <= 64) return 8;
104 // There's no need to check tx_height since the maximum values for
105 // smaller sizes are: 8x8: 63, 8x16: 127.
106 if (non_zero_coeff_count <= 128) return 16;
107 if (non_zero_coeff_count <= 192) return 24;
108 }
109 if (tx_width == 16) {
110 if (non_zero_coeff_count <= 64) return 4;
111 if (non_zero_coeff_count <= 128) return 8;
112 // There's no need to check tx_height since the maximum values for
113 // smaller sizes are: 16x8: 127, 16x16: 255.
114 if (non_zero_coeff_count <= 256) return 16;
115 if (non_zero_coeff_count <= 384) return 24;
116 }
117 if (tx_width == 32) {
118 if (non_zero_coeff_count <= 128) return 4;
119 if (non_zero_coeff_count <= 256) return 8;
120 // There's no need to check tx_height since the maximum values for
121 // smaller sizes are: 32x8 is 255, 32x16 is 511.
122 if ((non_zero_coeff_count <= 512)) return 16;
123 if ((non_zero_coeff_count <= 768)) return 24;
124 }
125 break;
126 }
127 return (tx_width >= 16) ? std::min(tx_height, 32) : tx_height;
128 }
129
130 } // namespace
131
132 template <typename Residual, typename Pixel>
Reconstruct(const dsp::Dsp & dsp,TransformType tx_type,TransformSize tx_size,bool lossless,Residual * const buffer,int start_x,int start_y,Array2DView<Pixel> * frame,int non_zero_coeff_count)133 void Reconstruct(const dsp::Dsp& dsp, TransformType tx_type,
134 TransformSize tx_size, bool lossless, Residual* const buffer,
135 int start_x, int start_y, Array2DView<Pixel>* frame,
136 int non_zero_coeff_count) {
137 static_assert(sizeof(Residual) == 2 || sizeof(Residual) == 4, "");
138 const int tx_width_log2 = kTransformWidthLog2[tx_size];
139 const int tx_height_log2 = kTransformHeightLog2[tx_size];
140
141 int tx_height = (non_zero_coeff_count == 1) ? 1 : kTransformHeight[tx_size];
142 if (tx_height > 4) {
143 static constexpr int (*kGetNumRows[])(TransformType tx_type, int tx_height,
144 int non_zero_coeff_count) = {
145 &GetNumRows<4>, &GetNumRows<8>, &GetNumRows<16>, &GetNumRows<32>,
146 &GetNumRows<32>};
147 tx_height = kGetNumRows[tx_width_log2 - 2](tx_type, tx_height,
148 non_zero_coeff_count);
149 }
150 assert(tx_height <= 32);
151
152 // Row transform.
153 const dsp::Transform1dSize row_transform_size =
154 GetTransform1dSize(tx_width_log2);
155 const dsp::Transform1d row_transform =
156 lossless ? dsp::kTransform1dWht : kRowTransform[tx_type];
157 const dsp::InverseTransformAddFunc row_transform_func =
158 dsp.inverse_transforms[row_transform][row_transform_size][dsp::kRow];
159 assert(row_transform_func != nullptr);
160
161 row_transform_func(tx_type, tx_size, tx_height, buffer, start_x, start_y,
162 frame);
163
164 // Column transform.
165 const dsp::Transform1dSize column_transform_size =
166 GetTransform1dSize(tx_height_log2);
167 const dsp::Transform1d column_transform =
168 lossless ? dsp::kTransform1dWht : kColumnTransform[tx_type];
169 const dsp::InverseTransformAddFunc column_transform_func =
170 dsp.inverse_transforms[column_transform][column_transform_size]
171 [dsp::kColumn];
172 assert(column_transform_func != nullptr);
173
174 column_transform_func(tx_type, tx_size, tx_height, buffer, start_x, start_y,
175 frame);
176 }
177
178 template void Reconstruct(const dsp::Dsp& dsp, TransformType tx_type,
179 TransformSize tx_size, bool lossless, int16_t* buffer,
180 int start_x, int start_y, Array2DView<uint8_t>* frame,
181 int non_zero_coeff_count);
182 #if LIBGAV1_MAX_BITDEPTH >= 10
183 template void Reconstruct(const dsp::Dsp& dsp, TransformType tx_type,
184 TransformSize tx_size, bool lossless, int32_t* buffer,
185 int start_x, int start_y,
186 Array2DView<uint16_t>* frame,
187 int non_zero_coeff_count);
188 #endif
189
190 } // namespace libgav1
191