• 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_TILE_H_
18 #define LIBGAV1_SRC_TILE_H_
19 
20 #include <algorithm>
21 #include <array>
22 #include <cassert>
23 #include <cmath>
24 #include <condition_variable>  // NOLINT (unapproved c++11 header)
25 #include <cstddef>
26 #include <cstdint>
27 #include <memory>
28 #include <mutex>  // NOLINT (unapproved c++11 header)
29 
30 #include "src/buffer_pool.h"
31 #include "src/decoder_state.h"
32 #include "src/dsp/common.h"
33 #include "src/dsp/constants.h"
34 #include "src/dsp/dsp.h"
35 #include "src/frame_scratch_buffer.h"
36 #include "src/loop_restoration_info.h"
37 #include "src/obu_parser.h"
38 #include "src/post_filter.h"
39 #include "src/quantizer.h"
40 #include "src/residual_buffer_pool.h"
41 #include "src/symbol_decoder_context.h"
42 #include "src/tile_scratch_buffer.h"
43 #include "src/utils/array_2d.h"
44 #include "src/utils/block_parameters_holder.h"
45 #include "src/utils/blocking_counter.h"
46 #include "src/utils/common.h"
47 #include "src/utils/compiler_attributes.h"
48 #include "src/utils/constants.h"
49 #include "src/utils/entropy_decoder.h"
50 #include "src/utils/memory.h"
51 #include "src/utils/segmentation_map.h"
52 #include "src/utils/threadpool.h"
53 #include "src/utils/types.h"
54 #include "src/yuv_buffer.h"
55 
56 namespace libgav1 {
57 
58 // Indicates what the ProcessSuperBlock() and TransformBlock() functions should
59 // do. "Parse" refers to consuming the bitstream, reading the transform
60 // coefficients and performing the dequantization. "Decode" refers to computing
61 // the prediction, applying the inverse transforms and adding the residual.
62 enum ProcessingMode {
63   kProcessingModeParseOnly,
64   kProcessingModeDecodeOnly,
65   kProcessingModeParseAndDecode,
66 };
67 
68 // The alignment requirement is due to the SymbolDecoderContext member
69 // symbol_decoder_context_.
70 class Tile : public MaxAlignedAllocable {
71  public:
Create(int tile_number,const uint8_t * const data,size_t size,const ObuSequenceHeader & sequence_header,const ObuFrameHeader & frame_header,RefCountedBuffer * const current_frame,const DecoderState & state,FrameScratchBuffer * const frame_scratch_buffer,const WedgeMaskArray & wedge_masks,const QuantizerMatrix & quantizer_matrix,SymbolDecoderContext * const saved_symbol_decoder_context,const SegmentationMap * prev_segment_ids,PostFilter * const post_filter,const dsp::Dsp * const dsp,ThreadPool * const thread_pool,BlockingCounterWithStatus * const pending_tiles,bool frame_parallel,bool use_intra_prediction_buffer,bool parse_only)72   static std::unique_ptr<Tile> Create(
73       int tile_number, const uint8_t* const data, size_t size,
74       const ObuSequenceHeader& sequence_header,
75       const ObuFrameHeader& frame_header, RefCountedBuffer* const current_frame,
76       const DecoderState& state, FrameScratchBuffer* const frame_scratch_buffer,
77       const WedgeMaskArray& wedge_masks,
78       const QuantizerMatrix& quantizer_matrix,
79       SymbolDecoderContext* const saved_symbol_decoder_context,
80       const SegmentationMap* prev_segment_ids, PostFilter* const post_filter,
81       const dsp::Dsp* const dsp, ThreadPool* const thread_pool,
82       BlockingCounterWithStatus* const pending_tiles, bool frame_parallel,
83       bool use_intra_prediction_buffer, bool parse_only) {
84     std::unique_ptr<Tile> tile(new (std::nothrow) Tile(
85         tile_number, data, size, sequence_header, frame_header, current_frame,
86         state, frame_scratch_buffer, wedge_masks, quantizer_matrix,
87         saved_symbol_decoder_context, prev_segment_ids, post_filter, dsp,
88         thread_pool, pending_tiles, frame_parallel, use_intra_prediction_buffer,
89         parse_only));
90     return (tile != nullptr && tile->Init()) ? std::move(tile) : nullptr;
91   }
92 
93   // Move only.
94   Tile(Tile&& tile) noexcept;
95   Tile& operator=(Tile&& tile) noexcept;
96   Tile(const Tile&) = delete;
97   Tile& operator=(const Tile&) = delete;
98 
99   struct Block;  // Defined after this class.
100 
101   // Parses the entire tile.
102   bool Parse();
103   // Decodes the entire tile. |superblock_row_progress| and
104   // |superblock_row_progress_condvar| are arrays of size equal to the number of
105   // superblock rows in the frame. Increments |superblock_row_progress[i]| after
106   // each superblock row at index |i| is decoded. If the count reaches the
107   // number of tile columns, then it notifies
108   // |superblock_row_progress_condvar[i]|.
109   bool Decode(std::mutex* mutex, int* superblock_row_progress,
110               std::condition_variable* superblock_row_progress_condvar);
111   // Parses and decodes the entire tile. Depending on the configuration of this
112   // Tile, this function may do multithreaded decoding.
113   bool ParseAndDecode();  // 5.11.2.
114   // Processes all the columns of the superblock row at |row4x4| that are within
115   // this Tile. If |save_symbol_decoder_context| is true, then
116   // SaveSymbolDecoderContext() is invoked for the last superblock row.
117   template <ProcessingMode processing_mode, bool save_symbol_decoder_context>
118   bool ProcessSuperBlockRow(int row4x4, TileScratchBuffer* scratch_buffer);
119 
sequence_header()120   const ObuSequenceHeader& sequence_header() const { return sequence_header_; }
frame_header()121   const ObuFrameHeader& frame_header() const { return frame_header_; }
current_frame()122   const RefCountedBuffer& current_frame() const { return current_frame_; }
motion_field()123   const TemporalMotionField& motion_field() const { return motion_field_; }
reference_frame_sign_bias()124   const std::array<bool, kNumReferenceFrameTypes>& reference_frame_sign_bias()
125       const {
126     return reference_frame_sign_bias_;
127   }
128 
IsRow4x4Inside(int row4x4)129   bool IsRow4x4Inside(int row4x4) const {
130     return row4x4 >= row4x4_start_ && row4x4 < row4x4_end_;
131   }
132 
133   // 5.11.51.
IsInside(int row4x4,int column4x4)134   bool IsInside(int row4x4, int column4x4) const {
135     return IsRow4x4Inside(row4x4) && column4x4 >= column4x4_start_ &&
136            column4x4 < column4x4_end_;
137   }
138 
IsLeftInside(int column4x4)139   bool IsLeftInside(int column4x4) const {
140     // We use "larger than" as the condition. Don't pass in the left column
141     // offset column4x4 - 1.
142     assert(column4x4 <= column4x4_end_);
143     return column4x4 > column4x4_start_;
144   }
145 
IsTopInside(int row4x4)146   bool IsTopInside(int row4x4) const {
147     // We use "larger than" as the condition. Don't pass in the top row offset
148     // row4x4 - 1.
149     assert(row4x4 <= row4x4_end_);
150     return row4x4 > row4x4_start_;
151   }
152 
IsTopLeftInside(int row4x4,int column4x4)153   bool IsTopLeftInside(int row4x4, int column4x4) const {
154     // We use "larger than" as the condition. Don't pass in the top row offset
155     // row4x4 - 1 or the left column offset column4x4 - 1.
156     assert(row4x4 <= row4x4_end_);
157     assert(column4x4 <= column4x4_end_);
158     return row4x4 > row4x4_start_ && column4x4 > column4x4_start_;
159   }
160 
IsBottomRightInside(int row4x4,int column4x4)161   bool IsBottomRightInside(int row4x4, int column4x4) const {
162     assert(row4x4 >= row4x4_start_);
163     assert(column4x4 >= column4x4_start_);
164     return row4x4 < row4x4_end_ && column4x4 < column4x4_end_;
165   }
166 
BlockParametersAddress(int row4x4,int column4x4)167   BlockParameters** BlockParametersAddress(int row4x4, int column4x4) const {
168     return block_parameters_holder_.Address(row4x4, column4x4);
169   }
170 
BlockParametersStride()171   int BlockParametersStride() const {
172     return block_parameters_holder_.columns4x4();
173   }
174 
175   // Returns true if Parameters() can be called with |row| and |column| as
176   // inputs, false otherwise.
HasParameters(int row,int column)177   bool HasParameters(int row, int column) const {
178     return block_parameters_holder_.Find(row, column) != nullptr;
179   }
Parameters(int row,int column)180   const BlockParameters& Parameters(int row, int column) const {
181     return *block_parameters_holder_.Find(row, column);
182   }
183 
number()184   int number() const { return number_; }
superblock_rows()185   int superblock_rows() const { return superblock_rows_; }
superblock_columns()186   int superblock_columns() const { return superblock_columns_; }
row4x4_start()187   int row4x4_start() const { return row4x4_start_; }
column4x4_start()188   int column4x4_start() const { return column4x4_start_; }
column4x4_end()189   int column4x4_end() const { return column4x4_end_; }
190 
GetTileMeanQP()191   int GetTileMeanQP() const {
192     return static_cast<int>(
193         std::round(static_cast<float>(weighted_cumulative_block_qp_) /
194                    cumulative_block_weights_));
195   }
196 
197  private:
198   // Stores the transform tree state when reading variable size transform trees
199   // and when applying the transform tree. When applying the transform tree,
200   // |depth| is not used.
201   struct TransformTreeNode {
202     // The default constructor is invoked by the Stack<TransformTreeNode, n>
203     // constructor. Stack<> does not use the default-constructed elements, so it
204     // is safe for the default constructor to not initialize the members.
205     TransformTreeNode() = default;
206     TransformTreeNode(int x, int y, TransformSize tx_size, int depth = -1)
xTransformTreeNode207         : x(x), y(y), tx_size(tx_size), depth(depth) {}
208 
209     int x;
210     int y;
211     TransformSize tx_size;
212     int depth;
213   };
214 
215   // Enum to track the processing state of a superblock.
216   enum SuperBlockState : uint8_t {
217     kSuperBlockStateNone,       // Not yet parsed or decoded.
218     kSuperBlockStateParsed,     // Parsed but not yet decoded.
219     kSuperBlockStateScheduled,  // Scheduled for decoding.
220     kSuperBlockStateDecoded     // Parsed and decoded.
221   };
222 
223   // Parameters used to facilitate multi-threading within the Tile.
224   struct ThreadingParameters {
225     std::mutex mutex;
226     // 2d array of size |superblock_rows_| by |superblock_columns_| containing
227     // the processing state of each superblock.
228     Array2D<SuperBlockState> sb_state LIBGAV1_GUARDED_BY(mutex);
229     // Variable used to indicate either parse or decode failure.
230     bool abort LIBGAV1_GUARDED_BY(mutex) = false;
231     int pending_jobs LIBGAV1_GUARDED_BY(mutex) = 0;
232     std::condition_variable pending_jobs_zero_condvar;
233   };
234 
235   // The residual pointer is used to traverse the |residual_buffer_|. It is
236   // used in two different ways.
237   // If |split_parse_and_decode_| is true:
238   //    The pointer points to the beginning of the |residual_buffer_| when the
239   //    "parse" and "decode" steps begin. It is then moved forward tx_size in
240   //    each iteration of the "parse" and the "decode" steps. In this case, the
241   //    ResidualPtr variable passed into various functions starting from
242   //    ProcessSuperBlock is used as an in/out parameter to keep track of the
243   //    residual pointer.
244   // If |split_parse_and_decode_| is false:
245   //    The pointer is reset to the beginning of the |residual_buffer_| for
246   //    every transform block.
247   using ResidualPtr = uint8_t*;
248 
249   Tile(int tile_number, const uint8_t* data, size_t size,
250        const ObuSequenceHeader& sequence_header,
251        const ObuFrameHeader& frame_header, RefCountedBuffer* current_frame,
252        const DecoderState& state, FrameScratchBuffer* frame_scratch_buffer,
253        const WedgeMaskArray& wedge_masks,
254        const QuantizerMatrix& quantizer_matrix,
255        SymbolDecoderContext* saved_symbol_decoder_context,
256        const SegmentationMap* prev_segment_ids, PostFilter* post_filter,
257        const dsp::Dsp* dsp, ThreadPool* thread_pool,
258        BlockingCounterWithStatus* pending_tiles, bool frame_parallel,
259        bool use_intra_prediction_buffer, bool parse_only);
260 
261   // Performs member initializations that may fail. Helper function used by
262   // Create().
263   LIBGAV1_MUST_USE_RESULT bool Init();
264 
265   // Saves the symbol decoder context of this tile into
266   // |saved_symbol_decoder_context_| if necessary.
267   void SaveSymbolDecoderContext();
268 
269   // Entry point for multi-threaded decoding. This function performs the same
270   // functionality as ParseAndDecode(). The current thread does the "parse" step
271   // while the worker threads do the "decode" step.
272   bool ThreadedParseAndDecode();
273 
274   // Returns whether or not the prerequisites for decoding the superblock at
275   // |row_index| and |column_index| are satisfied. |threading_.mutex| must be
276   // held when calling this function.
277   bool CanDecode(int row_index, int column_index) const;
278 
279   // This function is run by the worker threads when multi-threaded decoding is
280   // enabled. Once a superblock is decoded, this function will set the
281   // corresponding |threading_.sb_state| entry to kSuperBlockStateDecoded. On
282   // failure, |threading_.abort| will be set to true. If at any point
283   // |threading_.abort| becomes true, this function will return as early as it
284   // can. If the decoding succeeds, this function will also schedule the
285   // decoding jobs for the superblock to the bottom-left and the superblock to
286   // the right of this superblock (if it is allowed).
287   void DecodeSuperBlock(int row_index, int column_index, int block_width4x4);
288 
289   // If |use_intra_prediction_buffer_| is true, then this function copies the
290   // last row of the superblockrow starting at |row4x4| into the
291   // |intra_prediction_buffer_| (which may be used by the intra prediction
292   // process for the next superblock row).
293   void PopulateIntraPredictionBuffer(int row4x4);
294 
295   uint16_t* GetPartitionCdf(int row4x4, int column4x4, BlockSize block_size);
296   bool ReadPartition(int row4x4, int column4x4, BlockSize block_size,
297                      bool has_rows, bool has_columns, Partition* partition);
298   // Processes the Partition starting at |row4x4_start|, |column4x4_start|
299   // iteratively. It performs a DFS traversal over the partition tree to process
300   // the blocks in the right order.
301   bool ProcessPartition(
302       int row4x4_start, int column4x4_start, TileScratchBuffer* scratch_buffer,
303       ResidualPtr* residual);  // Iterative implementation of 5.11.4.
304   bool ProcessBlock(int row4x4, int column4x4, BlockSize block_size,
305                     TileScratchBuffer* scratch_buffer,
306                     ResidualPtr* residual);   // 5.11.5.
307   void ResetCdef(int row4x4, int column4x4);  // 5.11.55.
308 
309   // This function is used to decode a superblock when the parsing has already
310   // been done for that superblock.
311   bool DecodeSuperBlock(int sb_row_index, int sb_column_index,
312                         TileScratchBuffer* scratch_buffer);
313   // Helper function used by DecodeSuperBlock(). Note that the decode_block()
314   // function in the spec is equivalent to ProcessBlock() in the code.
315   bool DecodeBlock(int row4x4, int column4x4, BlockSize block_size,
316                    TileScratchBuffer* scratch_buffer, ResidualPtr* residual);
317 
318   void ClearBlockDecoded(TileScratchBuffer* scratch_buffer, int row4x4,
319                          int column4x4);  // 5.11.3.
320   bool ProcessSuperBlock(int row4x4, int column4x4,
321                          TileScratchBuffer* scratch_buffer,
322                          ProcessingMode mode);
323   void ResetLoopRestorationParams();
324   void ReadLoopRestorationCoefficients(int row4x4, int column4x4,
325                                        BlockSize block_size);  // 5.11.57.
326 
327   // Helper functions for DecodeBlock.
328   bool ReadSegmentId(const Block& block);       // 5.11.9.
329   bool ReadIntraSegmentId(const Block& block);  // 5.11.8.
330   void ReadSkip(const Block& block);            // 5.11.11.
331   bool ReadSkipMode(const Block& block);        // 5.11.10.
332   void ReadCdef(const Block& block);            // 5.11.56.
333   // Returns the new value. |cdf| is an array of size kDeltaSymbolCount + 1.
334   int ReadAndClipDelta(uint16_t* cdf, int delta_small, int scale, int min_value,
335                        int max_value, int value);
336   void ReadQuantizerIndexDelta(const Block& block);  // 5.11.12.
337   void ReadLoopFilterDelta(const Block& block);      // 5.11.13.
338   // Populates |BlockParameters::deblock_filter_level| for the given |block|
339   // using |deblock_filter_levels_|.
340   void PopulateDeblockFilterLevel(const Block& block);
341   void PopulateCdefSkip(const Block& block);
342   void ReadPredictionModeY(const Block& block, bool intra_y_mode);
343   void ReadIntraAngleInfo(const Block& block,
344                           PlaneType plane_type);  // 5.11.42 and 5.11.43.
345   void ReadPredictionModeUV(const Block& block);
346   void ReadCflAlpha(const Block& block);  // 5.11.45.
347   int GetPaletteCache(const Block& block, PlaneType plane_type,
348                       uint16_t* cache);
349   void ReadPaletteColors(const Block& block, Plane plane);
350   void ReadPaletteModeInfo(const Block& block);      // 5.11.46.
351   void ReadFilterIntraModeInfo(const Block& block);  // 5.11.24.
352   int ReadMotionVectorComponent(const Block& block,
353                                 int component);                // 5.11.32.
354   void ReadMotionVector(const Block& block, int index);        // 5.11.31.
355   bool DecodeIntraModeInfo(const Block& block);                // 5.11.7.
356   int8_t ComputePredictedSegmentId(const Block& block) const;  // 5.11.21.
357   bool ReadInterSegmentId(const Block& block, bool pre_skip);  // 5.11.19.
358   void ReadIsInter(const Block& block, bool skip_mode);        // 5.11.20.
359   bool ReadIntraBlockModeInfo(const Block& block,
360                               bool intra_y_mode);  // 5.11.22.
361   CompoundReferenceType ReadCompoundReferenceType(const Block& block);
362   template <bool is_single, bool is_backward, int index>
363   uint16_t* GetReferenceCdf(const Block& block, CompoundReferenceType type =
364                                                     kNumCompoundReferenceTypes);
365   void ReadReferenceFrames(const Block& block, bool skip_mode);  // 5.11.25.
366   void ReadInterPredictionModeY(const Block& block,
367                                 const MvContexts& mode_contexts,
368                                 bool skip_mode);
369   void ReadRefMvIndex(const Block& block);
370   void ReadInterIntraMode(const Block& block, bool is_compound,
371                           bool skip_mode);        // 5.11.28.
IsScaled(ReferenceFrameType type)372   bool IsScaled(ReferenceFrameType type) const {  // Part of 5.11.27.
373     const int index =
374         frame_header_.reference_frame_index[type - kReferenceFrameLast];
375     return reference_frames_[index]->upscaled_width() != frame_header_.width ||
376            reference_frames_[index]->frame_height() != frame_header_.height;
377   }
378   void ReadMotionMode(const Block& block, bool is_compound,
379                       bool skip_mode);  // 5.11.27.
380   uint16_t* GetIsExplicitCompoundTypeCdf(const Block& block);
381   uint16_t* GetIsCompoundTypeAverageCdf(const Block& block);
382   void ReadCompoundType(const Block& block, bool is_compound, bool skip_mode,
383                         bool* is_explicit_compound_type,
384                         bool* is_compound_type_average);  // 5.11.29.
385   uint16_t* GetInterpolationFilterCdf(const Block& block, int direction);
386   void ReadInterpolationFilter(const Block& block, bool skip_mode);
387   bool ReadInterBlockModeInfo(const Block& block, bool skip_mode);  // 5.11.23.
388   bool DecodeInterModeInfo(const Block& block);                     // 5.11.18.
389   bool DecodeModeInfo(const Block& block);                          // 5.11.6.
390   bool IsMvValid(const Block& block, bool is_compound) const;       // 6.10.25.
391   bool AssignInterMv(const Block& block, bool is_compound);         // 5.11.26.
392   bool AssignIntraMv(const Block& block);                           // 5.11.26.
393   int GetTopTransformWidth(const Block& block, int row4x4, int column4x4,
394                            bool ignore_skip);
395   int GetLeftTransformHeight(const Block& block, int row4x4, int column4x4,
396                              bool ignore_skip);
397   TransformSize ReadFixedTransformSize(const Block& block);  // 5.11.15.
398   // Iterative implementation of 5.11.17.
399   void ReadVariableTransformTree(const Block& block, int row4x4, int column4x4,
400                                  TransformSize tx_size);
401   void DecodeTransformSize(const Block& block);  // 5.11.16.
402   bool ComputePrediction(const Block& block);    // 5.11.33.
403   // |x4| and |y4| are the column and row positions of the 4x4 block. |w4| and
404   // |h4| are the width and height in 4x4 units of |tx_size|.
405   int GetTransformAllZeroContext(const Block& block, Plane plane,
406                                  TransformSize tx_size, int x4, int y4, int w4,
407                                  int h4);
408   TransformSet GetTransformSet(TransformSize tx_size,
409                                bool is_inter) const;  // 5.11.48.
410   TransformType ComputeTransformType(const Block& block, Plane plane,
411                                      TransformSize tx_size, int block_x,
412                                      int block_y);  // 5.11.40.
413   void ReadTransformType(const Block& block, int x4, int y4,
414                          TransformSize tx_size);  // 5.11.47.
415   template <typename ResidualType>
416   void ReadCoeffBase2D(
417       const uint16_t* scan, TransformSize tx_size, int adjusted_tx_width_log2,
418       int eob,
419       uint16_t coeff_base_cdf[kCoeffBaseContexts][kCoeffBaseSymbolCount + 1],
420       uint16_t coeff_base_range_cdf[kCoeffBaseRangeContexts]
421                                    [kCoeffBaseRangeSymbolCount + 1],
422       ResidualType* quantized_buffer, uint8_t* level_buffer);
423   template <typename ResidualType>
424   void ReadCoeffBaseHorizontal(
425       const uint16_t* scan, TransformSize tx_size, int adjusted_tx_width_log2,
426       int eob,
427       uint16_t coeff_base_cdf[kCoeffBaseContexts][kCoeffBaseSymbolCount + 1],
428       uint16_t coeff_base_range_cdf[kCoeffBaseRangeContexts]
429                                    [kCoeffBaseRangeSymbolCount + 1],
430       ResidualType* quantized_buffer, uint8_t* level_buffer);
431   template <typename ResidualType>
432   void ReadCoeffBaseVertical(
433       const uint16_t* scan, TransformSize tx_size, int adjusted_tx_width_log2,
434       int eob,
435       uint16_t coeff_base_cdf[kCoeffBaseContexts][kCoeffBaseSymbolCount + 1],
436       uint16_t coeff_base_range_cdf[kCoeffBaseRangeContexts]
437                                    [kCoeffBaseRangeSymbolCount + 1],
438       ResidualType* quantized_buffer, uint8_t* level_buffer);
439   int GetDcSignContext(int x4, int y4, int w4, int h4, Plane plane);
440   void SetEntropyContexts(int x4, int y4, int w4, int h4, Plane plane,
441                           uint8_t coefficient_level, int8_t dc_category);
442   void InterIntraPrediction(
443       uint16_t* prediction_0, const uint8_t* prediction_mask,
444       ptrdiff_t prediction_mask_stride,
445       const PredictionParameters& prediction_parameters, int prediction_width,
446       int prediction_height, int subsampling_x, int subsampling_y,
447       uint8_t* dest,
448       ptrdiff_t dest_stride);  // Part of section 7.11.3.1 in the spec.
449   void CompoundInterPrediction(
450       const Block& block, const uint8_t* prediction_mask,
451       ptrdiff_t prediction_mask_stride, int prediction_width,
452       int prediction_height, int subsampling_x, int subsampling_y,
453       int candidate_row, int candidate_column, uint8_t* dest,
454       ptrdiff_t dest_stride);  // Part of section 7.11.3.1 in the spec.
455   GlobalMotion* GetWarpParams(const Block& block, Plane plane,
456                               int prediction_width, int prediction_height,
457                               const PredictionParameters& prediction_parameters,
458                               ReferenceFrameType reference_type,
459                               bool* is_local_valid,
460                               GlobalMotion* global_motion_params,
461                               GlobalMotion* local_warp_params)
462       const;  // Part of section 7.11.3.1 in the spec.
463   bool InterPrediction(const Block& block, Plane plane, int x, int y,
464                        int prediction_width, int prediction_height,
465                        int candidate_row, int candidate_column,
466                        bool* is_local_valid,
467                        GlobalMotion* local_warp_params);  // 7.11.3.1.
468   void ScaleMotionVector(const MotionVector& mv, Plane plane,
469                          int reference_frame_index, int x, int y, int* start_x,
470                          int* start_y, int* step_x, int* step_y);  // 7.11.3.3.
471   // If the method returns false, the caller only uses the output parameters
472   // *ref_block_start_x and *ref_block_start_y. If the method returns true, the
473   // caller uses all four output parameters.
474   static bool GetReferenceBlockPosition(
475       int reference_frame_index, bool is_scaled, int width, int height,
476       int ref_start_x, int ref_last_x, int ref_start_y, int ref_last_y,
477       int start_x, int start_y, int step_x, int step_y, int left_border,
478       int right_border, int top_border, int bottom_border,
479       int* ref_block_start_x, int* ref_block_start_y, int* ref_block_end_x,
480       int* ref_block_end_y);
481 
482   template <typename Pixel>
483   void BuildConvolveBlock(Plane plane, int reference_frame_index,
484                           bool is_scaled, int height, int ref_start_x,
485                           int ref_last_x, int ref_start_y, int ref_last_y,
486                           int step_y, int ref_block_start_x,
487                           int ref_block_end_x, int ref_block_start_y,
488                           uint8_t* block_buffer,
489                           ptrdiff_t convolve_buffer_stride,
490                           ptrdiff_t block_extended_width);
491   bool BlockInterPrediction(const Block& block, Plane plane,
492                             int reference_frame_index, const MotionVector& mv,
493                             int x, int y, int width, int height,
494                             int candidate_row, int candidate_column,
495                             uint16_t* prediction, bool is_compound,
496                             bool is_inter_intra, uint8_t* dest,
497                             ptrdiff_t dest_stride);  // 7.11.3.4.
498   bool BlockWarpProcess(const Block& block, Plane plane, int index,
499                         int block_start_x, int block_start_y, int width,
500                         int height, GlobalMotion* warp_params, bool is_compound,
501                         bool is_inter_intra, uint8_t* dest,
502                         ptrdiff_t dest_stride);  // 7.11.3.5.
503   bool ObmcBlockPrediction(const Block& block, const MotionVector& mv,
504                            Plane plane, int reference_frame_index, int width,
505                            int height, int x, int y, int candidate_row,
506                            int candidate_column,
507                            ObmcDirection blending_direction);
508   bool ObmcPrediction(const Block& block, Plane plane, int width,
509                       int height);  // 7.11.3.9.
510   void DistanceWeightedPrediction(void* prediction_0, void* prediction_1,
511                                   int width, int height, int candidate_row,
512                                   int candidate_column, uint8_t* dest,
513                                   ptrdiff_t dest_stride);  // 7.11.3.15.
514   // This function specializes the parsing of DC coefficient by removing some of
515   // the branches when i == 0 (since scan[0] is always 0 and scan[i] is always
516   // non-zero for all other possible values of i). |dc_category| is an output
517   // parameter that is populated when |is_dc_coefficient| is true.
518   // |coefficient_level| is an output parameter which accumulates the
519   // coefficient level.
520   template <typename ResidualType, bool is_dc_coefficient>
521   LIBGAV1_ALWAYS_INLINE bool ReadSignAndApplyDequantization(
522       const uint16_t* scan, int i, int q_value, const uint8_t* quantizer_matrix,
523       int shift, int max_value, uint16_t* dc_sign_cdf, int8_t* dc_category,
524       int* coefficient_level,
525       ResidualType* residual_buffer);     // Part of 5.11.39.
526   int ReadCoeffBaseRange(uint16_t* cdf);  // Part of 5.11.39.
527   // Returns the number of non-zero coefficients that were read. |tx_type| is an
528   // output parameter that stores the computed transform type for the plane
529   // whose coefficients were read. Returns -1 on failure.
530   template <typename ResidualType>
531   int ReadTransformCoefficients(const Block& block, Plane plane, int start_x,
532                                 int start_y, TransformSize tx_size,
533                                 TransformType* tx_type);  // 5.11.39.
534   bool TransformBlock(const Block& block, Plane plane, int base_x, int base_y,
535                       TransformSize tx_size, int x, int y,
536                       ProcessingMode mode);  // 5.11.35.
537   // Iterative implementation of 5.11.36.
538   bool TransformTree(const Block& block, int start_x, int start_y,
539                      BlockSize plane_size, ProcessingMode mode);
540   void ReconstructBlock(const Block& block, Plane plane, int start_x,
541                         int start_y, TransformSize tx_size,
542                         TransformType tx_type,
543                         int non_zero_coeff_count);         // Part of 7.12.3.
544   bool Residual(const Block& block, ProcessingMode mode);  // 5.11.34.
545   // part of 5.11.5 (reset_block_context() in the spec).
546   void ResetEntropyContext(const Block& block);
547   // Populates the |color_context| and |color_order| for the |i|th iteration
548   // with entries counting down from |start| to |end| (|start| > |end|).
549   void PopulatePaletteColorContexts(
550       const Block& block, PlaneType plane_type, int i, int start, int end,
551       uint8_t color_order[kMaxPaletteSquare][kMaxPaletteSize],
552       uint8_t color_context[kMaxPaletteSquare]);  // 5.11.50.
553   bool ReadPaletteTokens(const Block& block);     // 5.11.49.
554   template <typename Pixel>
555   void IntraPrediction(const Block& block, Plane plane, int x, int y,
556                        bool has_left, bool has_top, bool has_top_right,
557                        bool has_bottom_left, PredictionMode mode,
558                        TransformSize tx_size);
559   int GetIntraEdgeFilterType(const Block& block,
560                              Plane plane) const;  // 7.11.2.8.
561   template <typename Pixel>
562   void DirectionalPrediction(const Block& block, Plane plane, int x, int y,
563                              bool has_left, bool has_top, bool needs_left,
564                              bool needs_top, int prediction_angle, int width,
565                              int height, int max_x, int max_y,
566                              TransformSize tx_size, Pixel* top_row,
567                              Pixel* left_column);  // 7.11.2.4.
568   template <typename Pixel>
569   void PalettePrediction(const Block& block, Plane plane, int start_x,
570                          int start_y, int x, int y,
571                          TransformSize tx_size);  // 7.11.4.
572   template <typename Pixel>
573   void ChromaFromLumaPrediction(const Block& block, Plane plane, int start_x,
574                                 int start_y,
575                                 TransformSize tx_size);  // 7.11.5.
576   // Section 7.19. Applies some filtering and reordering to the motion vectors
577   // for the given |block| and stores them into |current_frame_|.
578   void StoreMotionFieldMvsIntoCurrentFrame(const Block& block);
579 
580   // SetCdfContext*() functions will populate the |left_context_| and
581   // |top_context_| for the |block|.
582   void SetCdfContextUsePredictedSegmentId(const Block& block,
583                                           bool use_predicted_segment_id);
584   void SetCdfContextCompoundType(const Block& block,
585                                  bool is_explicit_compound_type,
586                                  bool is_compound_type_average);
587   void SetCdfContextSkipMode(const Block& block, bool skip_mode);
588   void SetCdfContextPaletteSize(const Block& block);
589   void SetCdfContextUVMode(const Block& block);
590 
591   // Returns the zero-based index of the super block that contains |row4x4|
592   // relative to the start of this tile.
SuperBlockRowIndex(int row4x4)593   int SuperBlockRowIndex(int row4x4) const {
594     return (row4x4 - row4x4_start_) >>
595            (sequence_header_.use_128x128_superblock ? 5 : 4);
596   }
597 
598   // Returns the zero-based index of the super block that contains |column4x4|
599   // relative to the start of this tile.
SuperBlockColumnIndex(int column4x4)600   int SuperBlockColumnIndex(int column4x4) const {
601     return (column4x4 - column4x4_start_) >>
602            (sequence_header_.use_128x128_superblock ? 5 : 4);
603   }
604 
605   // Returns the zero-based index of the block that starts at row4x4 or
606   // column4x4 relative to the start of the superblock that contains the block.
607   // This is used to index into the members of |left_context_| and
608   // |top_context_|.
CdfContextIndex(int row_or_column4x4)609   int CdfContextIndex(int row_or_column4x4) const {
610     return row_or_column4x4 -
611            (row_or_column4x4 &
612             (sequence_header_.use_128x128_superblock ? ~31 : ~15));
613   }
614 
SuperBlockSize()615   BlockSize SuperBlockSize() const {
616     return sequence_header_.use_128x128_superblock ? kBlock128x128
617                                                    : kBlock64x64;
618   }
PlaneCount()619   int PlaneCount() const {
620     return sequence_header_.color_config.is_monochrome ? kMaxPlanesMonochrome
621                                                        : kMaxPlanes;
622   }
623 
624   const int number_;
625   const int row_;
626   const int column_;
627   const uint8_t* const data_;
628   size_t size_;
629   int row4x4_start_;
630   int row4x4_end_;
631   int column4x4_start_;
632   int column4x4_end_;
633   int superblock_rows_;
634   int superblock_columns_;
635   bool read_deltas_;
636   const int8_t subsampling_x_[kMaxPlanes];
637   const int8_t subsampling_y_[kMaxPlanes];
638 
639   // The dimensions (in order) are: segment_id, level_index (based on plane and
640   // direction), reference_frame and mode_id.
641   uint8_t deblock_filter_levels_[kMaxSegments][kFrameLfCount]
642                                 [kNumReferenceFrameTypes][2];
643 
644   // current_quantizer_index_ is in the range [0, 255].
645   uint8_t current_quantizer_index_;
646   // The weighted sum of the QP values per block for a tile. The weights are in
647   // terms of 4x4 blocks. E.g., a block of size 32x16 has the weight 32/4 *
648   // 16/4.
649   int64_t weighted_cumulative_block_qp_ = 0;
650   // The sums of the weights per block in a tile.
651   int64_t cumulative_block_weights_ = 0;
652 
653   // These two arrays (|coefficient_levels_| and |dc_categories_|) are used to
654   // store the entropy context. Their dimensions are as follows: First -
655   // left/top; Second - plane; Third - row4x4 (if first dimension is
656   // left)/column4x4 (if first dimension is top).
657   //
658   // This is equivalent to the LeftLevelContext and AboveLevelContext arrays in
659   // the spec. In the spec, it stores values from 0 through 63 (inclusive). The
660   // stored values are used to compute the left and top contexts in
661   // GetTransformAllZeroContext. In that function, we only care about the
662   // following values: 0, 1, 2, 3 and >= 4. So instead of clamping to 63, we
663   // clamp to 4 (i.e.) all the values greater than 4 are stored as 4.
664   std::array<Array2D<uint8_t>, 2> coefficient_levels_;
665   // This is equivalent to the LeftDcContext and AboveDcContext arrays in the
666   // spec. In the spec, it can store 3 possible values: 0, 1 and 2 (where 1
667   // means the value is < 0, 2 means the value is > 0 and 0 means the value is
668   // equal to 0).
669   //
670   // The stored values are used in two places:
671   //  * GetTransformAllZeroContext: Here, we only care about whether the
672   //  value is 0 or not (whether it is 1 or 2 is irrelevant).
673   //  * GetDcSignContext: Here, we do the following computation: if the
674   //  stored value is 1, we decrement a counter. If the stored value is 2
675   //  we increment a counter.
676   //
677   // Based on this usage, we can simply replace 1 with -1 and 2 with 1 and
678   // use that value to compute the counter.
679   //
680   // The usage on GetTransformAllZeroContext is unaffected since there we
681   // only care about whether it is 0 or not.
682   std::array<Array2D<int8_t>, 2> dc_categories_;
683   const ObuSequenceHeader& sequence_header_;
684   const ObuFrameHeader& frame_header_;
685   const std::array<bool, kNumReferenceFrameTypes>& reference_frame_sign_bias_;
686   const std::array<RefCountedBufferPtr, kNumReferenceFrameTypes>&
687       reference_frames_;
688   TemporalMotionField& motion_field_;
689   const std::array<uint8_t, kNumReferenceFrameTypes>& reference_order_hint_;
690   const WedgeMaskArray& wedge_masks_;
691   const QuantizerMatrix& quantizer_matrix_;
692   EntropyDecoder reader_;
693   SymbolDecoderContext symbol_decoder_context_;
694   SymbolDecoderContext* const saved_symbol_decoder_context_;
695   const SegmentationMap* prev_segment_ids_;
696   const dsp::Dsp& dsp_;
697   PostFilter& post_filter_;
698   BlockParametersHolder& block_parameters_holder_;
699   Quantizer quantizer_;
700   // When there is no multi-threading within the Tile, |residual_buffer_| is
701   // used. When there is multi-threading within the Tile,
702   // |residual_buffer_threaded_| is used. In the following comment,
703   // |residual_buffer| refers to either |residual_buffer_| or
704   // |residual_buffer_threaded_| depending on whether multi-threading is enabled
705   // within the Tile or not.
706   // The |residual_buffer| is used to help with the dequantization and the
707   // inverse transform processes. It is declared as a uint8_t, but is always
708   // accessed either as an int16_t or int32_t depending on |bitdepth|. Here is
709   // what it stores at various stages of the decoding process (in the order
710   // which they happen):
711   //   1) In ReadTransformCoefficients(), this buffer is used to store the
712   //   dequantized values.
713   //   2) In Reconstruct(), this buffer is used as the input to the row
714   //   transform process.
715   // The size of this buffer would be:
716   //    For |residual_buffer_|: (4096 + 32 * |kResidualPaddingVertical|) *
717   //        |residual_size_|. Where 4096 = 64x64 which is the maximum transform
718   //        size, and 32 * |kResidualPaddingVertical| is the padding to avoid
719   //        bottom boundary checks when parsing quantized coefficients. This
720   //        memory is allocated and owned by the Tile class.
721   //    For |residual_buffer_threaded_|: See the comment below. This memory is
722   //        not allocated or owned by the Tile class.
723   AlignedUniquePtr<uint8_t> residual_buffer_;
724   // This is a 2d array of pointers of size |superblock_rows_| by
725   // |superblock_columns_| where each pointer points to a ResidualBuffer for a
726   // single super block. The array is populated when the parsing process begins
727   // by calling |residual_buffer_pool_->Get()| and the memory is released back
728   // to the pool by calling |residual_buffer_pool_->Release()| when the decoding
729   // process is complete.
730   Array2D<std::unique_ptr<ResidualBuffer>> residual_buffer_threaded_;
731   // sizeof(int16_t or int32_t) depending on |bitdepth|.
732   const size_t residual_size_;
733   // Number of superblocks on the top-right that will have to be decoded before
734   // the current superblock can be decoded. This will be 1 if allow_intrabc is
735   // false. If allow_intrabc is true, then this value will be
736   // use_128x128_superblock ? 3 : 5. This is the allowed range of reference for
737   // the top rows for intrabc.
738   const int intra_block_copy_lag_;
739 
740   // In the Tile class, we use the "current_frame" in two ways:
741   //   1) To write the decoded output into (using the |buffer_| view).
742   //   2) To read the pixels for intra block copy (using the |current_frame_|
743   //      reference).
744   //
745   // When intra block copy is off, |buffer_| and |current_frame_| may or may not
746   // point to the same plane pointers. But it is okay since |current_frame_| is
747   // never used in this case.
748   //
749   // When intra block copy is on, |buffer_| and |current_frame_| always point to
750   // the same plane pointers (since post filtering is disabled). So the usage in
751   // both case 1 and case 2 remain valid.
752   Array2DView<uint8_t> buffer_[kMaxPlanes];
753   RefCountedBuffer& current_frame_;
754 
755   Array2D<int8_t>& cdef_index_;
756   Array2D<uint8_t>& cdef_skip_;
757   Array2D<TransformSize>& inter_transform_sizes_;
758   std::array<RestorationUnitInfo, kMaxPlanes> reference_unit_info_;
759   // If |thread_pool_| is nullptr, the calling thread will do the parsing and
760   // the decoding in one pass. If |thread_pool_| is not nullptr, then the main
761   // thread will do the parsing while the thread pool workers will do the
762   // decoding.
763   ThreadPool* const thread_pool_;
764   ThreadingParameters threading_;
765   ResidualBufferPool* const residual_buffer_pool_;
766   TileScratchBufferPool* const tile_scratch_buffer_pool_;
767   BlockingCounterWithStatus* const pending_tiles_;
768   bool split_parse_and_decode_;
769   // This is used only when |split_parse_and_decode_| is false.
770   std::unique_ptr<PredictionParameters> prediction_parameters_ = nullptr;
771   // Stores the |transform_type| for the super block being decoded at a 4x4
772   // granularity. The spec uses absolute indices for this array but it is
773   // sufficient to use indices relative to the super block being decoded.
774   TransformType transform_types_[32][32];
775   // delta_lf_[i] is in the range [-63, 63].
776   int8_t delta_lf_[kFrameLfCount];
777   // True if all the values in |delta_lf_| are zero. False otherwise.
778   bool delta_lf_all_zero_;
779   const bool frame_parallel_;
780   const bool use_intra_prediction_buffer_;
781   // Buffer used to store the unfiltered pixels that are necessary for decoding
782   // the next superblock row (for the intra prediction process). Used only if
783   // |use_intra_prediction_buffer_| is true. The |frame_scratch_buffer| contains
784   // one row buffer for each tile row. This tile will have to use the buffer
785   // corresponding to this tile's row.
786   IntraPredictionBuffer* const intra_prediction_buffer_;
787   // Stores the progress of the reference frames. This will be used to avoid
788   // unnecessary calls into RefCountedBuffer::WaitUntil().
789   std::array<int, kNumReferenceFrameTypes> reference_frame_progress_cache_;
790   // Stores the CDF contexts necessary for the "left" block.
791   BlockCdfContext left_context_;
792   // Stores the CDF contexts necessary for the "top" block. The size of this
793   // buffer is the number of superblock columns in this tile. For each block,
794   // the access index will be the corresponding SuperBlockColumnIndex()'th
795   // entry.
796   DynamicBuffer<BlockCdfContext> top_context_;
797   // Whether the tile should only be parsed and not decoded.
798   const bool parse_only_;
799 };
800 
801 struct Tile::Block {
BlockBlock802   Block(Tile* tile_ptr, BlockSize size, int row4x4, int column4x4,
803         TileScratchBuffer* const scratch_buffer, ResidualPtr* residual)
804       : tile(*tile_ptr),
805         size(size),
806         row4x4(row4x4),
807         column4x4(column4x4),
808         width(kBlockWidthPixels[size]),
809         height(kBlockHeightPixels[size]),
810         width4x4(width >> 2),
811         height4x4(height >> 2),
812         scratch_buffer(scratch_buffer),
813         residual(residual),
814         top_context(tile.top_context_.get() +
815                     tile.SuperBlockColumnIndex(column4x4)),
816         top_context_index(tile.CdfContextIndex(column4x4)),
817         left_context_index(tile.CdfContextIndex(row4x4)) {
818     assert(size != kBlockInvalid);
819     residual_size[kPlaneY] = kPlaneResidualSize[size][0][0];
820     residual_size[kPlaneU] = residual_size[kPlaneV] =
821         kPlaneResidualSize[size][tile.subsampling_x_[kPlaneU]]
822                           [tile.subsampling_y_[kPlaneU]];
823     assert(residual_size[kPlaneY] != kBlockInvalid);
824     if (tile.PlaneCount() > 1) {
825       assert(residual_size[kPlaneU] != kBlockInvalid);
826     }
827     if ((row4x4 & 1) == 0 &&
828         (tile.sequence_header_.color_config.subsampling_y & height4x4) == 1) {
829       has_chroma = false;
830     } else if ((column4x4 & 1) == 0 &&
831                (tile.sequence_header_.color_config.subsampling_x & width4x4) ==
832                    1) {
833       has_chroma = false;
834     } else {
835       has_chroma = !tile.sequence_header_.color_config.is_monochrome;
836     }
837     top_available[kPlaneY] = tile.IsTopInside(row4x4);
838     left_available[kPlaneY] = tile.IsLeftInside(column4x4);
839     if (has_chroma) {
840       // top_available[kPlaneU] and top_available[kPlaneV] are valid only if
841       // has_chroma is true.
842       // The next 3 lines are equivalent to:
843       // top_available[kPlaneU] = top_available[kPlaneV] =
844       //     top_available[kPlaneY] &&
845       //     ((tile.sequence_header_.color_config.subsampling_y & height4x4) ==
846       //     0 || tile.IsTopInside(row4x4 - 1));
847       top_available[kPlaneU] = top_available[kPlaneV] = tile.IsTopInside(
848           row4x4 -
849           (tile.sequence_header_.color_config.subsampling_y & height4x4));
850       // left_available[kPlaneU] and left_available[kPlaneV] are valid only if
851       // has_chroma is true.
852       // The next 3 lines are equivalent to:
853       // left_available[kPlaneU] = left_available[kPlaneV] =
854       //     left_available[kPlaneY] &&
855       //     ((tile.sequence_header_.color_config.subsampling_x & width4x4) == 0
856       //      || tile.IsLeftInside(column4x4 - 1));
857       left_available[kPlaneU] = left_available[kPlaneV] = tile.IsLeftInside(
858           column4x4 -
859           (tile.sequence_header_.color_config.subsampling_x & width4x4));
860     }
861     const ptrdiff_t stride = tile.BlockParametersStride();
862     BlockParameters** const bps =
863         tile.BlockParametersAddress(row4x4, column4x4);
864     bp = *bps;
865     // bp_top is valid only if top_available[kPlaneY] is true.
866     if (top_available[kPlaneY]) {
867       bp_top = *(bps - stride);
868     }
869     // bp_left is valid only if left_available[kPlaneY] is true.
870     if (left_available[kPlaneY]) {
871       bp_left = *(bps - 1);
872     }
873   }
874 
HasChromaBlock875   bool HasChroma() const { return has_chroma; }
876 
877   // These return values of these group of functions are valid only if the
878   // corresponding top_available or left_available is true.
TopReferenceBlock879   ReferenceFrameType TopReference(int index) const {
880     return bp_top->reference_frame[index];
881   }
882 
LeftReferenceBlock883   ReferenceFrameType LeftReference(int index) const {
884     return bp_left->reference_frame[index];
885   }
886 
IsTopIntraBlock887   bool IsTopIntra() const { return TopReference(0) <= kReferenceFrameIntra; }
IsLeftIntraBlock888   bool IsLeftIntra() const { return LeftReference(0) <= kReferenceFrameIntra; }
889 
IsTopSingleBlock890   bool IsTopSingle() const { return TopReference(1) <= kReferenceFrameIntra; }
IsLeftSingleBlock891   bool IsLeftSingle() const { return LeftReference(1) <= kReferenceFrameIntra; }
892 
CountReferencesBlock893   int CountReferences(ReferenceFrameType type) const {
894     return static_cast<int>(top_available[kPlaneY] &&
895                             bp_top->reference_frame[0] == type) +
896            static_cast<int>(top_available[kPlaneY] &&
897                             bp_top->reference_frame[1] == type) +
898            static_cast<int>(left_available[kPlaneY] &&
899                             bp_left->reference_frame[0] == type) +
900            static_cast<int>(left_available[kPlaneY] &&
901                             bp_left->reference_frame[1] == type);
902   }
903 
904   // 7.10.3.
905   // Checks if there are any inter blocks to the left or above. If so, it
906   // returns true indicating that the block has neighbors that are suitable for
907   // use by overlapped motion compensation.
HasOverlappableCandidatesBlock908   bool HasOverlappableCandidates() const {
909     const ptrdiff_t stride = tile.BlockParametersStride();
910     BlockParameters** const bps = tile.BlockParametersAddress(0, 0);
911     if (top_available[kPlaneY]) {
912       BlockParameters** bps_top = bps + (row4x4 - 1) * stride + (column4x4 | 1);
913       const int columns = std::min(tile.frame_header_.columns4x4 - column4x4,
914                                    static_cast<int>(width4x4));
915       BlockParameters** const bps_top_end = bps_top + columns;
916       do {
917         if ((*bps_top)->reference_frame[0] > kReferenceFrameIntra) {
918           return true;
919         }
920         bps_top += 2;
921       } while (bps_top < bps_top_end);
922     }
923     if (left_available[kPlaneY]) {
924       BlockParameters** bps_left = bps + (row4x4 | 1) * stride + column4x4 - 1;
925       const int rows = std::min(tile.frame_header_.rows4x4 - row4x4,
926                                 static_cast<int>(height4x4));
927       BlockParameters** const bps_left_end = bps_left + rows * stride;
928       do {
929         if ((*bps_left)->reference_frame[0] > kReferenceFrameIntra) {
930           return true;
931         }
932         bps_left += 2 * stride;
933       } while (bps_left < bps_left_end);
934     }
935     return false;
936   }
937 
938   Tile& tile;
939   bool has_chroma;
940   const BlockSize size;
941   bool top_available[kMaxPlanes];
942   bool left_available[kMaxPlanes];
943   BlockSize residual_size[kMaxPlanes];
944   const int row4x4;
945   const int column4x4;
946   const int width;
947   const int height;
948   const int width4x4;
949   const int height4x4;
950   const BlockParameters* bp_top;
951   const BlockParameters* bp_left;
952   BlockParameters* bp;
953   TileScratchBuffer* const scratch_buffer;
954   ResidualPtr* const residual;
955   BlockCdfContext* const top_context;
956   const int top_context_index;
957   const int left_context_index;
958 };
959 
960 extern template bool
961 Tile::ProcessSuperBlockRow<kProcessingModeDecodeOnly, false>(
962     int row4x4, TileScratchBuffer* scratch_buffer);
963 extern template bool
964 Tile::ProcessSuperBlockRow<kProcessingModeParseAndDecode, true>(
965     int row4x4, TileScratchBuffer* scratch_buffer);
966 
967 }  // namespace libgav1
968 
969 #endif  // LIBGAV1_SRC_TILE_H_
970