• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The libgav1 Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef LIBGAV1_SRC_POST_FILTER_H_
18 #define LIBGAV1_SRC_POST_FILTER_H_
19 
20 #include <algorithm>
21 #include <array>
22 #include <atomic>
23 #include <cstddef>
24 #include <cstdint>
25 #include <cstring>
26 #include <type_traits>
27 
28 #include "src/dsp/common.h"
29 #include "src/dsp/dsp.h"
30 #include "src/frame_scratch_buffer.h"
31 #include "src/loop_restoration_info.h"
32 #include "src/obu_parser.h"
33 #include "src/utils/array_2d.h"
34 #include "src/utils/block_parameters_holder.h"
35 #include "src/utils/common.h"
36 #include "src/utils/constants.h"
37 #include "src/utils/memory.h"
38 #include "src/utils/threadpool.h"
39 #include "src/yuv_buffer.h"
40 
41 namespace libgav1 {
42 
43 // This class applies in-loop filtering for each frame after it is
44 // reconstructed. The in-loop filtering contains all post processing filtering
45 // for the reconstructed frame, including deblock filter, CDEF, superres,
46 // and loop restoration.
47 // Historically, for example in libaom, loop filter refers to deblock filter.
48 // To avoid name conflicts, we call this class PostFilter (post processing).
49 // In-loop post filtering order is:
50 // deblock --> CDEF --> super resolution--> loop restoration.
51 // When CDEF and super resolution is not used, we can combine deblock
52 // and restoration together to only filter frame buffer once.
53 class PostFilter {
54  public:
55   // This class does not take ownership of the masks/restoration_info, but it
56   // may change their values.
57   //
58   // The overall flow of data in this class (for both single and multi-threaded
59   // cases) is as follows:
60   //   -> Input: |frame_buffer_|.
61   //   -> Initialize |source_buffer_|, |cdef_buffer_| and
62   //      |loop_restoration_buffer_|.
63   //   -> Deblocking:
64   //      * Input: |source_buffer_|
65   //      * Output: |source_buffer_|
66   //   -> CDEF:
67   //      * Input: |source_buffer_|
68   //      * Output: |cdef_buffer_|
69   //   -> SuperRes:
70   //      * Input: |cdef_buffer_|
71   //      * Output: |cdef_buffer_|
72   //   -> Loop Restoration:
73   //      * Input: |cdef_buffer_|
74   //      * Output: |loop_restoration_buffer_|.
75   //   -> Now |frame_buffer_| contains the filtered frame.
76   PostFilter(const ObuFrameHeader& frame_header,
77              const ObuSequenceHeader& sequence_header,
78              FrameScratchBuffer* frame_scratch_buffer, YuvBuffer* frame_buffer,
79              const dsp::Dsp* dsp, int do_post_filter_mask);
80 
81   // non copyable/movable.
82   PostFilter(const PostFilter&) = delete;
83   PostFilter& operator=(const PostFilter&) = delete;
84   PostFilter(PostFilter&&) = delete;
85   PostFilter& operator=(PostFilter&&) = delete;
86 
87   // The overall function that applies all post processing filtering with
88   // multiple threads.
89   // * The filtering order is:
90   //   deblock --> CDEF --> super resolution--> loop restoration.
91   // * The output of each filter is the input for the following filter. A
92   //   special case is that loop restoration needs a few rows of the deblocked
93   //   frame and the entire cdef filtered frame:
94   //   deblock --> CDEF --> super resolution --> loop restoration.
95   //              |                                 ^
96   //              |                                 |
97   //              -----------> super resolution -----
98   // * Any of these filters could be present or absent.
99   // * |frame_buffer_| points to the decoded frame buffer. When
100   //   ApplyFilteringThreaded() is called, |frame_buffer_| is modified by each
101   //   of the filters as described below.
102   // Filter behavior (multi-threaded):
103   // * Deblock: In-place filtering. The output is written to |source_buffer_|.
104   //            If cdef and loop restoration are both on, then 4 rows (as
105   //            specified by |kDeblockedRowsForLoopRestoration|) in every 64x64
106   //            block is copied into |deblock_buffer_|.
107   // * Cdef: Filtering output is written into |threaded_window_buffer_| and then
108   //         copied into the |cdef_buffer_| (which is just |source_buffer_| with
109   //         a shift to the top-left).
110   // * SuperRes: Near in-place filtering (with an additional line buffer for
111   //             each row). The output is written to |cdef_buffer_|.
112   // * Restoration: Uses the |cdef_buffer_| and |deblock_buffer_| as the input
113   //                and the output is written into the
114   //                |threaded_window_buffer_|. It is then copied to the
115   //                |loop_restoration_buffer_| (which is just |cdef_buffer_|
116   //                with a shift to the top-left).
117   void ApplyFilteringThreaded();
118 
119   // Does the overall post processing filter for one superblock row starting at
120   // |row4x4| with height 4*|sb4x4|. If |do_deblock| is false, deblocking filter
121   // will not be applied.
122   //
123   // Filter behavior (single-threaded):
124   // * Deblock: In-place filtering. The output is written to |source_buffer_|.
125   //            If cdef and loop restoration are both on, then 4 rows (as
126   //            specified by |kDeblockedRowsForLoopRestoration|) in every 64x64
127   //            block is copied into |deblock_buffer_|.
128   // * Cdef: In-place filtering. The output is written into |cdef_buffer_|
129   //         (which is just |source_buffer_| with a shift to the top-left).
130   // * SuperRes: Near in-place filtering (with an additional line buffer for
131   //             each row). The output is written to |cdef_buffer_|.
132   // * Restoration: Near in-place filtering. Uses a local block of size 64x64.
133   //                Uses the |cdef_buffer_| and |deblock_buffer_| as the input
134   //                and the output is written into |loop_restoration_buffer_|
135   //                (which is just |source_buffer_| with a shift to the
136   //                top-left).
137   // Returns the index of the last row whose post processing is complete and can
138   // be used for referencing.
139   int ApplyFilteringForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row,
140                                         bool do_deblock);
141 
142   // Apply deblocking filter in one direction (specified by |loop_filter_type|)
143   // for the superblock row starting at |row4x4_start| for columns starting from
144   // |column4x4_start| in increments of 16 (or 8 for chroma with subsampling)
145   // until the smallest multiple of 16 that is >= |column4x4_end| or until
146   // |frame_header_.columns4x4|, whichever is lower. This function must be
147   // called only if |DoDeblock()| returns true.
148   void ApplyDeblockFilter(LoopFilterType loop_filter_type, int row4x4_start,
149                           int column4x4_start, int column4x4_end, int sb4x4);
150 
DoCdef(const ObuFrameHeader & frame_header,int do_post_filter_mask)151   static bool DoCdef(const ObuFrameHeader& frame_header,
152                      int do_post_filter_mask) {
153     return (frame_header.cdef.bits > 0 ||
154             frame_header.cdef.y_primary_strength[0] > 0 ||
155             frame_header.cdef.y_secondary_strength[0] > 0 ||
156             frame_header.cdef.uv_primary_strength[0] > 0 ||
157             frame_header.cdef.uv_secondary_strength[0] > 0) &&
158            (do_post_filter_mask & 0x02) != 0;
159   }
DoCdef()160   bool DoCdef() const { return DoCdef(frame_header_, do_post_filter_mask_); }
161   // If filter levels for Y plane (0 for vertical, 1 for horizontal),
162   // are all zero, deblock filter will not be applied.
DoDeblock(const ObuFrameHeader & frame_header,uint8_t do_post_filter_mask)163   static bool DoDeblock(const ObuFrameHeader& frame_header,
164                         uint8_t do_post_filter_mask) {
165     return (frame_header.loop_filter.level[0] > 0 ||
166             frame_header.loop_filter.level[1] > 0) &&
167            (do_post_filter_mask & 0x01) != 0;
168   }
DoDeblock()169   bool DoDeblock() const {
170     return DoDeblock(frame_header_, do_post_filter_mask_);
171   }
172 
173   // This function takes the cdef filtered buffer and the deblocked buffer to
174   // prepare a block as input for loop restoration.
175   // In striped loop restoration:
176   // The filtering needs to fetch the area of size (width + 6) x (height + 4),
177   // in which (width + 6) x height area is from upscaled frame
178   // (superres_buffer). Top 2 rows and bottom 2 rows are from deblocked frame
179   // (deblock_buffer). Special cases are: (1). when it is the top border, the
180   // top 2 rows are from cdef filtered frame. (2). when it is the bottom border,
181   // the bottom 2 rows are from cdef filtered frame. This function is called
182   // only when cdef is applied for this frame.
183   template <typename Pixel>
184   static void PrepareLoopRestorationBlock(const Pixel* src_buffer,
185                                           ptrdiff_t src_stride,
186                                           const Pixel* deblock_buffer,
187                                           ptrdiff_t deblock_stride, Pixel* dst,
188                                           ptrdiff_t dst_stride, int width,
189                                           int height, bool frame_top_border,
190                                           bool frame_bottom_border);
191 
GetZeroDeltaDeblockFilterLevel(int segment_id,int level_index,ReferenceFrameType type,int mode_id)192   uint8_t GetZeroDeltaDeblockFilterLevel(int segment_id, int level_index,
193                                          ReferenceFrameType type,
194                                          int mode_id) const {
195     return deblock_filter_levels_[segment_id][level_index][type][mode_id];
196   }
197   // Computes the deblock filter levels using |delta_lf| and stores them in
198   // |deblock_filter_levels|.
199   void ComputeDeblockFilterLevels(
200       const int8_t delta_lf[kFrameLfCount],
201       uint8_t deblock_filter_levels[kMaxSegments][kFrameLfCount]
202                                    [kNumReferenceFrameTypes][2]) const;
203   // Returns true if loop restoration will be performed for the given parameters
204   // and mask.
DoRestoration(const LoopRestoration & loop_restoration,uint8_t do_post_filter_mask,int num_planes)205   static bool DoRestoration(const LoopRestoration& loop_restoration,
206                             uint8_t do_post_filter_mask, int num_planes) {
207     if (num_planes == kMaxPlanesMonochrome) {
208       return loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone &&
209              (do_post_filter_mask & 0x08) != 0;
210     }
211     return (loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone ||
212             loop_restoration.type[kPlaneU] != kLoopRestorationTypeNone ||
213             loop_restoration.type[kPlaneV] != kLoopRestorationTypeNone) &&
214            (do_post_filter_mask & 0x08) != 0;
215   }
DoRestoration()216   bool DoRestoration() const {
217     return DoRestoration(loop_restoration_, do_post_filter_mask_, planes_);
218   }
219 
220   // Returns a pointer to the unfiltered buffer. This is used by the Tile class
221   // to determine where to write the output of the tile decoding process taking
222   // in-place filtering offsets into consideration.
GetUnfilteredBuffer(int plane)223   uint8_t* GetUnfilteredBuffer(int plane) { return source_buffer_[plane]; }
frame_buffer()224   const YuvBuffer& frame_buffer() const { return frame_buffer_; }
225 
226   // Returns true if SuperRes will be performed for the given frame header and
227   // mask.
DoSuperRes(const ObuFrameHeader & frame_header,uint8_t do_post_filter_mask)228   static bool DoSuperRes(const ObuFrameHeader& frame_header,
229                          uint8_t do_post_filter_mask) {
230     return frame_header.width != frame_header.upscaled_width &&
231            (do_post_filter_mask & 0x04) != 0;
232   }
DoSuperRes()233   bool DoSuperRes() const {
234     return DoSuperRes(frame_header_, do_post_filter_mask_);
235   }
restoration_info()236   LoopRestorationInfo* restoration_info() const { return restoration_info_; }
GetBufferOffset(uint8_t * base_buffer,int stride,Plane plane,int row4x4,int column4x4)237   uint8_t* GetBufferOffset(uint8_t* base_buffer, int stride, Plane plane,
238                            int row4x4, int column4x4) const {
239     return base_buffer +
240            RowOrColumn4x4ToPixel(row4x4, plane, subsampling_y_[plane]) *
241                stride +
242            RowOrColumn4x4ToPixel(column4x4, plane, subsampling_x_[plane]) *
243                pixel_size_;
244   }
GetSourceBuffer(Plane plane,int row4x4,int column4x4)245   uint8_t* GetSourceBuffer(Plane plane, int row4x4, int column4x4) const {
246     return GetBufferOffset(source_buffer_[plane], frame_buffer_.stride(plane),
247                            plane, row4x4, column4x4);
248   }
249 
GetWindowBufferWidth(const ThreadPool * const thread_pool,const ObuFrameHeader & frame_header)250   static int GetWindowBufferWidth(const ThreadPool* const thread_pool,
251                                   const ObuFrameHeader& frame_header) {
252     return (thread_pool == nullptr) ? 0
253                                     : Align(frame_header.upscaled_width, 64);
254   }
255 
256   // For multi-threaded cdef and loop restoration, window height is the minimum
257   // of the following two quantities:
258   //  1) thread_count * 64
259   //  2) frame_height rounded up to the nearest power of 64
260   // Where 64 is the block size for cdef and loop restoration.
GetWindowBufferHeight(const ThreadPool * const thread_pool,const ObuFrameHeader & frame_header)261   static int GetWindowBufferHeight(const ThreadPool* const thread_pool,
262                                    const ObuFrameHeader& frame_header) {
263     if (thread_pool == nullptr) return 0;
264     const int thread_count = 1 + thread_pool->num_threads();
265     const int window_height = MultiplyBy64(thread_count);
266     const int adjusted_frame_height = Align(frame_header.height, 64);
267     return std::min(adjusted_frame_height, window_height);
268   }
269 
270   template <typename Pixel>
271   static void ExtendFrame(Pixel* frame_start, int width, int height,
272                           ptrdiff_t stride, int left, int right, int top,
273                           int bottom);
274 
275  private:
276   // The type of the HorizontalDeblockFilter and VerticalDeblockFilter member
277   // functions.
278   using DeblockFilter = void (PostFilter::*)(int row4x4_start,
279                                              int column4x4_start);
280   // The lookup table for picking the deblock filter, according to deblock
281   // filter type.
282   const DeblockFilter deblock_filter_func_[2] = {
283       &PostFilter::VerticalDeblockFilter, &PostFilter::HorizontalDeblockFilter};
284 
285   // Functions common to all post filters.
286 
287   // Extends the frame by setting the border pixel values to the one from its
288   // closest frame boundary.
289   void ExtendFrameBoundary(uint8_t* frame_start, int width, int height,
290                            ptrdiff_t stride, int left, int right, int top,
291                            int bottom) const;
292   // Extend frame boundary for referencing if the frame will be saved as a
293   // reference frame.
294   void ExtendBordersForReferenceFrame();
295   // Copies the deblocked pixels needed for loop restoration.
296   void CopyDeblockedPixels(Plane plane, int row4x4);
297   // Copies the border for one superblock row. If |for_loop_restoration| is
298   // true, then it assumes that the border extension is being performed for the
299   // input of the loop restoration process. If |for_loop_restoration| is false,
300   // then it assumes that the border extension is being performed for using the
301   // current frame as a reference frame. In this case, |progress_row_| is also
302   // updated.
303   void CopyBordersForOneSuperBlockRow(int row4x4, int sb4x4,
304                                       bool for_loop_restoration);
305   // Sets up the |deblock_buffer_| for loop restoration.
306   void SetupDeblockBuffer(int row4x4_start, int sb4x4);
307   // Returns true if we can perform border extension in loop (i.e.) without
308   // waiting until the entire frame is decoded. If intra_block_copy is true, we
309   // do in-loop border extension only if the upscaled_width is the same as 4 *
310   // columns4x4. Otherwise, we cannot do in loop border extension since those
311   // pixels may be used by intra block copy.
DoBorderExtensionInLoop()312   bool DoBorderExtensionInLoop() const {
313     return !frame_header_.allow_intrabc ||
314            frame_header_.upscaled_width ==
315                MultiplyBy4(frame_header_.columns4x4);
316   }
317   template <typename Pixel>
CopyPlane(const Pixel * src,ptrdiff_t src_stride,int width,int height,Pixel * dst,ptrdiff_t dst_stride)318   void CopyPlane(const Pixel* src, ptrdiff_t src_stride, int width, int height,
319                  Pixel* dst, ptrdiff_t dst_stride) {
320     for (int y = 0; y < height; ++y) {
321       memcpy(dst, src, width * sizeof(Pixel));
322       src += src_stride;
323       dst += dst_stride;
324     }
325   }
326 
327   // Functions for the Deblocking filter.
328 
GetIndex(int row4x4)329   static int GetIndex(int row4x4) { return DivideBy4(row4x4); }
GetShift(int row4x4,int column4x4)330   static int GetShift(int row4x4, int column4x4) {
331     return ((row4x4 & 3) << 4) | column4x4;
332   }
GetDeblockUnitId(int row_unit,int column_unit)333   int GetDeblockUnitId(int row_unit, int column_unit) const {
334     return row_unit * num_64x64_blocks_per_row_ + column_unit;
335   }
336   bool GetHorizontalDeblockFilterEdgeInfo(int row4x4, int column4x4,
337                                           uint8_t* level, int* step,
338                                           int* filter_length) const;
339   void GetHorizontalDeblockFilterEdgeInfoUV(int row4x4, int column4x4,
340                                             uint8_t* level_u, uint8_t* level_v,
341                                             int* step,
342                                             int* filter_length) const;
343   bool GetVerticalDeblockFilterEdgeInfo(int row4x4, int column4x4,
344                                         BlockParameters* const* bp_ptr,
345                                         uint8_t* level, int* step,
346                                         int* filter_length) const;
347   void GetVerticalDeblockFilterEdgeInfoUV(int column4x4,
348                                           BlockParameters* const* bp_ptr,
349                                           uint8_t* level_u, uint8_t* level_v,
350                                           int* step, int* filter_length) const;
351   void HorizontalDeblockFilter(int row4x4_start, int column4x4_start);
352   void VerticalDeblockFilter(int row4x4_start, int column4x4_start);
353   // HorizontalDeblockFilter and VerticalDeblockFilter must have the correct
354   // signature.
355   static_assert(std::is_same<decltype(&PostFilter::HorizontalDeblockFilter),
356                              DeblockFilter>::value,
357                 "");
358   static_assert(std::is_same<decltype(&PostFilter::VerticalDeblockFilter),
359                              DeblockFilter>::value,
360                 "");
361   // Applies deblock filtering for the superblock row starting at |row4x4| with
362   // a height of 4*|sb4x4|.
363   void ApplyDeblockFilterForOneSuperBlockRow(int row4x4, int sb4x4);
364   void DeblockFilterWorker(int jobs_per_plane, const Plane* planes,
365                            int num_planes, std::atomic<int>* job_counter,
366                            DeblockFilter deblock_filter);
367   void ApplyDeblockFilterThreaded();
368 
369   // Functions for the cdef filter.
370 
371   uint8_t* GetCdefBufferAndStride(int start_x, int start_y, int plane,
372                                   int window_buffer_plane_size,
373                                   int* cdef_stride) const;
374   // This function prepares the input source block for cdef filtering. The input
375   // source block contains a 12x12 block, with the inner 8x8 as the desired
376   // filter region. It pads the block if the 12x12 block includes out of frame
377   // pixels with a large value. This achieves the required behavior defined in
378   // section 5.11.52 of the spec.
379   template <typename Pixel>
380   void PrepareCdefBlock(int block_width4x4, int block_height4x4, int row4x4,
381                         int column4x4, uint16_t* cdef_source,
382                         ptrdiff_t cdef_stride, bool y_plane);
383   template <typename Pixel>
384   void ApplyCdefForOneUnit(uint16_t* cdef_block, int index, int block_width4x4,
385                            int block_height4x4, int row4x4_start,
386                            int column4x4_start);
387   // Helper function used by ApplyCdefForOneSuperBlockRow to avoid some code
388   // duplication.
389   void ApplyCdefForOneSuperBlockRowHelper(int row4x4, int block_height4x4);
390   // Applies cdef filtering for the superblock row starting at |row4x4| with a
391   // height of 4*|sb4x4|.
392   void ApplyCdefForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row);
393   template <typename Pixel>
394   void ApplyCdefForOneRowInWindow(int row, int column);
395   template <typename Pixel>
396   void ApplyCdefThreaded();
397   void ApplyCdef();  // Sections 7.15 and 7.15.1.
398 
399   // Functions for the SuperRes filter.
400 
401   // Applies super resolution for the |buffers| for |rows[plane]| rows of each
402   // plane. If |in_place| is true, the line buffer will not be used and the
403   // SuperRes output will be written to a row above the input row. If |in_place|
404   // is false, the line buffer will be used to store a copy of the input and the
405   // output will be written to the same row as the input row.
406   template <bool in_place>
407   void ApplySuperRes(const std::array<uint8_t*, kMaxPlanes>& buffers,
408                      const std::array<int, kMaxPlanes>& strides,
409                      const std::array<int, kMaxPlanes>& rows,
410                      size_t line_buffer_offset);  // Section 7.16.
411   // Applies SuperRes for the superblock row starting at |row4x4| with a height
412   // of 4*|sb4x4|.
413   void ApplySuperResForOneSuperBlockRow(int row4x4, int sb4x4,
414                                         bool is_last_row);
415   void ApplySuperResThreaded();
416 
417   // Functions for the Loop Restoration filter.
418 
419   template <typename Pixel>
420   void ApplyLoopRestorationForOneRowInWindow(
421       const Pixel* src_buffer, Plane plane, int plane_height, int plane_width,
422       int y, int x, int row, int unit_row, int current_process_unit_height,
423       int plane_unit_size, int window_width,
424       Array2DView<Pixel>* loop_restored_window);
425   // Applies loop restoration for the superblock row starting at |row4x4_start|
426   // with a height of 4*|sb4x4|.
427   template <typename Pixel>
428   void ApplyLoopRestorationSingleThread(int row4x4_start, int sb4x4);
429   void ApplyLoopRestoration(int row4x4_start, int sb4x4);
430   template <typename Pixel>
431   void ApplyLoopRestorationThreaded();
432   // Note for ApplyLoopRestoration():
433   // First, we must differentiate loop restoration processing unit from loop
434   // restoration unit.
435   // (1). Loop restoration processing unit size is default to 64x64.
436   // Only when the remaining filtering area is smaller than 64x64, the
437   // processing unit size is the actual area size.
438   // For U/V plane, it is (64 >> subsampling_x) x (64 >> subsampling_y).
439   // (2). Loop restoration unit size can be 64x64, 128x128, 256x256 for Y
440   // plane. The unit size for chroma can be the same or half, depending on
441   // subsampling. If either subsampling_x or subsampling_y is one, unit size
442   // is halved on both x and y sides.
443   // All loop restoration units have the same size for one plane.
444   // One loop restoration unit could contain multiple processing units.
445   // But they share the same sets of loop restoration parameters.
446   // (3). Loop restoration has a row offset, kRestorationUnitOffset = 8. The
447   // size of first row of loop restoration units and processing units is
448   // shrunk by the offset.
449   // (4). Loop restoration units wrap the bottom and the right of the frame,
450   // if the remaining area is small. The criteria is whether the number of
451   // remaining rows/columns is smaller than half of loop restoration unit
452   // size.
453   // For example, if the frame size is 140x140, loop restoration unit size is
454   // 128x128. The size of the first loop restoration unit is 128x(128-8) =
455   // 128 columns x 120 rows.
456   // Since 140 - 120 < 128/2. The remaining 20 rows will be folded to the loop
457   // restoration unit. Similarly, the remaining 12 columns will also be folded
458   // to current loop restoration unit. So, even frame size is 140x140,
459   // there's only one loop restoration unit. Suppose processing unit is 64x64,
460   // then sizes of the first row of processing units are 64x56, 64x56, 12x56,
461   // respectively. The second row is 64x64, 64x64, 12x64.
462   // The third row is 64x20, 64x20, 12x20.
463   void ApplyLoopRestoration();
464 
465   const ObuFrameHeader& frame_header_;
466   const LoopRestoration& loop_restoration_;
467   const dsp::Dsp& dsp_;
468   const int num_64x64_blocks_per_row_;
469   const int upscaled_width_;
470   const int width_;
471   const int height_;
472   const int8_t bitdepth_;
473   const int8_t subsampling_x_[kMaxPlanes];
474   const int8_t subsampling_y_[kMaxPlanes];
475   const int8_t planes_;
476   const int pixel_size_;
477   const uint8_t* const inner_thresh_;
478   const uint8_t* const outer_thresh_;
479   const bool needs_chroma_deblock_;
480   // This stores the deblocking filter levels assuming that the delta is zero.
481   // This will be used by all superblocks whose delta is zero (without having to
482   // recompute them). The dimensions (in order) are: segment_id, level_index
483   // (based on plane and direction), reference_frame and mode_id.
484   uint8_t deblock_filter_levels_[kMaxSegments][kFrameLfCount]
485                                 [kNumReferenceFrameTypes][2];
486   // Stores the SuperRes info for the frame.
487   struct {
488     int upscaled_width;
489     int initial_subpixel_x;
490     int step;
491   } super_res_info_[kMaxPlanes];
492   const Array2D<int16_t>& cdef_index_;
493   const Array2D<TransformSize>& inter_transform_sizes_;
494   // Pointer to the data buffer used for multi-threaded cdef or loop
495   // restoration. The size of this buffer must be at least
496   // |window_buffer_width_| * |window_buffer_height_| * |pixel_size_|.
497   // Or |planes_| times that for multi-threaded cdef.
498   // If |thread_pool_| is nullptr, then this buffer is not used and can be
499   // nullptr as well.
500   uint8_t* const threaded_window_buffer_;
501   LoopRestorationInfo* const restoration_info_;
502   // Pointer to the line buffer used by ApplySuperRes(). If SuperRes is on, then
503   // the buffer will be large enough to hold one downscaled row +
504   // 2 * kSuperResHorizontalBorder + kSuperResHorizontalPadding.
505   uint8_t* const superres_line_buffer_;
506   const BlockParametersHolder& block_parameters_;
507   // Frame buffer to hold cdef filtered frame.
508   YuvBuffer cdef_filtered_buffer_;
509   // Input frame buffer.
510   YuvBuffer& frame_buffer_;
511   // A view into |frame_buffer_| that points to the input and output of the
512   // deblocking process.
513   uint8_t* source_buffer_[kMaxPlanes];
514   // A view into |frame_buffer_| that points to the output of the CDEF filtered
515   // planes (to facilitate in-place CDEF filtering).
516   uint8_t* cdef_buffer_[kMaxPlanes];
517   // A view into |frame_buffer_| that points to the planes after the SuperRes
518   // filter is applied (to facilitate in-place SuperRes).
519   uint8_t* superres_buffer_[kMaxPlanes];
520   // A view into |frame_buffer_| that points to the output of the Loop Restored
521   // planes (to facilitate in-place Loop Restoration).
522   uint8_t* loop_restoration_buffer_[kMaxPlanes];
523   // Buffer used to store the deblocked pixels that are necessary for loop
524   // restoration. This buffer will store 4 rows for every 64x64 block (4 rows
525   // for every 32x32 for chroma with subsampling). The indices of the rows that
526   // are stored are specified in |kDeblockedRowsForLoopRestoration|. First 4
527   // rows of this buffer are never populated and never used.
528   // This buffer is used only when both Cdef and Loop Restoration are on.
529   YuvBuffer& deblock_buffer_;
530   const uint8_t do_post_filter_mask_;
531   ThreadPool* const thread_pool_;
532   const int window_buffer_width_;
533   const int window_buffer_height_;
534 
535   // Tracks the progress of the post filters.
536   int progress_row_ = -1;
537 
538   // A block buffer to hold the input that is converted to uint16_t before
539   // cdef filtering. Only used in single threaded case.
540   uint16_t cdef_block_[kCdefUnitSizeWithBorders * kCdefUnitSizeWithBorders * 3];
541 
542   template <int bitdepth, typename Pixel>
543   friend class PostFilterSuperResTest;
544 
545   template <int bitdepth, typename Pixel>
546   friend class PostFilterHelperFuncTest;
547 };
548 
549 extern template void PostFilter::ExtendFrame<uint8_t>(uint8_t* frame_start,
550                                                       int width, int height,
551                                                       ptrdiff_t stride,
552                                                       int left, int right,
553                                                       int top, int bottom);
554 extern template void PostFilter::PrepareLoopRestorationBlock<uint8_t>(
555     const uint8_t* src_buffer, ptrdiff_t src_stride,
556     const uint8_t* deblock_buffer, ptrdiff_t deblock_stride, uint8_t* dst,
557     ptrdiff_t dst_stride, const int width, const int height,
558     const bool frame_top_border, const bool frame_bottom_border);
559 
560 #if LIBGAV1_MAX_BITDEPTH >= 10
561 extern template void PostFilter::ExtendFrame<uint16_t>(uint16_t* frame_start,
562                                                        int width, int height,
563                                                        ptrdiff_t stride,
564                                                        int left, int right,
565                                                        int top, int bottom);
566 extern template void PostFilter::PrepareLoopRestorationBlock<uint16_t>(
567     const uint16_t* src_buffer, ptrdiff_t src_stride,
568     const uint16_t* deblock_buffer, ptrdiff_t deblock_stride, uint16_t* dst,
569     ptrdiff_t dst_stride, const int width, const int height,
570     const bool frame_top_border, const bool frame_bottom_border);
571 #endif
572 
573 }  // namespace libgav1
574 
575 #endif  // LIBGAV1_SRC_POST_FILTER_H_
576