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