aboutsummaryrefslogtreecommitdiff
path: root/src/reconstruction.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/reconstruction.cc')
-rw-r--r--src/reconstruction.cc190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/reconstruction.cc b/src/reconstruction.cc
new file mode 100644
index 0000000..1aa1233
--- /dev/null
+++ b/src/reconstruction.cc
@@ -0,0 +1,190 @@
+// Copyright 2019 The libgav1 Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/reconstruction.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+#include "src/utils/common.h"
+
+namespace libgav1 {
+namespace {
+
+// Maps TransformType to dsp::Transform1D for the row transforms.
+constexpr dsp::Transform1D kRowTransform[kNumTransformTypes] = {
+ dsp::k1DTransformDct, dsp::k1DTransformAdst,
+ dsp::k1DTransformDct, dsp::k1DTransformAdst,
+ dsp::k1DTransformAdst, dsp::k1DTransformDct,
+ dsp::k1DTransformAdst, dsp::k1DTransformAdst,
+ dsp::k1DTransformAdst, dsp::k1DTransformIdentity,
+ dsp::k1DTransformIdentity, dsp::k1DTransformDct,
+ dsp::k1DTransformIdentity, dsp::k1DTransformAdst,
+ dsp::k1DTransformIdentity, dsp::k1DTransformAdst};
+
+// Maps TransformType to dsp::Transform1D for the column transforms.
+constexpr dsp::Transform1D kColumnTransform[kNumTransformTypes] = {
+ dsp::k1DTransformDct, dsp::k1DTransformDct,
+ dsp::k1DTransformAdst, dsp::k1DTransformAdst,
+ dsp::k1DTransformDct, dsp::k1DTransformAdst,
+ dsp::k1DTransformAdst, dsp::k1DTransformAdst,
+ dsp::k1DTransformAdst, dsp::k1DTransformIdentity,
+ dsp::k1DTransformDct, dsp::k1DTransformIdentity,
+ dsp::k1DTransformAdst, dsp::k1DTransformIdentity,
+ dsp::k1DTransformAdst, dsp::k1DTransformIdentity};
+
+dsp::TransformSize1D Get1DTransformSize(int size_log2) {
+ return static_cast<dsp::TransformSize1D>(size_log2 - 2);
+}
+
+// Returns the number of rows to process based on |non_zero_coeff_count|. The
+// transform loops process either 4 or a multiple of 8 rows. Use the
+// TransformClass derived from |tx_type| to determine the scan order.
+template <int tx_width>
+int GetNumRows(TransformType tx_type, int tx_height, int non_zero_coeff_count) {
+ const TransformClass tx_class = GetTransformClass(tx_type);
+
+ switch (tx_class) {
+ case kTransformClass2D:
+ if (tx_width == 4) {
+ if (non_zero_coeff_count <= 13) return 4;
+ if (non_zero_coeff_count <= 29) return 8;
+ }
+ if (tx_width == 8) {
+ if (non_zero_coeff_count <= 10) return 4;
+ if ((non_zero_coeff_count <= 14) & (tx_height > 8)) return 4;
+ if (non_zero_coeff_count <= 43) return 8;
+ if ((non_zero_coeff_count <= 107) & (tx_height > 16)) return 16;
+ if ((non_zero_coeff_count <= 171) & (tx_height > 16)) return 24;
+ }
+ if (tx_width == 16) {
+ if (non_zero_coeff_count <= 10) return 4;
+ if ((non_zero_coeff_count <= 14) & (tx_height > 16)) return 4;
+ if (non_zero_coeff_count <= 36) return 8;
+ if ((non_zero_coeff_count <= 44) & (tx_height > 16)) return 8;
+ if ((non_zero_coeff_count <= 151) & (tx_height > 16)) return 16;
+ if ((non_zero_coeff_count <= 279) & (tx_height > 16)) return 24;
+ }
+ if (tx_width == 32) {
+ if (non_zero_coeff_count <= 10) return 4;
+ if (non_zero_coeff_count <= 36) return 8;
+ if ((non_zero_coeff_count <= 136) & (tx_height > 16)) return 16;
+ if ((non_zero_coeff_count <= 300) & (tx_height > 16)) return 24;
+ }
+ break;
+
+ case kTransformClassHorizontal:
+ if (non_zero_coeff_count <= 4) return 4;
+ if (non_zero_coeff_count <= 8) return 8;
+ if ((non_zero_coeff_count <= 16) & (tx_height > 16)) return 16;
+ if ((non_zero_coeff_count <= 24) & (tx_height > 16)) return 24;
+ break;
+
+ default:
+ assert(tx_class == kTransformClassVertical);
+ if (tx_width == 4) {
+ if (non_zero_coeff_count <= 16) return 4;
+ if (non_zero_coeff_count <= 32) return 8;
+ }
+ if (tx_width == 8) {
+ if (non_zero_coeff_count <= 32) return 4;
+ if (non_zero_coeff_count <= 64) return 8;
+ // There's no need to check tx_height since the maximum values for
+ // smaller sizes are: 8x8: 63, 8x16: 127.
+ if (non_zero_coeff_count <= 128) return 16;
+ if (non_zero_coeff_count <= 192) return 24;
+ }
+ if (tx_width == 16) {
+ if (non_zero_coeff_count <= 64) return 4;
+ if (non_zero_coeff_count <= 128) return 8;
+ // There's no need to check tx_height since the maximum values for
+ // smaller sizes are: 16x8: 127, 16x16: 255.
+ if (non_zero_coeff_count <= 256) return 16;
+ if (non_zero_coeff_count <= 384) return 24;
+ }
+ if (tx_width == 32) {
+ if (non_zero_coeff_count <= 128) return 4;
+ if (non_zero_coeff_count <= 256) return 8;
+ // There's no need to check tx_height since the maximum values for
+ // smaller sizes are: 32x8 is 255, 32x16 is 511.
+ if ((non_zero_coeff_count <= 512)) return 16;
+ if ((non_zero_coeff_count <= 768)) return 24;
+ }
+ break;
+ }
+ return (tx_width >= 16) ? std::min(tx_height, 32) : tx_height;
+}
+
+} // namespace
+
+template <typename Residual, typename Pixel>
+void 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) {
+ static_assert(sizeof(Residual) == 2 || sizeof(Residual) == 4, "");
+ const int tx_width_log2 = kTransformWidthLog2[tx_size];
+ const int tx_height_log2 = kTransformHeightLog2[tx_size];
+
+ int tx_height = (non_zero_coeff_count == 1) ? 1 : kTransformHeight[tx_size];
+ if (tx_height > 4) {
+ static constexpr int (*kGetNumRows[])(TransformType tx_type, int tx_height,
+ int non_zero_coeff_count) = {
+ &GetNumRows<4>, &GetNumRows<8>, &GetNumRows<16>, &GetNumRows<32>,
+ &GetNumRows<32>};
+ tx_height = kGetNumRows[tx_width_log2 - 2](tx_type, tx_height,
+ non_zero_coeff_count);
+ }
+ assert(tx_height <= 32);
+
+ // Row transform.
+ const dsp::TransformSize1D row_transform_size =
+ Get1DTransformSize(tx_width_log2);
+ const dsp::Transform1D row_transform =
+ lossless ? dsp::k1DTransformWht : kRowTransform[tx_type];
+ const dsp::InverseTransformAddFunc row_transform_func =
+ dsp.inverse_transforms[row_transform][row_transform_size][dsp::kRow];
+ assert(row_transform_func != nullptr);
+
+ row_transform_func(tx_type, tx_size, tx_height, buffer, start_x, start_y,
+ frame);
+
+ // Column transform.
+ const dsp::TransformSize1D column_transform_size =
+ Get1DTransformSize(tx_height_log2);
+ const dsp::Transform1D column_transform =
+ lossless ? dsp::k1DTransformWht : kColumnTransform[tx_type];
+ const dsp::InverseTransformAddFunc column_transform_func =
+ dsp.inverse_transforms[column_transform][column_transform_size]
+ [dsp::kColumn];
+ assert(column_transform_func != nullptr);
+
+ column_transform_func(tx_type, tx_size, tx_height, buffer, start_x, start_y,
+ frame);
+}
+
+template void Reconstruct(const dsp::Dsp& dsp, TransformType tx_type,
+ TransformSize tx_size, bool lossless, int16_t* buffer,
+ int start_x, int start_y, Array2DView<uint8_t>* frame,
+ int non_zero_coeff_count);
+#if LIBGAV1_MAX_BITDEPTH >= 10
+template void Reconstruct(const dsp::Dsp& dsp, TransformType tx_type,
+ TransformSize tx_size, bool lossless, int32_t* buffer,
+ int start_x, int start_y,
+ Array2DView<uint16_t>* frame,
+ int non_zero_coeff_count);
+#endif
+
+} // namespace libgav1