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