| /* |
| * 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. |
| */ |
| |
| #ifndef LIBGAV1_SRC_POST_FILTER_H_ |
| #define LIBGAV1_SRC_POST_FILTER_H_ |
| |
| #include <algorithm> |
| #include <array> |
| #include <atomic> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <type_traits> |
| |
| #include "src/dsp/common.h" |
| #include "src/dsp/dsp.h" |
| #include "src/frame_scratch_buffer.h" |
| #include "src/loop_restoration_info.h" |
| #include "src/obu_parser.h" |
| #include "src/utils/array_2d.h" |
| #include "src/utils/block_parameters_holder.h" |
| #include "src/utils/common.h" |
| #include "src/utils/constants.h" |
| #include "src/utils/memory.h" |
| #include "src/utils/threadpool.h" |
| #include "src/yuv_buffer.h" |
| |
| namespace libgav1 { |
| |
| // This class applies in-loop filtering for each frame after it is |
| // reconstructed. The in-loop filtering contains all post processing filtering |
| // for the reconstructed frame, including deblock filter, CDEF, superres, |
| // and loop restoration. |
| // Historically, for example in libaom, loop filter refers to deblock filter. |
| // To avoid name conflicts, we call this class PostFilter (post processing). |
| // In-loop post filtering order is: |
| // deblock --> CDEF --> super resolution--> loop restoration. |
| // When CDEF and super resolution is not used, we can combine deblock |
| // and restoration together to only filter frame buffer once. |
| class PostFilter { |
| public: |
| // This class does not take ownership of the masks/restoration_info, but it |
| // may change their values. |
| // |
| // The overall flow of data in this class (for both single and multi-threaded |
| // cases) is as follows: |
| // -> Input: |frame_buffer_|. |
| // -> Initialize |source_buffer_|, |cdef_buffer_| and |
| // |loop_restoration_buffer_|. |
| // -> Deblocking: |
| // * Input: |source_buffer_| |
| // * Output: |source_buffer_| |
| // -> CDEF: |
| // * Input: |source_buffer_| |
| // * Output: |cdef_buffer_| |
| // -> SuperRes: |
| // * Input: |cdef_buffer_| |
| // * Output: |cdef_buffer_| |
| // -> Loop Restoration: |
| // * Input: |cdef_buffer_| |
| // * Output: |loop_restoration_buffer_|. |
| // -> Now |frame_buffer_| contains the filtered frame. |
| PostFilter(const ObuFrameHeader& frame_header, |
| const ObuSequenceHeader& sequence_header, |
| FrameScratchBuffer* frame_scratch_buffer, YuvBuffer* frame_buffer, |
| const dsp::Dsp* dsp, int do_post_filter_mask); |
| |
| // non copyable/movable. |
| PostFilter(const PostFilter&) = delete; |
| PostFilter& operator=(const PostFilter&) = delete; |
| PostFilter(PostFilter&&) = delete; |
| PostFilter& operator=(PostFilter&&) = delete; |
| |
| // The overall function that applies all post processing filtering with |
| // multiple threads. |
| // * The filtering order is: |
| // deblock --> CDEF --> super resolution--> loop restoration. |
| // * The output of each filter is the input for the following filter. A |
| // special case is that loop restoration needs a few rows of the deblocked |
| // frame and the entire cdef filtered frame: |
| // deblock --> CDEF --> super resolution --> loop restoration. |
| // | ^ |
| // | | |
| // -----------> super resolution ----- |
| // * Any of these filters could be present or absent. |
| // * |frame_buffer_| points to the decoded frame buffer. When |
| // ApplyFilteringThreaded() is called, |frame_buffer_| is modified by each |
| // of the filters as described below. |
| // Filter behavior (multi-threaded): |
| // * Deblock: In-place filtering. The output is written to |source_buffer_|. |
| // If cdef and loop restoration are both on, then 4 rows (as |
| // specified by |kDeblockedRowsForLoopRestoration|) in every 64x64 |
| // block is copied into |deblock_buffer_|. |
| // * Cdef: Filtering output is written into |threaded_window_buffer_| and then |
| // copied into the |cdef_buffer_| (which is just |source_buffer_| with |
| // a shift to the top-left). |
| // * SuperRes: Near in-place filtering (with an additional line buffer for |
| // each row). The output is written to |cdef_buffer_|. |
| // * Restoration: Uses the |cdef_buffer_| and |deblock_buffer_| as the input |
| // and the output is written into the |
| // |threaded_window_buffer_|. It is then copied to the |
| // |loop_restoration_buffer_| (which is just |cdef_buffer_| |
| // with a shift to the top-left). |
| void ApplyFilteringThreaded(); |
| |
| // Does the overall post processing filter for one superblock row starting at |
| // |row4x4| with height 4*|sb4x4|. If |do_deblock| is false, deblocking filter |
| // will not be applied. |
| // |
| // Filter behavior (single-threaded): |
| // * Deblock: In-place filtering. The output is written to |source_buffer_|. |
| // If cdef and loop restoration are both on, then 4 rows (as |
| // specified by |kDeblockedRowsForLoopRestoration|) in every 64x64 |
| // block is copied into |deblock_buffer_|. |
| // * Cdef: In-place filtering. The output is written into |cdef_buffer_| |
| // (which is just |source_buffer_| with a shift to the top-left). |
| // * SuperRes: Near in-place filtering (with an additional line buffer for |
| // each row). The output is written to |cdef_buffer_|. |
| // * Restoration: Near in-place filtering. Uses a local block of size 64x64. |
| // Uses the |cdef_buffer_| and |deblock_buffer_| as the input |
| // and the output is written into |loop_restoration_buffer_| |
| // (which is just |source_buffer_| with a shift to the |
| // top-left). |
| // Returns the index of the last row whose post processing is complete and can |
| // be used for referencing. |
| int ApplyFilteringForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row, |
| bool do_deblock); |
| |
| // Apply deblocking filter in one direction (specified by |loop_filter_type|) |
| // for the superblock row starting at |row4x4_start| for columns starting from |
| // |column4x4_start| in increments of 16 (or 8 for chroma with subsampling) |
| // until the smallest multiple of 16 that is >= |column4x4_end| or until |
| // |frame_header_.columns4x4|, whichever is lower. This function must be |
| // called only if |DoDeblock()| returns true. |
| void ApplyDeblockFilter(LoopFilterType loop_filter_type, int row4x4_start, |
| int column4x4_start, int column4x4_end, int sb4x4); |
| |
| static bool DoCdef(const ObuFrameHeader& frame_header, |
| int do_post_filter_mask) { |
| return (frame_header.cdef.bits > 0 || |
| frame_header.cdef.y_primary_strength[0] > 0 || |
| frame_header.cdef.y_secondary_strength[0] > 0 || |
| frame_header.cdef.uv_primary_strength[0] > 0 || |
| frame_header.cdef.uv_secondary_strength[0] > 0) && |
| (do_post_filter_mask & 0x02) != 0; |
| } |
| bool DoCdef() const { return DoCdef(frame_header_, do_post_filter_mask_); } |
| // If filter levels for Y plane (0 for vertical, 1 for horizontal), |
| // are all zero, deblock filter will not be applied. |
| static bool DoDeblock(const ObuFrameHeader& frame_header, |
| uint8_t do_post_filter_mask) { |
| return (frame_header.loop_filter.level[0] > 0 || |
| frame_header.loop_filter.level[1] > 0) && |
| (do_post_filter_mask & 0x01) != 0; |
| } |
| bool DoDeblock() const { |
| return DoDeblock(frame_header_, do_post_filter_mask_); |
| } |
| |
| // This function takes the cdef filtered buffer and the deblocked buffer to |
| // prepare a block as input for loop restoration. |
| // In striped loop restoration: |
| // The filtering needs to fetch the area of size (width + 6) x (height + 4), |
| // in which (width + 6) x height area is from upscaled frame |
| // (superres_buffer). Top 2 rows and bottom 2 rows are from deblocked frame |
| // (deblock_buffer). Special cases are: (1). when it is the top border, the |
| // top 2 rows are from cdef filtered frame. (2). when it is the bottom border, |
| // the bottom 2 rows are from cdef filtered frame. This function is called |
| // only when cdef is applied for this frame. |
| template <typename Pixel> |
| static void PrepareLoopRestorationBlock(const Pixel* src_buffer, |
| ptrdiff_t src_stride, |
| const Pixel* deblock_buffer, |
| ptrdiff_t deblock_stride, Pixel* dst, |
| ptrdiff_t dst_stride, int width, |
| int height, bool frame_top_border, |
| bool frame_bottom_border); |
| |
| uint8_t GetZeroDeltaDeblockFilterLevel(int segment_id, int level_index, |
| ReferenceFrameType type, |
| int mode_id) const { |
| return deblock_filter_levels_[segment_id][level_index][type][mode_id]; |
| } |
| // Computes the deblock filter levels using |delta_lf| and stores them in |
| // |deblock_filter_levels|. |
| void ComputeDeblockFilterLevels( |
| const int8_t delta_lf[kFrameLfCount], |
| uint8_t deblock_filter_levels[kMaxSegments][kFrameLfCount] |
| [kNumReferenceFrameTypes][2]) const; |
| // Returns true if loop restoration will be performed for the given parameters |
| // and mask. |
| static bool DoRestoration(const LoopRestoration& loop_restoration, |
| uint8_t do_post_filter_mask, int num_planes) { |
| if (num_planes == kMaxPlanesMonochrome) { |
| return loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone && |
| (do_post_filter_mask & 0x08) != 0; |
| } |
| return (loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone || |
| loop_restoration.type[kPlaneU] != kLoopRestorationTypeNone || |
| loop_restoration.type[kPlaneV] != kLoopRestorationTypeNone) && |
| (do_post_filter_mask & 0x08) != 0; |
| } |
| bool DoRestoration() const { |
| return DoRestoration(loop_restoration_, do_post_filter_mask_, planes_); |
| } |
| |
| // Returns a pointer to the unfiltered buffer. This is used by the Tile class |
| // to determine where to write the output of the tile decoding process taking |
| // in-place filtering offsets into consideration. |
| uint8_t* GetUnfilteredBuffer(int plane) { return source_buffer_[plane]; } |
| const YuvBuffer& frame_buffer() const { return frame_buffer_; } |
| |
| // Returns true if SuperRes will be performed for the given frame header and |
| // mask. |
| static bool DoSuperRes(const ObuFrameHeader& frame_header, |
| uint8_t do_post_filter_mask) { |
| return frame_header.width != frame_header.upscaled_width && |
| (do_post_filter_mask & 0x04) != 0; |
| } |
| bool DoSuperRes() const { |
| return DoSuperRes(frame_header_, do_post_filter_mask_); |
| } |
| LoopRestorationInfo* restoration_info() const { return restoration_info_; } |
| uint8_t* GetBufferOffset(uint8_t* base_buffer, int stride, Plane plane, |
| int row4x4, int column4x4) const { |
| return base_buffer + |
| RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_[plane]) * |
| stride + |
| RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_[plane]) * |
| pixel_size_; |
| } |
| uint8_t* GetSourceBuffer(Plane plane, int row4x4, int column4x4) const { |
| return GetBufferOffset(source_buffer_[plane], frame_buffer_.stride(plane), |
| plane, row4x4, column4x4); |
| } |
| |
| static int GetWindowBufferWidth(const ThreadPool* const thread_pool, |
| const ObuFrameHeader& frame_header) { |
| return (thread_pool == nullptr) ? 0 |
| : Align(frame_header.upscaled_width, 64); |
| } |
| |
| // For multi-threaded cdef and loop restoration, window height is the minimum |
| // of the following two quantities: |
| // 1) thread_count * 64 |
| // 2) frame_height rounded up to the nearest power of 64 |
| // Where 64 is the block size for cdef and loop restoration. |
| static int GetWindowBufferHeight(const ThreadPool* const thread_pool, |
| const ObuFrameHeader& frame_header) { |
| if (thread_pool == nullptr) return 0; |
| const int thread_count = 1 + thread_pool->num_threads(); |
| const int window_height = MultiplyBy64(thread_count); |
| const int adjusted_frame_height = Align(frame_header.height, 64); |
| return std::min(adjusted_frame_height, window_height); |
| } |
| |
| template <typename Pixel> |
| static void ExtendFrame(Pixel* frame_start, int width, int height, |
| ptrdiff_t stride, int left, int right, int top, |
| int bottom); |
| |
| private: |
| // The type of the HorizontalDeblockFilter and VerticalDeblockFilter member |
| // functions. |
| using DeblockFilter = void (PostFilter::*)(int row4x4_start, |
| int column4x4_start); |
| // The lookup table for picking the deblock filter, according to deblock |
| // filter type. |
| const DeblockFilter deblock_filter_func_[2] = { |
| &PostFilter::VerticalDeblockFilter, &PostFilter::HorizontalDeblockFilter}; |
| |
| // Functions common to all post filters. |
| |
| // Extends the frame by setting the border pixel values to the one from its |
| // closest frame boundary. |
| void ExtendFrameBoundary(uint8_t* frame_start, int width, int height, |
| ptrdiff_t stride, int left, int right, int top, |
| int bottom) const; |
| // Extend frame boundary for referencing if the frame will be saved as a |
| // reference frame. |
| void ExtendBordersForReferenceFrame(); |
| // Copies the deblocked pixels needed for loop restoration. |
| void CopyDeblockedPixels(Plane plane, int row4x4); |
| // Copies the border for one superblock row. If |for_loop_restoration| is |
| // true, then it assumes that the border extension is being performed for the |
| // input of the loop restoration process. If |for_loop_restoration| is false, |
| // then it assumes that the border extension is being performed for using the |
| // current frame as a reference frame. In this case, |progress_row_| is also |
| // updated. |
| void CopyBordersForOneSuperBlockRow(int row4x4, int sb4x4, |
| bool for_loop_restoration); |
| // Sets up the |deblock_buffer_| for loop restoration. |
| void SetupDeblockBuffer(int row4x4_start, int sb4x4); |
| // Returns true if we can perform border extension in loop (i.e.) without |
| // waiting until the entire frame is decoded. If intra_block_copy is true, we |
| // do in-loop border extension only if the upscaled_width is the same as 4 * |
| // columns4x4. Otherwise, we cannot do in loop border extension since those |
| // pixels may be used by intra block copy. |
| bool DoBorderExtensionInLoop() const { |
| return !frame_header_.allow_intrabc || |
| frame_header_.upscaled_width == |
| MultiplyBy4(frame_header_.columns4x4); |
| } |
| template <typename Pixel> |
| void CopyPlane(const Pixel* src, ptrdiff_t src_stride, int width, int height, |
| Pixel* dst, ptrdiff_t dst_stride) { |
| for (int y = 0; y < height; ++y) { |
| memcpy(dst, src, width * sizeof(Pixel)); |
| src += src_stride; |
| dst += dst_stride; |
| } |
| } |
| |
| // Functions for the Deblocking filter. |
| |
| static int GetIndex(int row4x4) { return DivideBy4(row4x4); } |
| static int GetShift(int row4x4, int column4x4) { |
| return ((row4x4 & 3) << 4) | column4x4; |
| } |
| int GetDeblockUnitId(int row_unit, int column_unit) const { |
| return row_unit * num_64x64_blocks_per_row_ + column_unit; |
| } |
| bool GetHorizontalDeblockFilterEdgeInfo(int row4x4, int column4x4, |
| uint8_t* level, int* step, |
| int* filter_length) const; |
| void GetHorizontalDeblockFilterEdgeInfoUV(int row4x4, int column4x4, |
| uint8_t* level_u, uint8_t* level_v, |
| int* step, |
| int* filter_length) const; |
| bool GetVerticalDeblockFilterEdgeInfo(int row4x4, int column4x4, |
| BlockParameters* const* bp_ptr, |
| uint8_t* level, int* step, |
| int* filter_length) const; |
| void GetVerticalDeblockFilterEdgeInfoUV(int column4x4, |
| BlockParameters* const* bp_ptr, |
| uint8_t* level_u, uint8_t* level_v, |
| int* step, int* filter_length) const; |
| void HorizontalDeblockFilter(int row4x4_start, int column4x4_start); |
| void VerticalDeblockFilter(int row4x4_start, int column4x4_start); |
| // HorizontalDeblockFilter and VerticalDeblockFilter must have the correct |
| // signature. |
| static_assert(std::is_same<decltype(&PostFilter::HorizontalDeblockFilter), |
| DeblockFilter>::value, |
| ""); |
| static_assert(std::is_same<decltype(&PostFilter::VerticalDeblockFilter), |
| DeblockFilter>::value, |
| ""); |
| // Applies deblock filtering for the superblock row starting at |row4x4| with |
| // a height of 4*|sb4x4|. |
| void ApplyDeblockFilterForOneSuperBlockRow(int row4x4, int sb4x4); |
| void DeblockFilterWorker(int jobs_per_plane, const Plane* planes, |
| int num_planes, std::atomic<int>* job_counter, |
| DeblockFilter deblock_filter); |
| void ApplyDeblockFilterThreaded(); |
| |
| // Functions for the cdef filter. |
| |
| uint8_t* GetCdefBufferAndStride(int start_x, int start_y, int plane, |
| int window_buffer_plane_size, |
| int* cdef_stride) const; |
| // This function prepares the input source block for cdef filtering. The input |
| // source block contains a 12x12 block, with the inner 8x8 as the desired |
| // filter region. It pads the block if the 12x12 block includes out of frame |
| // pixels with a large value. This achieves the required behavior defined in |
| // section 5.11.52 of the spec. |
| template <typename Pixel> |
| void PrepareCdefBlock(int block_width4x4, int block_height4x4, int row4x4, |
| int column4x4, uint16_t* cdef_source, |
| ptrdiff_t cdef_stride, bool y_plane); |
| template <typename Pixel> |
| void ApplyCdefForOneUnit(uint16_t* cdef_block, int index, int block_width4x4, |
| int block_height4x4, int row4x4_start, |
| int column4x4_start); |
| // Helper function used by ApplyCdefForOneSuperBlockRow to avoid some code |
| // duplication. |
| void ApplyCdefForOneSuperBlockRowHelper(int row4x4, int block_height4x4); |
| // Applies cdef filtering for the superblock row starting at |row4x4| with a |
| // height of 4*|sb4x4|. |
| void ApplyCdefForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row); |
| template <typename Pixel> |
| void ApplyCdefForOneRowInWindow(int row, int column); |
| template <typename Pixel> |
| void ApplyCdefThreaded(); |
| void ApplyCdef(); // Sections 7.15 and 7.15.1. |
| |
| // Functions for the SuperRes filter. |
| |
| // Applies super resolution for the |buffers| for |rows[plane]| rows of each |
| // plane. If |in_place| is true, the line buffer will not be used and the |
| // SuperRes output will be written to a row above the input row. If |in_place| |
| // is false, the line buffer will be used to store a copy of the input and the |
| // output will be written to the same row as the input row. |
| template <bool in_place> |
| void ApplySuperRes(const std::array<uint8_t*, kMaxPlanes>& buffers, |
| const std::array<int, kMaxPlanes>& strides, |
| const std::array<int, kMaxPlanes>& rows, |
| size_t line_buffer_offset); // Section 7.16. |
| // Applies SuperRes for the superblock row starting at |row4x4| with a height |
| // of 4*|sb4x4|. |
| void ApplySuperResForOneSuperBlockRow(int row4x4, int sb4x4, |
| bool is_last_row); |
| void ApplySuperResThreaded(); |
| |
| // Functions for the Loop Restoration filter. |
| |
| template <typename Pixel> |
| void ApplyLoopRestorationForOneRowInWindow( |
| const Pixel* src_buffer, Plane plane, int plane_height, int plane_width, |
| int y, int x, int row, int unit_row, int current_process_unit_height, |
| int plane_unit_size, int window_width, |
| Array2DView<Pixel>* loop_restored_window); |
| // Applies loop restoration for the superblock row starting at |row4x4_start| |
| // with a height of 4*|sb4x4|. |
| template <typename Pixel> |
| void ApplyLoopRestorationSingleThread(int row4x4_start, int sb4x4); |
| void ApplyLoopRestoration(int row4x4_start, int sb4x4); |
| template <typename Pixel> |
| void ApplyLoopRestorationThreaded(); |
| // Note for ApplyLoopRestoration(): |
| // First, we must differentiate loop restoration processing unit from loop |
| // restoration unit. |
| // (1). Loop restoration processing unit size is default to 64x64. |
| // Only when the remaining filtering area is smaller than 64x64, the |
| // processing unit size is the actual area size. |
| // For U/V plane, it is (64 >> subsampling_x) x (64 >> subsampling_y). |
| // (2). Loop restoration unit size can be 64x64, 128x128, 256x256 for Y |
| // plane. The unit size for chroma can be the same or half, depending on |
| // subsampling. If either subsampling_x or subsampling_y is one, unit size |
| // is halved on both x and y sides. |
| // All loop restoration units have the same size for one plane. |
| // One loop restoration unit could contain multiple processing units. |
| // But they share the same sets of loop restoration parameters. |
| // (3). Loop restoration has a row offset, kRestorationUnitOffset = 8. The |
| // size of first row of loop restoration units and processing units is |
| // shrunk by the offset. |
| // (4). Loop restoration units wrap the bottom and the right of the frame, |
| // if the remaining area is small. The criteria is whether the number of |
| // remaining rows/columns is smaller than half of loop restoration unit |
| // size. |
| // For example, if the frame size is 140x140, loop restoration unit size is |
| // 128x128. The size of the first loop restoration unit is 128x(128-8) = |
| // 128 columns x 120 rows. |
| // Since 140 - 120 < 128/2. The remaining 20 rows will be folded to the loop |
| // restoration unit. Similarly, the remaining 12 columns will also be folded |
| // to current loop restoration unit. So, even frame size is 140x140, |
| // there's only one loop restoration unit. Suppose processing unit is 64x64, |
| // then sizes of the first row of processing units are 64x56, 64x56, 12x56, |
| // respectively. The second row is 64x64, 64x64, 12x64. |
| // The third row is 64x20, 64x20, 12x20. |
| void ApplyLoopRestoration(); |
| |
| const ObuFrameHeader& frame_header_; |
| const LoopRestoration& loop_restoration_; |
| const dsp::Dsp& dsp_; |
| const int num_64x64_blocks_per_row_; |
| const int upscaled_width_; |
| const int width_; |
| const int height_; |
| const int8_t bitdepth_; |
| const int8_t subsampling_x_[kMaxPlanes]; |
| const int8_t subsampling_y_[kMaxPlanes]; |
| const int8_t planes_; |
| const int pixel_size_; |
| const uint8_t* const inner_thresh_; |
| const uint8_t* const outer_thresh_; |
| const bool needs_chroma_deblock_; |
| // This stores the deblocking filter levels assuming that the delta is zero. |
| // This will be used by all superblocks whose delta is zero (without having to |
| // recompute them). The dimensions (in order) are: segment_id, level_index |
| // (based on plane and direction), reference_frame and mode_id. |
| uint8_t deblock_filter_levels_[kMaxSegments][kFrameLfCount] |
| [kNumReferenceFrameTypes][2]; |
| // Stores the SuperRes info for the frame. |
| struct { |
| int upscaled_width; |
| int initial_subpixel_x; |
| int step; |
| } super_res_info_[kMaxPlanes]; |
| const Array2D<int16_t>& cdef_index_; |
| const Array2D<TransformSize>& inter_transform_sizes_; |
| // Pointer to the data buffer used for multi-threaded cdef or loop |
| // restoration. The size of this buffer must be at least |
| // |window_buffer_width_| * |window_buffer_height_| * |pixel_size_|. |
| // Or |planes_| times that for multi-threaded cdef. |
| // If |thread_pool_| is nullptr, then this buffer is not used and can be |
| // nullptr as well. |
| uint8_t* const threaded_window_buffer_; |
| LoopRestorationInfo* const restoration_info_; |
| // Pointer to the line buffer used by ApplySuperRes(). If SuperRes is on, then |
| // the buffer will be large enough to hold one downscaled row + |
| // 2 * kSuperResHorizontalBorder + kSuperResHorizontalPadding. |
| uint8_t* const superres_line_buffer_; |
| const BlockParametersHolder& block_parameters_; |
| // Frame buffer to hold cdef filtered frame. |
| YuvBuffer cdef_filtered_buffer_; |
| // Input frame buffer. |
| YuvBuffer& frame_buffer_; |
| // A view into |frame_buffer_| that points to the input and output of the |
| // deblocking process. |
| uint8_t* source_buffer_[kMaxPlanes]; |
| // A view into |frame_buffer_| that points to the output of the CDEF filtered |
| // planes (to facilitate in-place CDEF filtering). |
| uint8_t* cdef_buffer_[kMaxPlanes]; |
| // A view into |frame_buffer_| that points to the planes after the SuperRes |
| // filter is applied (to facilitate in-place SuperRes). |
| uint8_t* superres_buffer_[kMaxPlanes]; |
| // A view into |frame_buffer_| that points to the output of the Loop Restored |
| // planes (to facilitate in-place Loop Restoration). |
| uint8_t* loop_restoration_buffer_[kMaxPlanes]; |
| // Buffer used to store the deblocked pixels that are necessary for loop |
| // restoration. This buffer will store 4 rows for every 64x64 block (4 rows |
| // for every 32x32 for chroma with subsampling). The indices of the rows that |
| // are stored are specified in |kDeblockedRowsForLoopRestoration|. First 4 |
| // rows of this buffer are never populated and never used. |
| // This buffer is used only when both Cdef and Loop Restoration are on. |
| YuvBuffer& deblock_buffer_; |
| const uint8_t do_post_filter_mask_; |
| ThreadPool* const thread_pool_; |
| const int window_buffer_width_; |
| const int window_buffer_height_; |
| |
| // Tracks the progress of the post filters. |
| int progress_row_ = -1; |
| |
| // A block buffer to hold the input that is converted to uint16_t before |
| // cdef filtering. Only used in single threaded case. |
| uint16_t cdef_block_[kCdefUnitSizeWithBorders * kCdefUnitSizeWithBorders * 3]; |
| |
| template <int bitdepth, typename Pixel> |
| friend class PostFilterSuperResTest; |
| |
| template <int bitdepth, typename Pixel> |
| friend class PostFilterHelperFuncTest; |
| }; |
| |
| extern template void PostFilter::ExtendFrame<uint8_t>(uint8_t* frame_start, |
| int width, int height, |
| ptrdiff_t stride, |
| int left, int right, |
| int top, int bottom); |
| extern template void PostFilter::PrepareLoopRestorationBlock<uint8_t>( |
| const uint8_t* src_buffer, ptrdiff_t src_stride, |
| const uint8_t* deblock_buffer, ptrdiff_t deblock_stride, uint8_t* dst, |
| ptrdiff_t dst_stride, const int width, const int height, |
| const bool frame_top_border, const bool frame_bottom_border); |
| |
| #if LIBGAV1_MAX_BITDEPTH >= 10 |
| extern template void PostFilter::ExtendFrame<uint16_t>(uint16_t* frame_start, |
| int width, int height, |
| ptrdiff_t stride, |
| int left, int right, |
| int top, int bottom); |
| extern template void PostFilter::PrepareLoopRestorationBlock<uint16_t>( |
| const uint16_t* src_buffer, ptrdiff_t src_stride, |
| const uint16_t* deblock_buffer, ptrdiff_t deblock_stride, uint16_t* dst, |
| ptrdiff_t dst_stride, const int width, const int height, |
| const bool frame_top_border, const bool frame_bottom_border); |
| #endif |
| |
| } // namespace libgav1 |
| |
| #endif // LIBGAV1_SRC_POST_FILTER_H_ |