• 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_|, |superres_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: |superres_buffer_|
72   //   -> Loop Restoration:
73   //      * Input: |superres_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 |kLoopRestorationBorderRows|) in every 64x64 block
106   //            is copied into |loop_restoration_border_|.
107   // * Cdef: In-place filtering. Uses the |source_buffer_| and |cdef_border_| as
108   //         the input and the output is written into |cdef_buffer_| (which is
109   //         the same as |source_buffer_|).
110   // * SuperRes: Near in-place filtering. Uses the |cdef_buffer_| and
111   //             |superres_line_buffer_| as the input and the output is written
112   //             into |superres_buffer_| (which is just |cdef_buffer_| with a
113   //             shift to the top).
114   // * Restoration: Near in-place filtering.
115   //                Uses the |superres_buffer_| and |loop_restoration_border_|
116   //                as the input and the output is written into
117   //                |loop_restoration_buffer_| (which is just |superres_buffer_|
118   //                with a shift to the left).
119   void ApplyFilteringThreaded();
120 
121   // Does the overall post processing filter for one superblock row starting at
122   // |row4x4| with height 4*|sb4x4|. If |do_deblock| is false, deblocking filter
123   // will not be applied.
124   //
125   // Filter behavior (single-threaded):
126   // * Deblock: In-place filtering. The output is written to |source_buffer_|.
127   //            If cdef and loop restoration are both on, then 4 rows (as
128   //            specified by |kLoopRestorationBorderRows|) in every 64x64 block
129   //            is copied into |loop_restoration_border_|.
130   // * Cdef: In-place filtering. The output is written into |cdef_buffer_|
131   //         (which is just |source_buffer_| with a shift to the top-left).
132   // * SuperRes: Near in-place filtering. Uses the |cdef_buffer_| as the input
133   //             and the output is written into |superres_buffer_| (which is
134   //             just |cdef_buffer_| with a shift to the top).
135   // * Restoration: Near in-place filtering.
136   //                Uses the |superres_buffer_| and |loop_restoration_border_|
137   //                as the input and the output is written into
138   //                |loop_restoration_buffer_| (which is just |superres_buffer_|
139   //                with a shift to the left or top-left).
140   // Returns the index of the last row whose post processing is complete and can
141   // be used for referencing.
142   int ApplyFilteringForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row,
143                                         bool do_deblock);
144 
145   // Apply deblocking filter in one direction (specified by |loop_filter_type|)
146   // for the superblock row starting at |row4x4_start| for columns starting from
147   // |column4x4_start| in increments of 16 (or 8 for chroma with subsampling)
148   // until the smallest multiple of 16 that is >= |column4x4_end| or until
149   // |frame_header_.columns4x4|, whichever is lower. This function must be
150   // called only if |DoDeblock()| returns true.
151   void ApplyDeblockFilter(LoopFilterType loop_filter_type, int row4x4_start,
152                           int column4x4_start, int column4x4_end, int sb4x4);
153 
DoCdef(const ObuFrameHeader & frame_header,int do_post_filter_mask)154   static bool DoCdef(const ObuFrameHeader& frame_header,
155                      int do_post_filter_mask) {
156     return (frame_header.cdef.bits > 0 ||
157             frame_header.cdef.y_primary_strength[0] > 0 ||
158             frame_header.cdef.y_secondary_strength[0] > 0 ||
159             frame_header.cdef.uv_primary_strength[0] > 0 ||
160             frame_header.cdef.uv_secondary_strength[0] > 0) &&
161            (do_post_filter_mask & 0x02) != 0;
162   }
DoCdef()163   bool DoCdef() const { return DoCdef(frame_header_, do_post_filter_mask_); }
164   // If filter levels for Y plane (0 for vertical, 1 for horizontal),
165   // are all zero, deblock filter will not be applied.
DoDeblock(const ObuFrameHeader & frame_header,uint8_t do_post_filter_mask)166   static bool DoDeblock(const ObuFrameHeader& frame_header,
167                         uint8_t do_post_filter_mask) {
168     return (frame_header.loop_filter.level[0] > 0 ||
169             frame_header.loop_filter.level[1] > 0) &&
170            (do_post_filter_mask & 0x01) != 0;
171   }
DoDeblock()172   bool DoDeblock() const {
173     return DoDeblock(frame_header_, do_post_filter_mask_);
174   }
175 
GetZeroDeltaDeblockFilterLevel(int segment_id,int level_index,ReferenceFrameType type,int mode_id)176   uint8_t GetZeroDeltaDeblockFilterLevel(int segment_id, int level_index,
177                                          ReferenceFrameType type,
178                                          int mode_id) const {
179     return deblock_filter_levels_[segment_id][level_index][type][mode_id];
180   }
181   // Computes the deblock filter levels using |delta_lf| and stores them in
182   // |deblock_filter_levels|.
183   void ComputeDeblockFilterLevels(
184       const int8_t delta_lf[kFrameLfCount],
185       uint8_t deblock_filter_levels[kMaxSegments][kFrameLfCount]
186                                    [kNumReferenceFrameTypes][2]) const;
187   // Returns true if loop restoration will be performed for the given parameters
188   // and mask.
DoRestoration(const LoopRestoration & loop_restoration,uint8_t do_post_filter_mask,int num_planes)189   static bool DoRestoration(const LoopRestoration& loop_restoration,
190                             uint8_t do_post_filter_mask, int num_planes) {
191     if (num_planes == kMaxPlanesMonochrome) {
192       return loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone &&
193              (do_post_filter_mask & 0x08) != 0;
194     }
195     return (loop_restoration.type[kPlaneY] != kLoopRestorationTypeNone ||
196             loop_restoration.type[kPlaneU] != kLoopRestorationTypeNone ||
197             loop_restoration.type[kPlaneV] != kLoopRestorationTypeNone) &&
198            (do_post_filter_mask & 0x08) != 0;
199   }
DoRestoration()200   bool DoRestoration() const {
201     return DoRestoration(loop_restoration_, do_post_filter_mask_, planes_);
202   }
203 
204   // Returns a pointer to the unfiltered buffer. This is used by the Tile class
205   // to determine where to write the output of the tile decoding process taking
206   // in-place filtering offsets into consideration.
GetUnfilteredBuffer(int plane)207   uint8_t* GetUnfilteredBuffer(int plane) { return source_buffer_[plane]; }
frame_buffer()208   const YuvBuffer& frame_buffer() const { return frame_buffer_; }
209 
210   // Returns true if SuperRes will be performed for the given frame header and
211   // mask.
DoSuperRes(const ObuFrameHeader & frame_header,uint8_t do_post_filter_mask)212   static bool DoSuperRes(const ObuFrameHeader& frame_header,
213                          uint8_t do_post_filter_mask) {
214     return frame_header.width != frame_header.upscaled_width &&
215            (do_post_filter_mask & 0x04) != 0;
216   }
DoSuperRes()217   bool DoSuperRes() const {
218     return DoSuperRes(frame_header_, do_post_filter_mask_);
219   }
restoration_info()220   LoopRestorationInfo* restoration_info() const { return restoration_info_; }
GetBufferOffset(uint8_t * base_buffer,int stride,Plane plane,int row,int column)221   uint8_t* GetBufferOffset(uint8_t* base_buffer, int stride, Plane plane,
222                            int row, int column) const {
223     return base_buffer + (row >> subsampling_y_[plane]) * stride +
224            ((column >> subsampling_x_[plane]) << pixel_size_log2_);
225   }
GetSourceBuffer(Plane plane,int row4x4,int column4x4)226   uint8_t* GetSourceBuffer(Plane plane, int row4x4, int column4x4) const {
227     return GetBufferOffset(source_buffer_[plane], frame_buffer_.stride(plane),
228                            plane, MultiplyBy4(row4x4), MultiplyBy4(column4x4));
229   }
GetCdefBuffer(Plane plane,int row4x4,int column4x4)230   uint8_t* GetCdefBuffer(Plane plane, int row4x4, int column4x4) const {
231     return GetBufferOffset(cdef_buffer_[plane], frame_buffer_.stride(plane),
232                            plane, MultiplyBy4(row4x4), MultiplyBy4(column4x4));
233   }
GetSuperResBuffer(Plane plane,int row4x4,int column4x4)234   uint8_t* GetSuperResBuffer(Plane plane, int row4x4, int column4x4) const {
235     return GetBufferOffset(superres_buffer_[plane], frame_buffer_.stride(plane),
236                            plane, MultiplyBy4(row4x4), MultiplyBy4(column4x4));
237   }
238 
239   template <typename Pixel>
240   static void ExtendFrame(Pixel* frame_start, int width, int height,
241                           ptrdiff_t stride, int left, int right, int top,
242                           int bottom);
243 
244  private:
245   // The type of the HorizontalDeblockFilter and VerticalDeblockFilter member
246   // functions.
247   using DeblockFilter = void (PostFilter::*)(int row4x4_start,
248                                              int column4x4_start);
249   // The lookup table for picking the deblock filter, according to deblock
250   // filter type.
251   const DeblockFilter deblock_filter_func_[2] = {
252       &PostFilter::VerticalDeblockFilter, &PostFilter::HorizontalDeblockFilter};
253 
254   // Functions common to all post filters.
255 
256   // Extends the frame by setting the border pixel values to the one from its
257   // closest frame boundary.
258   void ExtendFrameBoundary(uint8_t* frame_start, int width, int height,
259                            ptrdiff_t stride, int left, int right, int top,
260                            int bottom) const;
261   // Extend frame boundary for referencing if the frame will be saved as a
262   // reference frame.
263   void ExtendBordersForReferenceFrame();
264   // Copies the deblocked pixels needed for loop restoration.
265   void CopyDeblockedPixels(Plane plane, int row4x4);
266   // Copies the border for one superblock row. If |for_loop_restoration| is
267   // true, then it assumes that the border extension is being performed for the
268   // input of the loop restoration process. If |for_loop_restoration| is false,
269   // then it assumes that the border extension is being performed for using the
270   // current frame as a reference frame. In this case, |progress_row_| is also
271   // updated.
272   void CopyBordersForOneSuperBlockRow(int row4x4, int sb4x4,
273                                       bool for_loop_restoration);
274   // Sets up the |loop_restoration_border_| for loop restoration.
275   // This is called when there is no CDEF filter. We copy rows from
276   // |superres_buffer_| and do the line extension.
277   void SetupLoopRestorationBorder(int row4x4_start);
278   // This is called when there is CDEF filter. We copy rows from
279   // |source_buffer_|, apply superres and do the line extension.
280   void SetupLoopRestorationBorder(int row4x4_start, int sb4x4);
281   // Returns true if we can perform border extension in loop (i.e.) without
282   // waiting until the entire frame is decoded. If intra_block_copy is true, we
283   // do in-loop border extension only if the upscaled_width is the same as 4 *
284   // columns4x4. Otherwise, we cannot do in loop border extension since those
285   // pixels may be used by intra block copy.
DoBorderExtensionInLoop()286   bool DoBorderExtensionInLoop() const {
287     return !frame_header_.allow_intrabc ||
288            frame_header_.upscaled_width ==
289                MultiplyBy4(frame_header_.columns4x4);
290   }
291   template <typename Pixel>
CopyPlane(const Pixel * src,ptrdiff_t src_stride,int width,int height,Pixel * dst,ptrdiff_t dst_stride)292   void CopyPlane(const Pixel* src, ptrdiff_t src_stride, int width, int height,
293                  Pixel* dst, ptrdiff_t dst_stride) {
294     assert(height > 0);
295     do {
296       memcpy(dst, src, width * sizeof(Pixel));
297       src += src_stride;
298       dst += dst_stride;
299     } while (--height != 0);
300   }
301 
302   // Worker function used for multi-threaded implementation of Deblocking, CDEF
303   // and Loop Restoration.
304   using WorkerFunction = void (PostFilter::*)(std::atomic<int>* row4x4_atomic);
305   // Schedules |worker| jobs to the |thread_pool_|, runs them in the calling
306   // thread and returns once all the jobs are completed.
307   void RunJobs(WorkerFunction worker);
308 
309   // Functions for the Deblocking filter.
310 
GetIndex(int row4x4)311   static int GetIndex(int row4x4) { return DivideBy4(row4x4); }
GetShift(int row4x4,int column4x4)312   static int GetShift(int row4x4, int column4x4) {
313     return ((row4x4 & 3) << 4) | column4x4;
314   }
GetDeblockUnitId(int row_unit,int column_unit)315   int GetDeblockUnitId(int row_unit, int column_unit) const {
316     return row_unit * num_64x64_blocks_per_row_ + column_unit;
317   }
318   bool GetHorizontalDeblockFilterEdgeInfo(int row4x4, int column4x4,
319                                           uint8_t* level, int* step,
320                                           int* filter_length) const;
321   void GetHorizontalDeblockFilterEdgeInfoUV(int row4x4, int column4x4,
322                                             uint8_t* level_u, uint8_t* level_v,
323                                             int* step,
324                                             int* filter_length) const;
325   bool GetVerticalDeblockFilterEdgeInfo(int row4x4, int column4x4,
326                                         BlockParameters* const* bp_ptr,
327                                         uint8_t* level, int* step,
328                                         int* filter_length) const;
329   void GetVerticalDeblockFilterEdgeInfoUV(int column4x4,
330                                           BlockParameters* const* bp_ptr,
331                                           uint8_t* level_u, uint8_t* level_v,
332                                           int* step, int* filter_length) const;
333   void HorizontalDeblockFilter(int row4x4_start, int column4x4_start);
334   void VerticalDeblockFilter(int row4x4_start, int column4x4_start);
335   // HorizontalDeblockFilter and VerticalDeblockFilter must have the correct
336   // signature.
337   static_assert(std::is_same<decltype(&PostFilter::HorizontalDeblockFilter),
338                              DeblockFilter>::value,
339                 "");
340   static_assert(std::is_same<decltype(&PostFilter::VerticalDeblockFilter),
341                              DeblockFilter>::value,
342                 "");
343   // Applies deblock filtering for the superblock row starting at |row4x4| with
344   // a height of 4*|sb4x4|.
345   void ApplyDeblockFilterForOneSuperBlockRow(int row4x4, int sb4x4);
346   // Worker function used for multi-threaded deblocking.
347   template <LoopFilterType loop_filter_type>
348   void DeblockFilterWorker(std::atomic<int>* row4x4_atomic);
349   static_assert(
350       std::is_same<
351           decltype(&PostFilter::DeblockFilterWorker<kLoopFilterTypeVertical>),
352           WorkerFunction>::value,
353       "");
354   static_assert(
355       std::is_same<
356           decltype(&PostFilter::DeblockFilterWorker<kLoopFilterTypeHorizontal>),
357           WorkerFunction>::value,
358       "");
359 
360   // Functions for the cdef filter.
361 
362   // Copies the deblocked pixels necessary for use by the multi-threaded cdef
363   // implementation into |cdef_border_|.
364   void SetupCdefBorder(int row4x4);
365   // This function prepares the input source block for cdef filtering. The input
366   // source block contains a 12x12 block, with the inner 8x8 as the desired
367   // filter region. It pads the block if the 12x12 block includes out of frame
368   // pixels with a large value. This achieves the required behavior defined in
369   // section 5.11.52 of the spec.
370   template <typename Pixel>
371   void PrepareCdefBlock(int block_width4x4, int block_height4x4, int row4x4,
372                         int column4x4, uint16_t* cdef_source,
373                         ptrdiff_t cdef_stride, bool y_plane,
374                         const uint8_t border_columns[kMaxPlanes][256],
375                         bool use_border_columns);
376   // Applies cdef for one 64x64 block.
377   template <typename Pixel>
378   void ApplyCdefForOneUnit(uint16_t* cdef_block, int index, int block_width4x4,
379                            int block_height4x4, int row4x4_start,
380                            int column4x4_start,
381                            uint8_t border_columns[2][kMaxPlanes][256],
382                            bool use_border_columns[2][2]);
383   // Helper function used by ApplyCdefForOneSuperBlockRow to avoid some code
384   // duplication.
385   void ApplyCdefForOneSuperBlockRowHelper(
386       uint16_t* cdef_block, uint8_t border_columns[2][kMaxPlanes][256],
387       int row4x4, int block_height4x4);
388   // Applies CDEF filtering for the superblock row starting at |row4x4| with a
389   // height of 4*|sb4x4|.
390   void ApplyCdefForOneSuperBlockRow(int row4x4, int sb4x4, bool is_last_row);
391   // Worker function used for multi-threaded CDEF.
392   void ApplyCdefWorker(std::atomic<int>* row4x4_atomic);
393   static_assert(std::is_same<decltype(&PostFilter::ApplyCdefWorker),
394                              WorkerFunction>::value,
395                 "");
396 
397   // Functions for the SuperRes filter.
398 
399   // Applies super resolution for the |src| for |rows[plane]| rows of each
400   // plane. If |line_buffer_row| is larger than or equal to 0, one more row will
401   // be processed, the line buffer indicated by |line_buffer_row| will be used
402   // as the source. If |dst_is_loop_restoration_border| is true, then it means
403   // that the |dst| pointers come from |loop_restoration_border_| and the
404   // strides will be populated from that buffer.
405   void ApplySuperRes(
406       const std::array<uint8_t*, kMaxPlanes>& src,
407       const std::array<int, kMaxPlanes>& rows, int line_buffer_row,
408       const std::array<uint8_t*, kMaxPlanes>& dst,
409       bool dst_is_loop_restoration_border = false);  // Section 7.16.
410   // Applies SuperRes for the superblock row starting at |row4x4| with a height
411   // of 4*|sb4x4|.
412   void ApplySuperResForOneSuperBlockRow(int row4x4, int sb4x4,
413                                         bool is_last_row);
414   void ApplySuperResThreaded();
415 
416   // Functions for the Loop Restoration filter.
417 
418   // Notes about Loop Restoration:
419   // (1). Loop restoration processing unit size is default to 64x64.
420   // Only when the remaining filtering area is smaller than 64x64, the
421   // processing unit size is the actual area size.
422   // For U/V plane, it is (64 >> subsampling_x) x (64 >> subsampling_y).
423   // (2). Loop restoration unit size can be 64x64, 128x128, 256x256 for Y
424   // plane. The unit size for chroma can be the same or half, depending on
425   // subsampling. If either subsampling_x or subsampling_y is one, unit size
426   // is halved on both x and y sides.
427   // All loop restoration units have the same size for one plane.
428   // One loop restoration unit could contain multiple processing units.
429   // But they share the same sets of loop restoration parameters.
430   // (3). Loop restoration has a row offset, kRestorationUnitOffset = 8. The
431   // size of first row of loop restoration units and processing units is
432   // shrunk by the offset.
433   // (4). Loop restoration units wrap the bottom and the right of the frame,
434   // if the remaining area is small. The criteria is whether the number of
435   // remaining rows/columns is smaller than half of loop restoration unit
436   // size.
437   // For example, if the frame size is 140x140, loop restoration unit size is
438   // 128x128. The size of the first loop restoration unit is 128x(128-8) =
439   // 128 columns x 120 rows.
440   // Since 140 - 120 < 128/2. The remaining 20 rows will be folded to the loop
441   // restoration unit. Similarly, the remaining 12 columns will also be folded
442   // to current loop restoration unit. So, even frame size is 140x140,
443   // there's only one loop restoration unit. Suppose processing unit is 64x64,
444   // then sizes of the first row of processing units are 64x56, 64x56, 12x56,
445   // respectively. The second row is 64x64, 64x64, 12x64.
446   // The third row is 64x20, 64x20, 12x20.
447 
448   // |stride| is shared by |src_buffer| and |dst_buffer|.
449   template <typename Pixel>
450   void ApplyLoopRestorationForOneRow(const Pixel* src_buffer, ptrdiff_t stride,
451                                      Plane plane, int plane_height,
452                                      int plane_width, int y, int unit_row,
453                                      int current_process_unit_height,
454                                      int plane_unit_size, Pixel* dst_buffer);
455   // Applies loop restoration for the superblock row starting at |row4x4_start|
456   // with a height of 4*|sb4x4|.
457   template <typename Pixel>
458   void ApplyLoopRestorationForOneSuperBlockRow(int row4x4_start, int sb4x4);
459   // Helper function that calls the right variant of
460   // ApplyLoopRestorationForOneSuperBlockRow based on the bitdepth.
461   void ApplyLoopRestoration(int row4x4_start, int sb4x4);
462   // Worker function used for multithreaded Loop Restoration.
463   void ApplyLoopRestorationWorker(std::atomic<int>* row4x4_atomic);
464   static_assert(std::is_same<decltype(&PostFilter::ApplyLoopRestorationWorker),
465                              WorkerFunction>::value,
466                 "");
467 
468   const ObuFrameHeader& frame_header_;
469   const LoopRestoration& loop_restoration_;
470   const dsp::Dsp& dsp_;
471   const int num_64x64_blocks_per_row_;
472   const int upscaled_width_;
473   const int width_;
474   const int height_;
475   const int8_t bitdepth_;
476   const int8_t subsampling_x_[kMaxPlanes];
477   const int8_t subsampling_y_[kMaxPlanes];
478   const int8_t planes_;
479   const int pixel_size_log2_;
480   const uint8_t* const inner_thresh_;
481   const uint8_t* const outer_thresh_;
482   const bool needs_chroma_deblock_;
483   // This stores the deblocking filter levels assuming that the delta is zero.
484   // This will be used by all superblocks whose delta is zero (without having to
485   // recompute them). The dimensions (in order) are: segment_id, level_index
486   // (based on plane and direction), reference_frame and mode_id.
487   uint8_t deblock_filter_levels_[kMaxSegments][kFrameLfCount]
488                                 [kNumReferenceFrameTypes][2];
489   // Stores the SuperRes info for the frame.
490   struct {
491     int upscaled_width;
492     int initial_subpixel_x;
493     int step;
494   } super_res_info_[kMaxPlanes];
495   const Array2D<int16_t>& cdef_index_;
496   const Array2D<TransformSize>& inter_transform_sizes_;
497   LoopRestorationInfo* const restoration_info_;
498   uint8_t* const superres_coefficients_[kNumPlaneTypes];
499   // Line buffer used by multi-threaded ApplySuperRes().
500   // In the multi-threaded case, this buffer will store the last downscaled row
501   // input of each thread to avoid overwrites by the first upscaled row output
502   // of the thread below it.
503   YuvBuffer& superres_line_buffer_;
504   const BlockParametersHolder& block_parameters_;
505   // Frame buffer to hold cdef filtered frame.
506   YuvBuffer cdef_filtered_buffer_;
507   // Input frame buffer.
508   YuvBuffer& frame_buffer_;
509   // A view into |frame_buffer_| that points to the input and output of the
510   // deblocking process.
511   uint8_t* source_buffer_[kMaxPlanes];
512   // A view into |frame_buffer_| that points to the output of the CDEF filtered
513   // planes (to facilitate in-place CDEF filtering).
514   uint8_t* cdef_buffer_[kMaxPlanes];
515   // A view into |frame_buffer_| that points to the planes after the SuperRes
516   // filter is applied (to facilitate in-place SuperRes).
517   uint8_t* superres_buffer_[kMaxPlanes];
518   // A view into |frame_buffer_| that points to the output of the Loop Restored
519   // planes (to facilitate in-place Loop Restoration).
520   uint8_t* loop_restoration_buffer_[kMaxPlanes];
521   YuvBuffer& cdef_border_;
522   // Buffer used to store the border pixels that are necessary for loop
523   // restoration. This buffer will store 4 rows for every 64x64 block (4 rows
524   // for every 32x32 for chroma with subsampling). The indices of the rows that
525   // are stored are specified in |kLoopRestorationBorderRows|. First 4 rows of
526   // this buffer are never populated and never used.
527   // This buffer is used only when both of the following conditions are true:
528   //   (1). Loop Restoration is on.
529   //   (2). Cdef is on, or multi-threading is enabled for post filter.
530   YuvBuffer& loop_restoration_border_;
531   const uint8_t do_post_filter_mask_;
532   ThreadPool* const thread_pool_;
533 
534   // Tracks the progress of the post filters.
535   int progress_row_ = -1;
536 
537   // A block buffer to hold the input that is converted to uint16_t before
538   // cdef filtering. Only used in single threaded case. Y plane is processed
539   // separately. U and V planes are processed together. So it is sufficient to
540   // have this buffer to accommodate 2 planes at a time.
541   uint16_t cdef_block_[kCdefUnitSizeWithBorders * kCdefUnitSizeWithBorders * 2];
542 
543   template <int bitdepth, typename Pixel>
544   friend class PostFilterSuperResTest;
545 
546   template <int bitdepth, typename Pixel>
547   friend class PostFilterHelperFuncTest;
548 };
549 
550 extern template void PostFilter::ExtendFrame<uint8_t>(uint8_t* frame_start,
551                                                       int width, int height,
552                                                       ptrdiff_t stride,
553                                                       int left, int right,
554                                                       int top, int bottom);
555 
556 #if LIBGAV1_MAX_BITDEPTH >= 10
557 extern template void PostFilter::ExtendFrame<uint16_t>(uint16_t* frame_start,
558                                                        int width, int height,
559                                                        ptrdiff_t stride,
560                                                        int left, int right,
561                                                        int top, int bottom);
562 #endif
563 
564 }  // namespace libgav1
565 
566 #endif  // LIBGAV1_SRC_POST_FILTER_H_
567