| // 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/dsp/loop_filter.h" |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| |
| #include "src/dsp/dsp.h" |
| #include "src/utils/common.h" |
| |
| namespace libgav1 { |
| namespace dsp { |
| namespace { |
| |
| // 7.14.6.1. |
| template <int bitdepth, typename Pixel> |
| struct LoopFilterFuncs_C { |
| LoopFilterFuncs_C() = delete; |
| |
| static constexpr int kMaxPixel = (1 << bitdepth) - 1; |
| static constexpr int kMinSignedPixel = -(1 << (bitdepth - 1)); |
| static constexpr int kMaxSignedPixel = (1 << (bitdepth - 1)) - 1; |
| static constexpr int kFlatThresh = 1 << (bitdepth - 8); |
| |
| static void Vertical4(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Horizontal4(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Vertical6(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Horizontal6(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Vertical8(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Horizontal8(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Vertical14(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| static void Horizontal14(void* dest, ptrdiff_t stride, int outer_thresh, |
| int inner_thresh, int hev_thresh); |
| }; |
| |
| inline void AdjustThresholds(const int bitdepth, int* const outer_thresh, |
| int* const inner_thresh, int* const hev_thresh) { |
| *outer_thresh <<= bitdepth - 8; |
| *inner_thresh <<= bitdepth - 8; |
| *hev_thresh <<= bitdepth - 8; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // 4-tap filters |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool NeedsFilter4(const Pixel* p, ptrdiff_t step, int outer_thresh, |
| int inner_thresh) { |
| const int p1 = p[-2 * step], p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step]; |
| return std::abs(p1 - p0) <= inner_thresh && |
| std::abs(q1 - q0) <= inner_thresh && |
| std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh; |
| } |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool Hev(const Pixel* p, ptrdiff_t step, int thresh) { |
| const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; |
| return (std::abs(p1 - p0) > thresh) || (std::abs(q1 - q0) > thresh); |
| } |
| |
| // 7.14.6.3. |
| // 4 pixels in, 2 pixels out. |
| template <int bitdepth, typename Pixel> |
| inline void Filter2_C(Pixel* p, ptrdiff_t step) { |
| const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; |
| const int min_signed_val = |
| LoopFilterFuncs_C<bitdepth, Pixel>::kMinSignedPixel; |
| const int max_signed_val = |
| LoopFilterFuncs_C<bitdepth, Pixel>::kMaxSignedPixel; |
| // 8bpp: [-893,892], 10bpp: [-3581,3580], 12bpp [-14333,14332] |
| const int a = 3 * (q0 - p0) + Clip3(p1 - q1, min_signed_val, max_signed_val); |
| // 8bpp: [-16,15], 10bpp: [-64,63], 12bpp: [-256,255] |
| const int a1 = Clip3(a + 4, min_signed_val, max_signed_val) >> 3; |
| const int a2 = Clip3(a + 3, min_signed_val, max_signed_val) >> 3; |
| const int max_unsigned_val = LoopFilterFuncs_C<bitdepth, Pixel>::kMaxPixel; |
| p[-step] = Clip3(p0 + a2, 0, max_unsigned_val); |
| p[0] = Clip3(q0 - a1, 0, max_unsigned_val); |
| } |
| |
| // 7.14.6.3. |
| // 4 pixels in, 4 pixels out. |
| template <int bitdepth, typename Pixel> |
| inline void Filter4_C(Pixel* p, ptrdiff_t step) { |
| const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step]; |
| const int a = 3 * (q0 - p0); |
| const int min_signed_val = |
| LoopFilterFuncs_C<bitdepth, Pixel>::kMinSignedPixel; |
| const int max_signed_val = |
| LoopFilterFuncs_C<bitdepth, Pixel>::kMaxSignedPixel; |
| const int a1 = Clip3(a + 4, min_signed_val, max_signed_val) >> 3; |
| const int a2 = Clip3(a + 3, min_signed_val, max_signed_val) >> 3; |
| const int a3 = (a1 + 1) >> 1; |
| const int max_unsigned_val = LoopFilterFuncs_C<bitdepth, Pixel>::kMaxPixel; |
| p[-2 * step] = Clip3(p1 + a3, 0, max_unsigned_val); |
| p[-1 * step] = Clip3(p0 + a2, 0, max_unsigned_val); |
| p[0 * step] = Clip3(q0 - a1, 0, max_unsigned_val); |
| p[1 * step] = Clip3(q1 - a3, 0, max_unsigned_val); |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical4(void* dest, ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter4(dst, 1, outer_thresh, inner_thresh)) { |
| if (Hev(dst, 1, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, 1); |
| } else { |
| Filter4_C<bitdepth>(dst, 1); |
| } |
| } |
| dst += stride; |
| } |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal4(void* dest, |
| ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter4(dst, stride, outer_thresh, inner_thresh)) { |
| if (Hev(dst, stride, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, stride); |
| } else { |
| Filter4_C<bitdepth>(dst, stride); |
| } |
| } |
| ++dst; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // 5-tap (chroma) filters |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool NeedsFilter6(const Pixel* p, ptrdiff_t step, int outer_thresh, |
| int inner_thresh) { |
| const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step]; |
| return std::abs(p2 - p1) <= inner_thresh && |
| std::abs(p1 - p0) <= inner_thresh && |
| std::abs(q1 - q0) <= inner_thresh && |
| std::abs(q2 - q1) <= inner_thresh && |
| std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh; |
| } |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool IsFlat3(const Pixel* p, ptrdiff_t step, int flat_thresh) { |
| const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step]; |
| return std::abs(p1 - p0) <= flat_thresh && std::abs(q1 - q0) <= flat_thresh && |
| std::abs(p2 - p0) <= flat_thresh && std::abs(q2 - q0) <= flat_thresh; |
| } |
| |
| template <typename Pixel> |
| inline Pixel ApplyFilter6(int filter_value) { |
| return static_cast<Pixel>(RightShiftWithRounding(filter_value, 3)); |
| } |
| |
| // 7.14.6.4. |
| // 6 pixels in, 4 pixels out. |
| template <typename Pixel> |
| inline void Filter6_C(Pixel* p, ptrdiff_t step) { |
| const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step]; |
| const int a1 = 2 * p1; |
| const int a0 = 2 * p0; |
| const int b0 = 2 * q0; |
| const int b1 = 2 * q1; |
| // The max is 8 * max_pixel + 4 for the rounder. |
| // 8bpp: 2044 (11 bits), 10bpp: 8188 (13 bits), 12bpp: 32764 (15 bits) |
| p[-2 * step] = ApplyFilter6<Pixel>(3 * p2 + a1 + a0 + q0); |
| p[-1 * step] = ApplyFilter6<Pixel>(p2 + a1 + a0 + b0 + q1); |
| p[0 * step] = ApplyFilter6<Pixel>(p1 + a0 + b0 + b1 + q2); |
| p[1 * step] = ApplyFilter6<Pixel>(p0 + b0 + b1 + 3 * q2); |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical6(void* dest, ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter6(dst, 1, outer_thresh, inner_thresh)) { |
| if (IsFlat3(dst, 1, flat_thresh)) { |
| Filter6_C(dst, 1); |
| } else if (Hev(dst, 1, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, 1); |
| } else { |
| Filter4_C<bitdepth>(dst, 1); |
| } |
| } |
| dst += stride; |
| } |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal6(void* dest, |
| ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter6(dst, stride, outer_thresh, inner_thresh)) { |
| if (IsFlat3(dst, stride, flat_thresh)) { |
| Filter6_C(dst, stride); |
| } else if (Hev(dst, stride, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, stride); |
| } else { |
| Filter4_C<bitdepth>(dst, stride); |
| } |
| } |
| ++dst; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // 7-tap filters |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool NeedsFilter8(const Pixel* p, ptrdiff_t step, int outer_thresh, |
| int inner_thresh) { |
| const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step], |
| p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step]; |
| return std::abs(p3 - p2) <= inner_thresh && |
| std::abs(p2 - p1) <= inner_thresh && |
| std::abs(p1 - p0) <= inner_thresh && |
| std::abs(q1 - q0) <= inner_thresh && |
| std::abs(q2 - q1) <= inner_thresh && |
| std::abs(q3 - q2) <= inner_thresh && |
| std::abs(p0 - q0) * 2 + std::abs(p1 - q1) / 2 <= outer_thresh; |
| } |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool IsFlat4(const Pixel* p, ptrdiff_t step, int flat_thresh) { |
| const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step], |
| p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step]; |
| return std::abs(p1 - p0) <= flat_thresh && std::abs(q1 - q0) <= flat_thresh && |
| std::abs(p2 - p0) <= flat_thresh && std::abs(q2 - q0) <= flat_thresh && |
| std::abs(p3 - p0) <= flat_thresh && std::abs(q3 - q0) <= flat_thresh; |
| } |
| |
| template <typename Pixel> |
| inline Pixel ApplyFilter8(int filter_value) { |
| return static_cast<Pixel>(RightShiftWithRounding(filter_value, 3)); |
| } |
| |
| // 7.14.6.4. |
| // 8 pixels in, 6 pixels out. |
| template <typename Pixel> |
| inline void Filter8_C(Pixel* p, ptrdiff_t step) { |
| const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step], |
| p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step]; |
| // The max is 8 * max_pixel + 4 for the rounder. |
| // 8bpp: 2044 (11 bits), 10bpp: 8188 (13 bits), 12bpp: 32764 (15 bits) |
| p[-3 * step] = ApplyFilter8<Pixel>(3 * p3 + 2 * p2 + p1 + p0 + q0); |
| p[-2 * step] = ApplyFilter8<Pixel>(2 * p3 + p2 + 2 * p1 + p0 + q0 + q1); |
| p[-1 * step] = ApplyFilter8<Pixel>(p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2); |
| p[0 * step] = ApplyFilter8<Pixel>(p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3); |
| p[1 * step] = ApplyFilter8<Pixel>(p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3); |
| p[2 * step] = ApplyFilter8<Pixel>(p0 + q0 + q1 + 2 * q2 + 3 * q3); |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical8(void* dest, ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter8(dst, 1, outer_thresh, inner_thresh)) { |
| if (IsFlat4(dst, 1, flat_thresh)) { |
| Filter8_C(dst, 1); |
| } else if (Hev(dst, 1, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, 1); |
| } else { |
| Filter4_C<bitdepth>(dst, 1); |
| } |
| } |
| dst += stride; |
| } |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal8(void* dest, |
| ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter8(dst, stride, outer_thresh, inner_thresh)) { |
| if (IsFlat4(dst, stride, flat_thresh)) { |
| Filter8_C(dst, stride); |
| } else if (Hev(dst, stride, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, stride); |
| } else { |
| Filter4_C<bitdepth>(dst, stride); |
| } |
| } |
| ++dst; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // 13-tap filters |
| |
| // 7.14.6.2. |
| template <typename Pixel> |
| inline bool IsFlatOuter4(const Pixel* p, ptrdiff_t step, int flat_thresh) { |
| const int p6 = p[-7 * step], p5 = p[-6 * step], p4 = p[-5 * step], |
| p0 = p[-step]; |
| const int q0 = p[0], q4 = p[4 * step], q5 = p[5 * step], q6 = p[6 * step]; |
| return std::abs(p4 - p0) <= flat_thresh && std::abs(q4 - q0) <= flat_thresh && |
| std::abs(p5 - p0) <= flat_thresh && std::abs(q5 - q0) <= flat_thresh && |
| std::abs(p6 - p0) <= flat_thresh && std::abs(q6 - q0) <= flat_thresh; |
| } |
| |
| template <typename Pixel> |
| inline Pixel ApplyFilter14(int filter_value) { |
| return static_cast<Pixel>(RightShiftWithRounding(filter_value, 4)); |
| } |
| |
| // 7.14.6.4. |
| // 14 pixels in, 12 pixels out. |
| template <typename Pixel> |
| inline void Filter14_C(Pixel* p, ptrdiff_t step) { |
| const int p6 = p[-7 * step], p5 = p[-6 * step], p4 = p[-5 * step], |
| p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step], |
| p0 = p[-step]; |
| const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step], |
| q4 = p[4 * step], q5 = p[5 * step], q6 = p[6 * step]; |
| // The max is 16 * max_pixel + 8 for the rounder. |
| // 8bpp: 4088 (12 bits), 10bpp: 16376 (14 bits), 12bpp: 65528 (16 bits) |
| p[-6 * step] = |
| ApplyFilter14<Pixel>(p6 * 7 + p5 * 2 + p4 * 2 + p3 + p2 + p1 + p0 + q0); |
| p[-5 * step] = ApplyFilter14<Pixel>(p6 * 5 + p5 * 2 + p4 * 2 + p3 * 2 + p2 + |
| p1 + p0 + q0 + q1); |
| p[-4 * step] = ApplyFilter14<Pixel>(p6 * 4 + p5 + p4 * 2 + p3 * 2 + p2 * 2 + |
| p1 + p0 + q0 + q1 + q2); |
| p[-3 * step] = ApplyFilter14<Pixel>(p6 * 3 + p5 + p4 + p3 * 2 + p2 * 2 + |
| p1 * 2 + p0 + q0 + q1 + q2 + q3); |
| p[-2 * step] = ApplyFilter14<Pixel>(p6 * 2 + p5 + p4 + p3 + p2 * 2 + p1 * 2 + |
| p0 * 2 + q0 + q1 + q2 + q3 + q4); |
| p[-1 * step] = ApplyFilter14<Pixel>(p6 + p5 + p4 + p3 + p2 + p1 * 2 + p0 * 2 + |
| q0 * 2 + q1 + q2 + q3 + q4 + q5); |
| p[0 * step] = ApplyFilter14<Pixel>(p5 + p4 + p3 + p2 + p1 + p0 * 2 + q0 * 2 + |
| q1 * 2 + q2 + q3 + q4 + q5 + q6); |
| p[1 * step] = ApplyFilter14<Pixel>(p4 + p3 + p2 + p1 + p0 + q0 * 2 + q1 * 2 + |
| q2 * 2 + q3 + q4 + q5 + q6 * 2); |
| p[2 * step] = ApplyFilter14<Pixel>(p3 + p2 + p1 + p0 + q0 + q1 * 2 + q2 * 2 + |
| q3 * 2 + q4 + q5 + q6 * 3); |
| p[3 * step] = ApplyFilter14<Pixel>(p2 + p1 + p0 + q0 + q1 + q2 * 2 + q3 * 2 + |
| q4 * 2 + q5 + q6 * 4); |
| p[4 * step] = ApplyFilter14<Pixel>(p1 + p0 + q0 + q1 + q2 + q3 * 2 + q4 * 2 + |
| q5 * 2 + q6 * 5); |
| p[5 * step] = |
| ApplyFilter14<Pixel>(p0 + q0 + q1 + q2 + q3 + q4 * 2 + q5 * 2 + q6 * 7); |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Vertical14(void* dest, |
| ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter8(dst, 1, outer_thresh, inner_thresh)) { |
| if (IsFlat4(dst, 1, flat_thresh)) { |
| if (IsFlatOuter4(dst, 1, flat_thresh)) { |
| Filter14_C(dst, 1); |
| } else { |
| Filter8_C(dst, 1); |
| } |
| } else if (Hev(dst, 1, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, 1); |
| } else { |
| Filter4_C<bitdepth>(dst, 1); |
| } |
| } |
| dst += stride; |
| } |
| } |
| |
| template <int bitdepth, typename Pixel> |
| void LoopFilterFuncs_C<bitdepth, Pixel>::Horizontal14(void* dest, |
| ptrdiff_t stride, |
| int outer_thresh, |
| int inner_thresh, |
| int hev_thresh) { |
| const int flat_thresh = LoopFilterFuncs_C<bitdepth, Pixel>::kFlatThresh; |
| AdjustThresholds(bitdepth, &outer_thresh, &inner_thresh, &hev_thresh); |
| auto* dst = static_cast<Pixel*>(dest); |
| stride /= sizeof(Pixel); |
| for (int i = 0; i < 4; ++i) { |
| if (NeedsFilter8(dst, stride, outer_thresh, inner_thresh)) { |
| if (IsFlat4(dst, stride, flat_thresh)) { |
| if (IsFlatOuter4(dst, stride, flat_thresh)) { |
| Filter14_C(dst, stride); |
| } else { |
| Filter8_C(dst, stride); |
| } |
| } else if (Hev(dst, stride, hev_thresh)) { |
| Filter2_C<bitdepth>(dst, stride); |
| } else { |
| Filter4_C<bitdepth>(dst, stride); |
| } |
| } |
| ++dst; |
| } |
| } |
| |
| using Defs8bpp = LoopFilterFuncs_C<8, uint8_t>; |
| |
| void Init8bpp() { |
| Dsp* const dsp = dsp_internal::GetWritableDspTable(8); |
| assert(dsp != nullptr); |
| #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal4; |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical4; |
| |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal6; |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical6; |
| |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal8; |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical8; |
| |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal14; |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical14; |
| #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| static_cast<void>(dsp); |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize4_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal4; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize4_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical4; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize6_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal6; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize6_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical6; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize8_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal8; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize8_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical8; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize14_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] = |
| Defs8bpp::Horizontal14; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_LoopFilterSize14_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] = |
| Defs8bpp::Vertical14; |
| #endif |
| #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| } |
| |
| #if LIBGAV1_MAX_BITDEPTH >= 10 |
| using Defs10bpp = LoopFilterFuncs_C<10, uint16_t>; |
| |
| void Init10bpp() { |
| Dsp* const dsp = dsp_internal::GetWritableDspTable(10); |
| assert(dsp != nullptr); |
| #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal4; |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical4; |
| |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal6; |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical6; |
| |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal8; |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical8; |
| |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal14; |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical14; |
| #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| static_cast<void>(dsp); |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize4_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal4; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize4_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize4][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical4; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize6_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal6; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize6_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize6][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical6; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize8_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal8; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize8_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize8][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical8; |
| #endif |
| |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize14_LoopFilterTypeHorizontal |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeHorizontal] = |
| Defs10bpp::Horizontal14; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_LoopFilterSize14_LoopFilterTypeVertical |
| dsp->loop_filters[kLoopFilterSize14][kLoopFilterTypeVertical] = |
| Defs10bpp::Vertical14; |
| #endif |
| #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| } |
| #endif // LIBGAV1_MAX_BITDEPTH >= 10 |
| |
| } // namespace |
| |
| void LoopFilterInit_C() { |
| Init8bpp(); |
| #if LIBGAV1_MAX_BITDEPTH >= 10 |
| Init10bpp(); |
| #endif |
| // Local functions that may be unused depending on the optimizations |
| // available. |
| static_cast<void>(AdjustThresholds); |
| } |
| |
| } // namespace dsp |
| } // namespace libgav1 |