• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <algorithm>
16 #include <array>
17 #include <cassert>
18 #include <cstdint>
19 #include <cstdlib>
20 #include <cstring>
21 #include <memory>
22 #include <vector>
23 
24 #include "src/buffer_pool.h"
25 #include "src/dsp/constants.h"
26 #include "src/motion_vector.h"
27 #include "src/obu_parser.h"
28 #include "src/prediction_mask.h"
29 #include "src/symbol_decoder_context.h"
30 #include "src/tile.h"
31 #include "src/utils/array_2d.h"
32 #include "src/utils/bit_mask_set.h"
33 #include "src/utils/block_parameters_holder.h"
34 #include "src/utils/common.h"
35 #include "src/utils/constants.h"
36 #include "src/utils/entropy_decoder.h"
37 #include "src/utils/logging.h"
38 #include "src/utils/segmentation.h"
39 #include "src/utils/segmentation_map.h"
40 #include "src/utils/types.h"
41 
42 namespace libgav1 {
43 namespace {
44 
45 constexpr int kDeltaQSmall = 3;
46 constexpr int kDeltaLfSmall = 3;
47 constexpr int kNoScale = 1 << kReferenceFrameScalePrecision;
48 
49 constexpr uint8_t kIntraYModeContext[kIntraPredictionModesY] = {
50     0, 1, 2, 3, 4, 4, 4, 4, 3, 0, 1, 2, 0};
51 
52 constexpr uint8_t kSizeGroup[kMaxBlockSizes] = {
53     0, 0, 0, 0, 1, 1, 1, 0, 1, 2, 2, 2, 1, 2, 3, 3, 2, 3, 3, 3, 3, 3};
54 
55 constexpr int kCompoundModeNewMvContexts = 5;
56 constexpr uint8_t kCompoundModeContextMap[3][kCompoundModeNewMvContexts] = {
57     {0, 1, 1, 1, 1}, {1, 2, 3, 4, 4}, {4, 4, 5, 6, 7}};
58 
59 enum CflSign : uint8_t {
60   kCflSignZero = 0,
61   kCflSignNegative = 1,
62   kCflSignPositive = 2
63 };
64 
65 // For each possible value of the combined signs (which is read from the
66 // bitstream), this array stores the following: sign_u, sign_v, alpha_u_context,
67 // alpha_v_context. Only positive entries are used. Entry at index i is computed
68 // as follows:
69 // sign_u = i / 3
70 // sign_v = i % 3
71 // alpha_u_context = i - 2
72 // alpha_v_context = (sign_v - 1) * 3 + sign_u
73 constexpr int8_t kCflAlphaLookup[kCflAlphaSignsSymbolCount][4] = {
74     {0, 1, -2, 0}, {0, 2, -1, 3}, {1, 0, 0, -2}, {1, 1, 1, 1},
75     {1, 2, 2, 4},  {2, 0, 3, -1}, {2, 1, 4, 2},  {2, 2, 5, 5},
76 };
77 
78 constexpr BitMaskSet kPredictionModeHasNearMvMask(kPredictionModeNearMv,
79                                                   kPredictionModeNearNearMv,
80                                                   kPredictionModeNearNewMv,
81                                                   kPredictionModeNewNearMv);
82 
83 constexpr BitMaskSet kIsInterIntraModeAllowedMask(kBlock8x8, kBlock8x16,
84                                                   kBlock16x8, kBlock16x16,
85                                                   kBlock16x32, kBlock32x16,
86                                                   kBlock32x32);
87 
IsBackwardReference(ReferenceFrameType type)88 bool IsBackwardReference(ReferenceFrameType type) {
89   return type >= kReferenceFrameBackward && type <= kReferenceFrameAlternate;
90 }
91 
IsSameDirectionReferencePair(ReferenceFrameType type1,ReferenceFrameType type2)92 bool IsSameDirectionReferencePair(ReferenceFrameType type1,
93                                   ReferenceFrameType type2) {
94   return (type1 >= kReferenceFrameBackward) ==
95          (type2 >= kReferenceFrameBackward);
96 }
97 
98 // This is called neg_deinterleave() in the spec.
DecodeSegmentId(int diff,int reference,int max)99 int DecodeSegmentId(int diff, int reference, int max) {
100   if (reference == 0) return diff;
101   if (reference >= max - 1) return max - diff - 1;
102   const int value = ((diff & 1) != 0) ? reference + ((diff + 1) >> 1)
103                                       : reference - (diff >> 1);
104   const int reference2 = (reference << 1);
105   if (reference2 < max) {
106     return (diff <= reference2) ? value : diff;
107   }
108   return (diff <= ((max - reference - 1) << 1)) ? value : max - (diff + 1);
109 }
110 
111 // This is called DrlCtxStack in section 7.10.2.14 of the spec.
112 // In the spec, the weights of all the nearest mvs are incremented by a bonus
113 // weight which is larger than any natural weight, and the weights of the mvs
114 // are compared with this bonus weight to determine their contexts. We replace
115 // this procedure by introducing |nearest_mv_count| in PredictionParameters,
116 // which records the count of the nearest mvs. Since all the nearest mvs are in
117 // the beginning of the mv stack, the |index| of a mv in the mv stack can be
118 // compared with |nearest_mv_count| to get that mv's context.
GetRefMvIndexContext(int nearest_mv_count,int index)119 int GetRefMvIndexContext(int nearest_mv_count, int index) {
120   if (index + 1 < nearest_mv_count) {
121     return 0;
122   }
123   if (index + 1 == nearest_mv_count) {
124     return 1;
125   }
126   return 2;
127 }
128 
129 // Returns true if both the width and height of the block is less than 64.
IsBlockDimensionLessThan64(BlockSize size)130 bool IsBlockDimensionLessThan64(BlockSize size) {
131   return size <= kBlock32x32 && size != kBlock16x64;
132 }
133 
GetUseCompoundReferenceContext(const Tile::Block & block)134 int GetUseCompoundReferenceContext(const Tile::Block& block) {
135   if (block.top_available[kPlaneY] && block.left_available[kPlaneY]) {
136     if (block.IsTopSingle() && block.IsLeftSingle()) {
137       return static_cast<int>(IsBackwardReference(block.TopReference(0))) ^
138              static_cast<int>(IsBackwardReference(block.LeftReference(0)));
139     }
140     if (block.IsTopSingle()) {
141       return 2 + static_cast<int>(IsBackwardReference(block.TopReference(0)) ||
142                                   block.IsTopIntra());
143     }
144     if (block.IsLeftSingle()) {
145       return 2 + static_cast<int>(IsBackwardReference(block.LeftReference(0)) ||
146                                   block.IsLeftIntra());
147     }
148     return 4;
149   }
150   if (block.top_available[kPlaneY]) {
151     return block.IsTopSingle()
152                ? static_cast<int>(IsBackwardReference(block.TopReference(0)))
153                : 3;
154   }
155   if (block.left_available[kPlaneY]) {
156     return block.IsLeftSingle()
157                ? static_cast<int>(IsBackwardReference(block.LeftReference(0)))
158                : 3;
159   }
160   return 1;
161 }
162 
163 // Calculates count0 by calling block.CountReferences() on the frame types from
164 // type0_start to type0_end, inclusive, and summing the results.
165 // Calculates count1 by calling block.CountReferences() on the frame types from
166 // type1_start to type1_end, inclusive, and summing the results.
167 // Compares count0 with count1 and returns 0, 1 or 2.
168 //
169 // See count_refs and ref_count_ctx in 8.3.2.
GetReferenceContext(const Tile::Block & block,ReferenceFrameType type0_start,ReferenceFrameType type0_end,ReferenceFrameType type1_start,ReferenceFrameType type1_end)170 int GetReferenceContext(const Tile::Block& block,
171                         ReferenceFrameType type0_start,
172                         ReferenceFrameType type0_end,
173                         ReferenceFrameType type1_start,
174                         ReferenceFrameType type1_end) {
175   int count0 = 0;
176   int count1 = 0;
177   for (int type = type0_start; type <= type0_end; ++type) {
178     count0 += block.CountReferences(static_cast<ReferenceFrameType>(type));
179   }
180   for (int type = type1_start; type <= type1_end; ++type) {
181     count1 += block.CountReferences(static_cast<ReferenceFrameType>(type));
182   }
183   return (count0 < count1) ? 0 : (count0 == count1 ? 1 : 2);
184 }
185 
186 }  // namespace
187 
ReadSegmentId(const Block & block)188 bool Tile::ReadSegmentId(const Block& block) {
189   int top_left = -1;
190   if (block.top_available[kPlaneY] && block.left_available[kPlaneY]) {
191     top_left =
192         block_parameters_holder_.Find(block.row4x4 - 1, block.column4x4 - 1)
193             ->segment_id;
194   }
195   int top = -1;
196   if (block.top_available[kPlaneY]) {
197     top = block.bp_top->segment_id;
198   }
199   int left = -1;
200   if (block.left_available[kPlaneY]) {
201     left = block.bp_left->segment_id;
202   }
203   int pred;
204   if (top == -1) {
205     pred = (left == -1) ? 0 : left;
206   } else if (left == -1) {
207     pred = top;
208   } else {
209     pred = (top_left == top) ? top : left;
210   }
211   BlockParameters& bp = *block.bp;
212   if (bp.skip) {
213     bp.segment_id = pred;
214     return true;
215   }
216   int context = 0;
217   if (top_left < 0) {
218     context = 0;
219   } else if (top_left == top && top_left == left) {
220     context = 2;
221   } else if (top_left == top || top_left == left || top == left) {
222     context = 1;
223   }
224   uint16_t* const segment_id_cdf =
225       symbol_decoder_context_.segment_id_cdf[context];
226   const int encoded_segment_id =
227       reader_.ReadSymbol<kMaxSegments>(segment_id_cdf);
228   bp.segment_id =
229       DecodeSegmentId(encoded_segment_id, pred,
230                       frame_header_.segmentation.last_active_segment_id + 1);
231   // Check the bitstream conformance requirement in Section 6.10.8 of the spec.
232   if (bp.segment_id < 0 ||
233       bp.segment_id > frame_header_.segmentation.last_active_segment_id) {
234     LIBGAV1_DLOG(
235         ERROR,
236         "Corrupted segment_ids: encoded %d, last active %d, postprocessed %d",
237         encoded_segment_id, frame_header_.segmentation.last_active_segment_id,
238         bp.segment_id);
239     return false;
240   }
241   return true;
242 }
243 
ReadIntraSegmentId(const Block & block)244 bool Tile::ReadIntraSegmentId(const Block& block) {
245   BlockParameters& bp = *block.bp;
246   if (!frame_header_.segmentation.enabled) {
247     bp.segment_id = 0;
248     return true;
249   }
250   return ReadSegmentId(block);
251 }
252 
ReadSkip(const Block & block)253 void Tile::ReadSkip(const Block& block) {
254   BlockParameters& bp = *block.bp;
255   if (frame_header_.segmentation.segment_id_pre_skip &&
256       frame_header_.segmentation.FeatureActive(bp.segment_id,
257                                                kSegmentFeatureSkip)) {
258     bp.skip = true;
259     return;
260   }
261   int context = 0;
262   if (block.top_available[kPlaneY] && block.bp_top->skip) {
263     ++context;
264   }
265   if (block.left_available[kPlaneY] && block.bp_left->skip) {
266     ++context;
267   }
268   uint16_t* const skip_cdf = symbol_decoder_context_.skip_cdf[context];
269   bp.skip = reader_.ReadSymbol(skip_cdf);
270 }
271 
ReadSkipMode(const Block & block)272 void Tile::ReadSkipMode(const Block& block) {
273   BlockParameters& bp = *block.bp;
274   if (!frame_header_.skip_mode_present ||
275       frame_header_.segmentation.FeatureActive(bp.segment_id,
276                                                kSegmentFeatureSkip) ||
277       frame_header_.segmentation.FeatureActive(bp.segment_id,
278                                                kSegmentFeatureReferenceFrame) ||
279       frame_header_.segmentation.FeatureActive(bp.segment_id,
280                                                kSegmentFeatureGlobalMv) ||
281       IsBlockDimension4(block.size)) {
282     bp.skip_mode = false;
283     return;
284   }
285   const int context =
286       (block.left_available[kPlaneY]
287            ? static_cast<int>(block.bp_left->skip_mode)
288            : 0) +
289       (block.top_available[kPlaneY] ? static_cast<int>(block.bp_top->skip_mode)
290                                     : 0);
291   bp.skip_mode =
292       reader_.ReadSymbol(symbol_decoder_context_.skip_mode_cdf[context]);
293 }
294 
ReadCdef(const Block & block)295 void Tile::ReadCdef(const Block& block) {
296   BlockParameters& bp = *block.bp;
297   if (bp.skip || frame_header_.coded_lossless ||
298       !sequence_header_.enable_cdef || frame_header_.allow_intrabc) {
299     return;
300   }
301   const int cdef_size4x4 = kNum4x4BlocksWide[kBlock64x64];
302   const int cdef_mask4x4 = ~(cdef_size4x4 - 1);
303   const int row4x4 = block.row4x4 & cdef_mask4x4;
304   const int column4x4 = block.column4x4 & cdef_mask4x4;
305   const int row = DivideBy16(row4x4);
306   const int column = DivideBy16(column4x4);
307   if (cdef_index_[row][column] == -1) {
308     cdef_index_[row][column] =
309         frame_header_.cdef.bits > 0
310             ? static_cast<int16_t>(reader_.ReadLiteral(frame_header_.cdef.bits))
311             : 0;
312     for (int i = row4x4; i < row4x4 + block.height4x4; i += cdef_size4x4) {
313       for (int j = column4x4; j < column4x4 + block.width4x4;
314            j += cdef_size4x4) {
315         cdef_index_[DivideBy16(i)][DivideBy16(j)] = cdef_index_[row][column];
316       }
317     }
318   }
319 }
320 
ReadAndClipDelta(uint16_t * const cdf,int delta_small,int scale,int min_value,int max_value,int value)321 int Tile::ReadAndClipDelta(uint16_t* const cdf, int delta_small, int scale,
322                            int min_value, int max_value, int value) {
323   int abs = reader_.ReadSymbol<kDeltaSymbolCount>(cdf);
324   if (abs == delta_small) {
325     const int remaining_bit_count =
326         static_cast<int>(reader_.ReadLiteral(3)) + 1;
327     const int abs_remaining_bits =
328         static_cast<int>(reader_.ReadLiteral(remaining_bit_count));
329     abs = abs_remaining_bits + (1 << remaining_bit_count) + 1;
330   }
331   if (abs != 0) {
332     const bool sign = static_cast<bool>(reader_.ReadBit());
333     const int scaled_abs = abs << scale;
334     const int reduced_delta = sign ? -scaled_abs : scaled_abs;
335     value += reduced_delta;
336     value = Clip3(value, min_value, max_value);
337   }
338   return value;
339 }
340 
ReadQuantizerIndexDelta(const Block & block)341 void Tile::ReadQuantizerIndexDelta(const Block& block) {
342   assert(read_deltas_);
343   BlockParameters& bp = *block.bp;
344   if ((block.size == SuperBlockSize() && bp.skip)) {
345     return;
346   }
347   current_quantizer_index_ =
348       ReadAndClipDelta(symbol_decoder_context_.delta_q_cdf, kDeltaQSmall,
349                        frame_header_.delta_q.scale, kMinLossyQuantizer,
350                        kMaxQuantizer, current_quantizer_index_);
351 }
352 
ReadLoopFilterDelta(const Block & block)353 void Tile::ReadLoopFilterDelta(const Block& block) {
354   assert(read_deltas_);
355   BlockParameters& bp = *block.bp;
356   if (!frame_header_.delta_lf.present ||
357       (block.size == SuperBlockSize() && bp.skip)) {
358     return;
359   }
360   int frame_lf_count = 1;
361   if (frame_header_.delta_lf.multi) {
362     frame_lf_count = kFrameLfCount - (PlaneCount() > 1 ? 0 : 2);
363   }
364   bool recompute_deblock_filter_levels = false;
365   for (int i = 0; i < frame_lf_count; ++i) {
366     uint16_t* const delta_lf_abs_cdf =
367         frame_header_.delta_lf.multi
368             ? symbol_decoder_context_.delta_lf_multi_cdf[i]
369             : symbol_decoder_context_.delta_lf_cdf;
370     const int8_t old_delta_lf = delta_lf_[i];
371     delta_lf_[i] = ReadAndClipDelta(
372         delta_lf_abs_cdf, kDeltaLfSmall, frame_header_.delta_lf.scale,
373         -kMaxLoopFilterValue, kMaxLoopFilterValue, delta_lf_[i]);
374     recompute_deblock_filter_levels =
375         recompute_deblock_filter_levels || (old_delta_lf != delta_lf_[i]);
376   }
377   delta_lf_all_zero_ =
378       (delta_lf_[0] | delta_lf_[1] | delta_lf_[2] | delta_lf_[3]) == 0;
379   if (!delta_lf_all_zero_ && recompute_deblock_filter_levels) {
380     post_filter_.ComputeDeblockFilterLevels(delta_lf_, deblock_filter_levels_);
381   }
382 }
383 
ReadPredictionModeY(const Block & block,bool intra_y_mode)384 void Tile::ReadPredictionModeY(const Block& block, bool intra_y_mode) {
385   uint16_t* cdf;
386   if (intra_y_mode) {
387     const PredictionMode top_mode =
388         block.top_available[kPlaneY] ? block.bp_top->y_mode : kPredictionModeDc;
389     const PredictionMode left_mode = block.left_available[kPlaneY]
390                                          ? block.bp_left->y_mode
391                                          : kPredictionModeDc;
392     const int top_context = kIntraYModeContext[top_mode];
393     const int left_context = kIntraYModeContext[left_mode];
394     cdf = symbol_decoder_context_
395               .intra_frame_y_mode_cdf[top_context][left_context];
396   } else {
397     cdf = symbol_decoder_context_.y_mode_cdf[kSizeGroup[block.size]];
398   }
399   block.bp->y_mode = static_cast<PredictionMode>(
400       reader_.ReadSymbol<kIntraPredictionModesY>(cdf));
401 }
402 
ReadIntraAngleInfo(const Block & block,PlaneType plane_type)403 void Tile::ReadIntraAngleInfo(const Block& block, PlaneType plane_type) {
404   BlockParameters& bp = *block.bp;
405   PredictionParameters& prediction_parameters =
406       *block.bp->prediction_parameters;
407   prediction_parameters.angle_delta[plane_type] = 0;
408   const PredictionMode mode =
409       (plane_type == kPlaneTypeY) ? bp.y_mode : bp.uv_mode;
410   if (IsBlockSmallerThan8x8(block.size) || !IsDirectionalMode(mode)) return;
411   uint16_t* const cdf =
412       symbol_decoder_context_.angle_delta_cdf[mode - kPredictionModeVertical];
413   prediction_parameters.angle_delta[plane_type] =
414       reader_.ReadSymbol<kAngleDeltaSymbolCount>(cdf);
415   prediction_parameters.angle_delta[plane_type] -= kMaxAngleDelta;
416 }
417 
ReadCflAlpha(const Block & block)418 void Tile::ReadCflAlpha(const Block& block) {
419   const int signs = reader_.ReadSymbol<kCflAlphaSignsSymbolCount>(
420       symbol_decoder_context_.cfl_alpha_signs_cdf);
421   const int8_t* const cfl_lookup = kCflAlphaLookup[signs];
422   const auto sign_u = static_cast<CflSign>(cfl_lookup[0]);
423   const auto sign_v = static_cast<CflSign>(cfl_lookup[1]);
424   PredictionParameters& prediction_parameters =
425       *block.bp->prediction_parameters;
426   prediction_parameters.cfl_alpha_u = 0;
427   if (sign_u != kCflSignZero) {
428     assert(cfl_lookup[2] >= 0);
429     prediction_parameters.cfl_alpha_u =
430         reader_.ReadSymbol<kCflAlphaSymbolCount>(
431             symbol_decoder_context_.cfl_alpha_cdf[cfl_lookup[2]]) +
432         1;
433     if (sign_u == kCflSignNegative) prediction_parameters.cfl_alpha_u *= -1;
434   }
435   prediction_parameters.cfl_alpha_v = 0;
436   if (sign_v != kCflSignZero) {
437     assert(cfl_lookup[3] >= 0);
438     prediction_parameters.cfl_alpha_v =
439         reader_.ReadSymbol<kCflAlphaSymbolCount>(
440             symbol_decoder_context_.cfl_alpha_cdf[cfl_lookup[3]]) +
441         1;
442     if (sign_v == kCflSignNegative) prediction_parameters.cfl_alpha_v *= -1;
443   }
444 }
445 
ReadPredictionModeUV(const Block & block)446 void Tile::ReadPredictionModeUV(const Block& block) {
447   BlockParameters& bp = *block.bp;
448   bool chroma_from_luma_allowed;
449   if (frame_header_.segmentation.lossless[bp.segment_id]) {
450     chroma_from_luma_allowed = block.residual_size[kPlaneU] == kBlock4x4;
451   } else {
452     chroma_from_luma_allowed = IsBlockDimensionLessThan64(block.size);
453   }
454   uint16_t* const cdf =
455       symbol_decoder_context_
456           .uv_mode_cdf[static_cast<int>(chroma_from_luma_allowed)][bp.y_mode];
457   if (chroma_from_luma_allowed) {
458     bp.uv_mode = static_cast<PredictionMode>(
459         reader_.ReadSymbol<kIntraPredictionModesUV>(cdf));
460   } else {
461     bp.uv_mode = static_cast<PredictionMode>(
462         reader_.ReadSymbol<kIntraPredictionModesUV - 1>(cdf));
463   }
464 }
465 
ReadMotionVectorComponent(const Block & block,const int component)466 int Tile::ReadMotionVectorComponent(const Block& block, const int component) {
467   const int context =
468       static_cast<int>(block.bp->prediction_parameters->use_intra_block_copy);
469   const bool sign = reader_.ReadSymbol(
470       symbol_decoder_context_.mv_sign_cdf[component][context]);
471   const int mv_class = reader_.ReadSymbol<kMvClassSymbolCount>(
472       symbol_decoder_context_.mv_class_cdf[component][context]);
473   int magnitude = 1;
474   int value;
475   uint16_t* fraction_cdf;
476   uint16_t* precision_cdf;
477   if (mv_class == 0) {
478     value = static_cast<int>(reader_.ReadSymbol(
479         symbol_decoder_context_.mv_class0_bit_cdf[component][context]));
480     fraction_cdf = symbol_decoder_context_
481                        .mv_class0_fraction_cdf[component][context][value];
482     precision_cdf = symbol_decoder_context_
483                         .mv_class0_high_precision_cdf[component][context];
484   } else {
485     assert(mv_class <= kMvBitSymbolCount);
486     value = 0;
487     for (int i = 0; i < mv_class; ++i) {
488       const int bit = static_cast<int>(reader_.ReadSymbol(
489           symbol_decoder_context_.mv_bit_cdf[component][context][i]));
490       value |= bit << i;
491     }
492     magnitude += 2 << (mv_class + 2);
493     fraction_cdf = symbol_decoder_context_.mv_fraction_cdf[component][context];
494     precision_cdf =
495         symbol_decoder_context_.mv_high_precision_cdf[component][context];
496   }
497   const int fraction =
498       (frame_header_.force_integer_mv == 0)
499           ? reader_.ReadSymbol<kMvFractionSymbolCount>(fraction_cdf)
500           : 3;
501   const int precision =
502       frame_header_.allow_high_precision_mv
503           ? static_cast<int>(reader_.ReadSymbol(precision_cdf))
504           : 1;
505   magnitude += (value << 3) | (fraction << 1) | precision;
506   return sign ? -magnitude : magnitude;
507 }
508 
ReadMotionVector(const Block & block,int index)509 void Tile::ReadMotionVector(const Block& block, int index) {
510   BlockParameters& bp = *block.bp;
511   const int context =
512       static_cast<int>(block.bp->prediction_parameters->use_intra_block_copy);
513   const auto mv_joint = static_cast<MvJointType>(
514       reader_.ReadSymbol(symbol_decoder_context_.mv_joint_cdf[context],
515                          static_cast<int>(kNumMvJointTypes)));
516   if (mv_joint == kMvJointTypeHorizontalZeroVerticalNonZero ||
517       mv_joint == kMvJointTypeNonZero) {
518     bp.mv.mv[index].mv[0] = ReadMotionVectorComponent(block, 0);
519   }
520   if (mv_joint == kMvJointTypeHorizontalNonZeroVerticalZero ||
521       mv_joint == kMvJointTypeNonZero) {
522     bp.mv.mv[index].mv[1] = ReadMotionVectorComponent(block, 1);
523   }
524 }
525 
ReadFilterIntraModeInfo(const Block & block)526 void Tile::ReadFilterIntraModeInfo(const Block& block) {
527   BlockParameters& bp = *block.bp;
528   PredictionParameters& prediction_parameters =
529       *block.bp->prediction_parameters;
530   prediction_parameters.use_filter_intra = false;
531   if (!sequence_header_.enable_filter_intra || bp.y_mode != kPredictionModeDc ||
532       bp.palette_mode_info.size[kPlaneTypeY] != 0 ||
533       !IsBlockDimensionLessThan64(block.size)) {
534     return;
535   }
536   prediction_parameters.use_filter_intra = reader_.ReadSymbol(
537       symbol_decoder_context_.use_filter_intra_cdf[block.size]);
538   if (prediction_parameters.use_filter_intra) {
539     prediction_parameters.filter_intra_mode = static_cast<FilterIntraPredictor>(
540         reader_.ReadSymbol<kNumFilterIntraPredictors>(
541             symbol_decoder_context_.filter_intra_mode_cdf));
542   }
543 }
544 
DecodeIntraModeInfo(const Block & block)545 bool Tile::DecodeIntraModeInfo(const Block& block) {
546   BlockParameters& bp = *block.bp;
547   bp.skip = false;
548   if (frame_header_.segmentation.segment_id_pre_skip &&
549       !ReadIntraSegmentId(block)) {
550     return false;
551   }
552   bp.skip_mode = false;
553   ReadSkip(block);
554   if (!frame_header_.segmentation.segment_id_pre_skip &&
555       !ReadIntraSegmentId(block)) {
556     return false;
557   }
558   ReadCdef(block);
559   if (read_deltas_) {
560     ReadQuantizerIndexDelta(block);
561     ReadLoopFilterDelta(block);
562     read_deltas_ = false;
563   }
564   PredictionParameters& prediction_parameters =
565       *block.bp->prediction_parameters;
566   prediction_parameters.use_intra_block_copy = false;
567   if (frame_header_.allow_intrabc) {
568     prediction_parameters.use_intra_block_copy =
569         reader_.ReadSymbol(symbol_decoder_context_.intra_block_copy_cdf);
570   }
571   if (prediction_parameters.use_intra_block_copy) {
572     bp.is_inter = true;
573     bp.reference_frame[0] = kReferenceFrameIntra;
574     bp.reference_frame[1] = kReferenceFrameNone;
575     bp.y_mode = kPredictionModeDc;
576     bp.uv_mode = kPredictionModeDc;
577     prediction_parameters.motion_mode = kMotionModeSimple;
578     prediction_parameters.compound_prediction_type =
579         kCompoundPredictionTypeAverage;
580     bp.palette_mode_info.size[kPlaneTypeY] = 0;
581     bp.palette_mode_info.size[kPlaneTypeUV] = 0;
582     bp.interpolation_filter[0] = kInterpolationFilterBilinear;
583     bp.interpolation_filter[1] = kInterpolationFilterBilinear;
584     MvContexts dummy_mode_contexts;
585     FindMvStack(block, /*is_compound=*/false, &dummy_mode_contexts);
586     return AssignIntraMv(block);
587   }
588   bp.is_inter = false;
589   return ReadIntraBlockModeInfo(block, /*intra_y_mode=*/true);
590 }
591 
ComputePredictedSegmentId(const Block & block) const592 int8_t Tile::ComputePredictedSegmentId(const Block& block) const {
593   // If prev_segment_ids_ is null, treat it as if it pointed to a segmentation
594   // map containing all 0s.
595   if (prev_segment_ids_ == nullptr) return 0;
596 
597   const int x_limit = std::min(frame_header_.columns4x4 - block.column4x4,
598                                static_cast<int>(block.width4x4));
599   const int y_limit = std::min(frame_header_.rows4x4 - block.row4x4,
600                                static_cast<int>(block.height4x4));
601   int8_t id = 7;
602   for (int y = 0; y < y_limit; ++y) {
603     for (int x = 0; x < x_limit; ++x) {
604       const int8_t prev_segment_id =
605           prev_segment_ids_->segment_id(block.row4x4 + y, block.column4x4 + x);
606       id = std::min(id, prev_segment_id);
607     }
608   }
609   return id;
610 }
611 
ReadInterSegmentId(const Block & block,bool pre_skip)612 bool Tile::ReadInterSegmentId(const Block& block, bool pre_skip) {
613   BlockParameters& bp = *block.bp;
614   if (!frame_header_.segmentation.enabled) {
615     bp.segment_id = 0;
616     return true;
617   }
618   if (!frame_header_.segmentation.update_map) {
619     bp.segment_id = ComputePredictedSegmentId(block);
620     return true;
621   }
622   if (pre_skip) {
623     if (!frame_header_.segmentation.segment_id_pre_skip) {
624       bp.segment_id = 0;
625       return true;
626     }
627   } else if (bp.skip) {
628     bp.use_predicted_segment_id = false;
629     return ReadSegmentId(block);
630   }
631   if (frame_header_.segmentation.temporal_update) {
632     const int context =
633         (block.left_available[kPlaneY]
634              ? static_cast<int>(block.bp_left->use_predicted_segment_id)
635              : 0) +
636         (block.top_available[kPlaneY]
637              ? static_cast<int>(block.bp_top->use_predicted_segment_id)
638              : 0);
639     bp.use_predicted_segment_id = reader_.ReadSymbol(
640         symbol_decoder_context_.use_predicted_segment_id_cdf[context]);
641     if (bp.use_predicted_segment_id) {
642       bp.segment_id = ComputePredictedSegmentId(block);
643       return true;
644     }
645   }
646   return ReadSegmentId(block);
647 }
648 
ReadIsInter(const Block & block)649 void Tile::ReadIsInter(const Block& block) {
650   BlockParameters& bp = *block.bp;
651   if (bp.skip_mode) {
652     bp.is_inter = true;
653     return;
654   }
655   if (frame_header_.segmentation.FeatureActive(bp.segment_id,
656                                                kSegmentFeatureReferenceFrame)) {
657     bp.is_inter =
658         frame_header_.segmentation
659             .feature_data[bp.segment_id][kSegmentFeatureReferenceFrame] !=
660         kReferenceFrameIntra;
661     return;
662   }
663   if (frame_header_.segmentation.FeatureActive(bp.segment_id,
664                                                kSegmentFeatureGlobalMv)) {
665     bp.is_inter = true;
666     return;
667   }
668   int context = 0;
669   if (block.top_available[kPlaneY] && block.left_available[kPlaneY]) {
670     context = (block.IsTopIntra() && block.IsLeftIntra())
671                   ? 3
672                   : static_cast<int>(block.IsTopIntra() || block.IsLeftIntra());
673   } else if (block.top_available[kPlaneY] || block.left_available[kPlaneY]) {
674     context = 2 * static_cast<int>(block.top_available[kPlaneY]
675                                        ? block.IsTopIntra()
676                                        : block.IsLeftIntra());
677   }
678   bp.is_inter =
679       reader_.ReadSymbol(symbol_decoder_context_.is_inter_cdf[context]);
680 }
681 
ReadIntraBlockModeInfo(const Block & block,bool intra_y_mode)682 bool Tile::ReadIntraBlockModeInfo(const Block& block, bool intra_y_mode) {
683   BlockParameters& bp = *block.bp;
684   bp.reference_frame[0] = kReferenceFrameIntra;
685   bp.reference_frame[1] = kReferenceFrameNone;
686   ReadPredictionModeY(block, intra_y_mode);
687   ReadIntraAngleInfo(block, kPlaneTypeY);
688   if (block.HasChroma()) {
689     ReadPredictionModeUV(block);
690     if (bp.uv_mode == kPredictionModeChromaFromLuma) {
691       ReadCflAlpha(block);
692     }
693     ReadIntraAngleInfo(block, kPlaneTypeUV);
694   }
695   ReadPaletteModeInfo(block);
696   ReadFilterIntraModeInfo(block);
697   return true;
698 }
699 
ReadCompoundReferenceType(const Block & block)700 CompoundReferenceType Tile::ReadCompoundReferenceType(const Block& block) {
701   // compound and inter.
702   const bool top_comp_inter = block.top_available[kPlaneY] &&
703                               !block.IsTopIntra() && !block.IsTopSingle();
704   const bool left_comp_inter = block.left_available[kPlaneY] &&
705                                !block.IsLeftIntra() && !block.IsLeftSingle();
706   // unidirectional compound.
707   const bool top_uni_comp =
708       top_comp_inter && IsSameDirectionReferencePair(block.TopReference(0),
709                                                      block.TopReference(1));
710   const bool left_uni_comp =
711       left_comp_inter && IsSameDirectionReferencePair(block.LeftReference(0),
712                                                       block.LeftReference(1));
713   int context;
714   if (block.top_available[kPlaneY] && !block.IsTopIntra() &&
715       block.left_available[kPlaneY] && !block.IsLeftIntra()) {
716     const int same_direction = static_cast<int>(IsSameDirectionReferencePair(
717         block.TopReference(0), block.LeftReference(0)));
718     if (!top_comp_inter && !left_comp_inter) {
719       context = 1 + MultiplyBy2(same_direction);
720     } else if (!top_comp_inter) {
721       context = left_uni_comp ? 3 + same_direction : 1;
722     } else if (!left_comp_inter) {
723       context = top_uni_comp ? 3 + same_direction : 1;
724     } else {
725       if (!top_uni_comp && !left_uni_comp) {
726         context = 0;
727       } else if (!top_uni_comp || !left_uni_comp) {
728         context = 2;
729       } else {
730         context = 3 + static_cast<int>(
731                           (block.TopReference(0) == kReferenceFrameBackward) ==
732                           (block.LeftReference(0) == kReferenceFrameBackward));
733       }
734     }
735   } else if (block.top_available[kPlaneY] && block.left_available[kPlaneY]) {
736     if (top_comp_inter) {
737       context = 1 + MultiplyBy2(static_cast<int>(top_uni_comp));
738     } else if (left_comp_inter) {
739       context = 1 + MultiplyBy2(static_cast<int>(left_uni_comp));
740     } else {
741       context = 2;
742     }
743   } else if (top_comp_inter) {
744     context = MultiplyBy4(static_cast<int>(top_uni_comp));
745   } else if (left_comp_inter) {
746     context = MultiplyBy4(static_cast<int>(left_uni_comp));
747   } else {
748     context = 2;
749   }
750   return static_cast<CompoundReferenceType>(reader_.ReadSymbol(
751       symbol_decoder_context_.compound_reference_type_cdf[context]));
752 }
753 
754 template <bool is_single, bool is_backward, int index>
GetReferenceCdf(const Block & block,CompoundReferenceType type)755 uint16_t* Tile::GetReferenceCdf(
756     const Block& block,
757     CompoundReferenceType type /*= kNumCompoundReferenceTypes*/) {
758   int context = 0;
759   if ((type == kCompoundReferenceUnidirectional && index == 0) ||
760       (is_single && index == 1)) {
761     // uni_comp_ref and single_ref_p1.
762     context =
763         GetReferenceContext(block, kReferenceFrameLast, kReferenceFrameGolden,
764                             kReferenceFrameBackward, kReferenceFrameAlternate);
765   } else if (type == kCompoundReferenceUnidirectional && index == 1) {
766     // uni_comp_ref_p1.
767     context =
768         GetReferenceContext(block, kReferenceFrameLast2, kReferenceFrameLast2,
769                             kReferenceFrameLast3, kReferenceFrameGolden);
770   } else if ((type == kCompoundReferenceUnidirectional && index == 2) ||
771              (type == kCompoundReferenceBidirectional && index == 2) ||
772              (is_single && index == 5)) {
773     // uni_comp_ref_p2, comp_ref_p2 and single_ref_p5.
774     context =
775         GetReferenceContext(block, kReferenceFrameLast3, kReferenceFrameLast3,
776                             kReferenceFrameGolden, kReferenceFrameGolden);
777   } else if ((type == kCompoundReferenceBidirectional && index == 0) ||
778              (is_single && index == 3)) {
779     // comp_ref and single_ref_p3.
780     context =
781         GetReferenceContext(block, kReferenceFrameLast, kReferenceFrameLast2,
782                             kReferenceFrameLast3, kReferenceFrameGolden);
783   } else if ((type == kCompoundReferenceBidirectional && index == 1) ||
784              (is_single && index == 4)) {
785     // comp_ref_p1 and single_ref_p4.
786     context =
787         GetReferenceContext(block, kReferenceFrameLast, kReferenceFrameLast,
788                             kReferenceFrameLast2, kReferenceFrameLast2);
789   } else if ((is_single && index == 2) || (is_backward && index == 0)) {
790     // single_ref_p2 and comp_bwdref.
791     context = GetReferenceContext(
792         block, kReferenceFrameBackward, kReferenceFrameAlternate2,
793         kReferenceFrameAlternate, kReferenceFrameAlternate);
794   } else if ((is_single && index == 6) || (is_backward && index == 1)) {
795     // single_ref_p6 and comp_bwdref_p1.
796     context = GetReferenceContext(
797         block, kReferenceFrameBackward, kReferenceFrameBackward,
798         kReferenceFrameAlternate2, kReferenceFrameAlternate2);
799   }
800   if (is_single) {
801     // The index parameter for single references is offset by one since the spec
802     // uses 1-based index for these elements.
803     return symbol_decoder_context_.single_reference_cdf[context][index - 1];
804   }
805   if (is_backward) {
806     return symbol_decoder_context_
807         .compound_backward_reference_cdf[context][index];
808   }
809   return symbol_decoder_context_.compound_reference_cdf[type][context][index];
810 }
811 
ReadReferenceFrames(const Block & block)812 void Tile::ReadReferenceFrames(const Block& block) {
813   BlockParameters& bp = *block.bp;
814   if (bp.skip_mode) {
815     bp.reference_frame[0] = frame_header_.skip_mode_frame[0];
816     bp.reference_frame[1] = frame_header_.skip_mode_frame[1];
817     return;
818   }
819   if (frame_header_.segmentation.FeatureActive(bp.segment_id,
820                                                kSegmentFeatureReferenceFrame)) {
821     bp.reference_frame[0] = static_cast<ReferenceFrameType>(
822         frame_header_.segmentation
823             .feature_data[bp.segment_id][kSegmentFeatureReferenceFrame]);
824     bp.reference_frame[1] = kReferenceFrameNone;
825     return;
826   }
827   if (frame_header_.segmentation.FeatureActive(bp.segment_id,
828                                                kSegmentFeatureSkip) ||
829       frame_header_.segmentation.FeatureActive(bp.segment_id,
830                                                kSegmentFeatureGlobalMv)) {
831     bp.reference_frame[0] = kReferenceFrameLast;
832     bp.reference_frame[1] = kReferenceFrameNone;
833     return;
834   }
835   const bool use_compound_reference =
836       frame_header_.reference_mode_select &&
837       std::min(block.width4x4, block.height4x4) >= 2 &&
838       reader_.ReadSymbol(symbol_decoder_context_.use_compound_reference_cdf
839                              [GetUseCompoundReferenceContext(block)]);
840   if (use_compound_reference) {
841     CompoundReferenceType reference_type = ReadCompoundReferenceType(block);
842     if (reference_type == kCompoundReferenceUnidirectional) {
843       // uni_comp_ref.
844       if (reader_.ReadSymbol(
845               GetReferenceCdf<false, false, 0>(block, reference_type))) {
846         bp.reference_frame[0] = kReferenceFrameBackward;
847         bp.reference_frame[1] = kReferenceFrameAlternate;
848         return;
849       }
850       // uni_comp_ref_p1.
851       if (!reader_.ReadSymbol(
852               GetReferenceCdf<false, false, 1>(block, reference_type))) {
853         bp.reference_frame[0] = kReferenceFrameLast;
854         bp.reference_frame[1] = kReferenceFrameLast2;
855         return;
856       }
857       // uni_comp_ref_p2.
858       if (reader_.ReadSymbol(
859               GetReferenceCdf<false, false, 2>(block, reference_type))) {
860         bp.reference_frame[0] = kReferenceFrameLast;
861         bp.reference_frame[1] = kReferenceFrameGolden;
862         return;
863       }
864       bp.reference_frame[0] = kReferenceFrameLast;
865       bp.reference_frame[1] = kReferenceFrameLast3;
866       return;
867     }
868     assert(reference_type == kCompoundReferenceBidirectional);
869     // comp_ref.
870     if (reader_.ReadSymbol(
871             GetReferenceCdf<false, false, 0>(block, reference_type))) {
872       // comp_ref_p2.
873       bp.reference_frame[0] =
874           reader_.ReadSymbol(
875               GetReferenceCdf<false, false, 2>(block, reference_type))
876               ? kReferenceFrameGolden
877               : kReferenceFrameLast3;
878     } else {
879       // comp_ref_p1.
880       bp.reference_frame[0] =
881           reader_.ReadSymbol(
882               GetReferenceCdf<false, false, 1>(block, reference_type))
883               ? kReferenceFrameLast2
884               : kReferenceFrameLast;
885     }
886     // comp_bwdref.
887     if (reader_.ReadSymbol(GetReferenceCdf<false, true, 0>(block))) {
888       bp.reference_frame[1] = kReferenceFrameAlternate;
889     } else {
890       // comp_bwdref_p1.
891       bp.reference_frame[1] =
892           reader_.ReadSymbol(GetReferenceCdf<false, true, 1>(block))
893               ? kReferenceFrameAlternate2
894               : kReferenceFrameBackward;
895     }
896     return;
897   }
898   assert(!use_compound_reference);
899   bp.reference_frame[1] = kReferenceFrameNone;
900   // single_ref_p1.
901   if (reader_.ReadSymbol(GetReferenceCdf<true, false, 1>(block))) {
902     // single_ref_p2.
903     if (reader_.ReadSymbol(GetReferenceCdf<true, false, 2>(block))) {
904       bp.reference_frame[0] = kReferenceFrameAlternate;
905       return;
906     }
907     // single_ref_p6.
908     bp.reference_frame[0] =
909         reader_.ReadSymbol(GetReferenceCdf<true, false, 6>(block))
910             ? kReferenceFrameAlternate2
911             : kReferenceFrameBackward;
912     return;
913   }
914   // single_ref_p3.
915   if (reader_.ReadSymbol(GetReferenceCdf<true, false, 3>(block))) {
916     // single_ref_p5.
917     bp.reference_frame[0] =
918         reader_.ReadSymbol(GetReferenceCdf<true, false, 5>(block))
919             ? kReferenceFrameGolden
920             : kReferenceFrameLast3;
921     return;
922   }
923   // single_ref_p4.
924   bp.reference_frame[0] =
925       reader_.ReadSymbol(GetReferenceCdf<true, false, 4>(block))
926           ? kReferenceFrameLast2
927           : kReferenceFrameLast;
928 }
929 
ReadInterPredictionModeY(const Block & block,const MvContexts & mode_contexts)930 void Tile::ReadInterPredictionModeY(const Block& block,
931                                     const MvContexts& mode_contexts) {
932   BlockParameters& bp = *block.bp;
933   if (bp.skip_mode) {
934     bp.y_mode = kPredictionModeNearestNearestMv;
935     return;
936   }
937   if (frame_header_.segmentation.FeatureActive(bp.segment_id,
938                                                kSegmentFeatureSkip) ||
939       frame_header_.segmentation.FeatureActive(bp.segment_id,
940                                                kSegmentFeatureGlobalMv)) {
941     bp.y_mode = kPredictionModeGlobalMv;
942     return;
943   }
944   if (bp.reference_frame[1] > kReferenceFrameIntra) {
945     const int idx0 = mode_contexts.reference_mv >> 1;
946     const int idx1 =
947         std::min(mode_contexts.new_mv, kCompoundModeNewMvContexts - 1);
948     const int context = kCompoundModeContextMap[idx0][idx1];
949     const int offset = reader_.ReadSymbol<kNumCompoundInterPredictionModes>(
950         symbol_decoder_context_.compound_prediction_mode_cdf[context]);
951     bp.y_mode =
952         static_cast<PredictionMode>(kPredictionModeNearestNearestMv + offset);
953     return;
954   }
955   // new_mv.
956   if (!reader_.ReadSymbol(
957           symbol_decoder_context_.new_mv_cdf[mode_contexts.new_mv])) {
958     bp.y_mode = kPredictionModeNewMv;
959     return;
960   }
961   // zero_mv.
962   if (!reader_.ReadSymbol(
963           symbol_decoder_context_.zero_mv_cdf[mode_contexts.zero_mv])) {
964     bp.y_mode = kPredictionModeGlobalMv;
965     return;
966   }
967   // ref_mv.
968   bp.y_mode =
969       reader_.ReadSymbol(
970           symbol_decoder_context_.reference_mv_cdf[mode_contexts.reference_mv])
971           ? kPredictionModeNearMv
972           : kPredictionModeNearestMv;
973 }
974 
ReadRefMvIndex(const Block & block)975 void Tile::ReadRefMvIndex(const Block& block) {
976   BlockParameters& bp = *block.bp;
977   PredictionParameters& prediction_parameters =
978       *block.bp->prediction_parameters;
979   prediction_parameters.ref_mv_index = 0;
980   if (bp.y_mode != kPredictionModeNewMv &&
981       bp.y_mode != kPredictionModeNewNewMv &&
982       !kPredictionModeHasNearMvMask.Contains(bp.y_mode)) {
983     return;
984   }
985   const int start =
986       static_cast<int>(kPredictionModeHasNearMvMask.Contains(bp.y_mode));
987   prediction_parameters.ref_mv_index = start;
988   for (int i = start; i < start + 2; ++i) {
989     if (prediction_parameters.ref_mv_count <= i + 1) break;
990     // drl_mode in the spec.
991     const bool ref_mv_index_bit = reader_.ReadSymbol(
992         symbol_decoder_context_.ref_mv_index_cdf[GetRefMvIndexContext(
993             prediction_parameters.nearest_mv_count, i)]);
994     prediction_parameters.ref_mv_index = i + static_cast<int>(ref_mv_index_bit);
995     if (!ref_mv_index_bit) return;
996   }
997 }
998 
ReadInterIntraMode(const Block & block,bool is_compound)999 void Tile::ReadInterIntraMode(const Block& block, bool is_compound) {
1000   BlockParameters& bp = *block.bp;
1001   PredictionParameters& prediction_parameters =
1002       *block.bp->prediction_parameters;
1003   prediction_parameters.inter_intra_mode = kNumInterIntraModes;
1004   prediction_parameters.is_wedge_inter_intra = false;
1005   if (bp.skip_mode || !sequence_header_.enable_interintra_compound ||
1006       is_compound || !kIsInterIntraModeAllowedMask.Contains(block.size)) {
1007     return;
1008   }
1009   // kSizeGroup[block.size] is guaranteed to be non-zero because of the block
1010   // size constraint enforced in the above condition.
1011   assert(kSizeGroup[block.size] - 1 >= 0);
1012   if (!reader_.ReadSymbol(
1013           symbol_decoder_context_
1014               .is_inter_intra_cdf[kSizeGroup[block.size] - 1])) {
1015     prediction_parameters.inter_intra_mode = kNumInterIntraModes;
1016     return;
1017   }
1018   prediction_parameters.inter_intra_mode =
1019       static_cast<InterIntraMode>(reader_.ReadSymbol<kNumInterIntraModes>(
1020           symbol_decoder_context_
1021               .inter_intra_mode_cdf[kSizeGroup[block.size] - 1]));
1022   bp.reference_frame[1] = kReferenceFrameIntra;
1023   prediction_parameters.angle_delta[kPlaneTypeY] = 0;
1024   prediction_parameters.angle_delta[kPlaneTypeUV] = 0;
1025   prediction_parameters.use_filter_intra = false;
1026   prediction_parameters.is_wedge_inter_intra = reader_.ReadSymbol(
1027       symbol_decoder_context_.is_wedge_inter_intra_cdf[block.size]);
1028   if (!prediction_parameters.is_wedge_inter_intra) return;
1029   prediction_parameters.wedge_index =
1030       reader_.ReadSymbol<kWedgeIndexSymbolCount>(
1031           symbol_decoder_context_.wedge_index_cdf[block.size]);
1032   prediction_parameters.wedge_sign = 0;
1033 }
1034 
IsScaled(ReferenceFrameType type) const1035 bool Tile::IsScaled(ReferenceFrameType type) const {
1036   const int index =
1037       frame_header_.reference_frame_index[type - kReferenceFrameLast];
1038   const int x_scale = ((reference_frames_[index]->upscaled_width()
1039                         << kReferenceFrameScalePrecision) +
1040                        DivideBy2(frame_header_.width)) /
1041                       frame_header_.width;
1042   if (x_scale != kNoScale) return true;
1043   const int y_scale = ((reference_frames_[index]->frame_height()
1044                         << kReferenceFrameScalePrecision) +
1045                        DivideBy2(frame_header_.height)) /
1046                       frame_header_.height;
1047   return y_scale != kNoScale;
1048 }
1049 
ReadMotionMode(const Block & block,bool is_compound)1050 void Tile::ReadMotionMode(const Block& block, bool is_compound) {
1051   BlockParameters& bp = *block.bp;
1052   PredictionParameters& prediction_parameters =
1053       *block.bp->prediction_parameters;
1054   const auto global_motion_type =
1055       frame_header_.global_motion[bp.reference_frame[0]].type;
1056   if (bp.skip_mode || !frame_header_.is_motion_mode_switchable ||
1057       IsBlockDimension4(block.size) ||
1058       (frame_header_.force_integer_mv == 0 &&
1059        (bp.y_mode == kPredictionModeGlobalMv ||
1060         bp.y_mode == kPredictionModeGlobalGlobalMv) &&
1061        global_motion_type > kGlobalMotionTransformationTypeTranslation) ||
1062       is_compound || bp.reference_frame[1] == kReferenceFrameIntra ||
1063       !block.HasOverlappableCandidates()) {
1064     prediction_parameters.motion_mode = kMotionModeSimple;
1065     return;
1066   }
1067   prediction_parameters.num_warp_samples = 0;
1068   int num_samples_scanned = 0;
1069   memset(prediction_parameters.warp_estimate_candidates, 0,
1070          sizeof(prediction_parameters.warp_estimate_candidates));
1071   FindWarpSamples(block, &prediction_parameters.num_warp_samples,
1072                   &num_samples_scanned,
1073                   prediction_parameters.warp_estimate_candidates);
1074   if (frame_header_.force_integer_mv != 0 ||
1075       prediction_parameters.num_warp_samples == 0 ||
1076       !frame_header_.allow_warped_motion || IsScaled(bp.reference_frame[0])) {
1077     prediction_parameters.motion_mode =
1078         reader_.ReadSymbol(symbol_decoder_context_.use_obmc_cdf[block.size])
1079             ? kMotionModeObmc
1080             : kMotionModeSimple;
1081     return;
1082   }
1083   prediction_parameters.motion_mode =
1084       static_cast<MotionMode>(reader_.ReadSymbol<kNumMotionModes>(
1085           symbol_decoder_context_.motion_mode_cdf[block.size]));
1086 }
1087 
GetIsExplicitCompoundTypeCdf(const Block & block)1088 uint16_t* Tile::GetIsExplicitCompoundTypeCdf(const Block& block) {
1089   int context = 0;
1090   if (block.top_available[kPlaneY]) {
1091     if (!block.IsTopSingle()) {
1092       context += static_cast<int>(block.bp_top->is_explicit_compound_type);
1093     } else if (block.TopReference(0) == kReferenceFrameAlternate) {
1094       context += 3;
1095     }
1096   }
1097   if (block.left_available[kPlaneY]) {
1098     if (!block.IsLeftSingle()) {
1099       context += static_cast<int>(block.bp_left->is_explicit_compound_type);
1100     } else if (block.LeftReference(0) == kReferenceFrameAlternate) {
1101       context += 3;
1102     }
1103   }
1104   return symbol_decoder_context_.is_explicit_compound_type_cdf[std::min(
1105       context, kIsExplicitCompoundTypeContexts - 1)];
1106 }
1107 
GetIsCompoundTypeAverageCdf(const Block & block)1108 uint16_t* Tile::GetIsCompoundTypeAverageCdf(const Block& block) {
1109   const BlockParameters& bp = *block.bp;
1110   const ReferenceInfo& reference_info = *current_frame_.reference_info();
1111   const int forward =
1112       std::abs(reference_info.relative_distance_from[bp.reference_frame[0]]);
1113   const int backward =
1114       std::abs(reference_info.relative_distance_from[bp.reference_frame[1]]);
1115   int context = (forward == backward) ? 3 : 0;
1116   if (block.top_available[kPlaneY]) {
1117     if (!block.IsTopSingle()) {
1118       context += static_cast<int>(block.bp_top->is_compound_type_average);
1119     } else if (block.TopReference(0) == kReferenceFrameAlternate) {
1120       ++context;
1121     }
1122   }
1123   if (block.left_available[kPlaneY]) {
1124     if (!block.IsLeftSingle()) {
1125       context += static_cast<int>(block.bp_left->is_compound_type_average);
1126     } else if (block.LeftReference(0) == kReferenceFrameAlternate) {
1127       ++context;
1128     }
1129   }
1130   return symbol_decoder_context_.is_compound_type_average_cdf[context];
1131 }
1132 
ReadCompoundType(const Block & block,bool is_compound)1133 void Tile::ReadCompoundType(const Block& block, bool is_compound) {
1134   BlockParameters& bp = *block.bp;
1135   bp.is_explicit_compound_type = false;
1136   bp.is_compound_type_average = true;
1137   PredictionParameters& prediction_parameters =
1138       *block.bp->prediction_parameters;
1139   if (bp.skip_mode) {
1140     prediction_parameters.compound_prediction_type =
1141         kCompoundPredictionTypeAverage;
1142     return;
1143   }
1144   if (is_compound) {
1145     if (sequence_header_.enable_masked_compound) {
1146       bp.is_explicit_compound_type =
1147           reader_.ReadSymbol(GetIsExplicitCompoundTypeCdf(block));
1148     }
1149     if (bp.is_explicit_compound_type) {
1150       if (kIsWedgeCompoundModeAllowed.Contains(block.size)) {
1151         // Only kCompoundPredictionTypeWedge and
1152         // kCompoundPredictionTypeDiffWeighted are signaled explicitly.
1153         prediction_parameters.compound_prediction_type =
1154             static_cast<CompoundPredictionType>(reader_.ReadSymbol(
1155                 symbol_decoder_context_.compound_type_cdf[block.size]));
1156       } else {
1157         prediction_parameters.compound_prediction_type =
1158             kCompoundPredictionTypeDiffWeighted;
1159       }
1160     } else {
1161       if (sequence_header_.enable_jnt_comp) {
1162         bp.is_compound_type_average =
1163             reader_.ReadSymbol(GetIsCompoundTypeAverageCdf(block));
1164         prediction_parameters.compound_prediction_type =
1165             bp.is_compound_type_average ? kCompoundPredictionTypeAverage
1166                                         : kCompoundPredictionTypeDistance;
1167       } else {
1168         prediction_parameters.compound_prediction_type =
1169             kCompoundPredictionTypeAverage;
1170         return;
1171       }
1172     }
1173     if (prediction_parameters.compound_prediction_type ==
1174         kCompoundPredictionTypeWedge) {
1175       prediction_parameters.wedge_index =
1176           reader_.ReadSymbol<kWedgeIndexSymbolCount>(
1177               symbol_decoder_context_.wedge_index_cdf[block.size]);
1178       prediction_parameters.wedge_sign = static_cast<int>(reader_.ReadBit());
1179     } else if (prediction_parameters.compound_prediction_type ==
1180                kCompoundPredictionTypeDiffWeighted) {
1181       prediction_parameters.mask_is_inverse =
1182           static_cast<bool>(reader_.ReadBit());
1183     }
1184     return;
1185   }
1186   if (prediction_parameters.inter_intra_mode != kNumInterIntraModes) {
1187     prediction_parameters.compound_prediction_type =
1188         prediction_parameters.is_wedge_inter_intra
1189             ? kCompoundPredictionTypeWedge
1190             : kCompoundPredictionTypeIntra;
1191     return;
1192   }
1193   prediction_parameters.compound_prediction_type =
1194       kCompoundPredictionTypeAverage;
1195 }
1196 
GetInterpolationFilterCdf(const Block & block,int direction)1197 uint16_t* Tile::GetInterpolationFilterCdf(const Block& block, int direction) {
1198   const BlockParameters& bp = *block.bp;
1199   int context = MultiplyBy8(direction) +
1200                 MultiplyBy4(static_cast<int>(bp.reference_frame[1] >
1201                                              kReferenceFrameIntra));
1202   int top_type = kNumExplicitInterpolationFilters;
1203   if (block.top_available[kPlaneY]) {
1204     if (block.bp_top->reference_frame[0] == bp.reference_frame[0] ||
1205         block.bp_top->reference_frame[1] == bp.reference_frame[0]) {
1206       top_type = block.bp_top->interpolation_filter[direction];
1207     }
1208   }
1209   int left_type = kNumExplicitInterpolationFilters;
1210   if (block.left_available[kPlaneY]) {
1211     if (block.bp_left->reference_frame[0] == bp.reference_frame[0] ||
1212         block.bp_left->reference_frame[1] == bp.reference_frame[0]) {
1213       left_type = block.bp_left->interpolation_filter[direction];
1214     }
1215   }
1216   if (left_type == top_type) {
1217     context += left_type;
1218   } else if (left_type == kNumExplicitInterpolationFilters) {
1219     context += top_type;
1220   } else if (top_type == kNumExplicitInterpolationFilters) {
1221     context += left_type;
1222   } else {
1223     context += kNumExplicitInterpolationFilters;
1224   }
1225   return symbol_decoder_context_.interpolation_filter_cdf[context];
1226 }
1227 
ReadInterpolationFilter(const Block & block)1228 void Tile::ReadInterpolationFilter(const Block& block) {
1229   BlockParameters& bp = *block.bp;
1230   if (frame_header_.interpolation_filter != kInterpolationFilterSwitchable) {
1231     static_assert(
1232         sizeof(bp.interpolation_filter) / sizeof(bp.interpolation_filter[0]) ==
1233             2,
1234         "Interpolation filter array size is not 2");
1235     for (auto& interpolation_filter : bp.interpolation_filter) {
1236       interpolation_filter = frame_header_.interpolation_filter;
1237     }
1238     return;
1239   }
1240   bool interpolation_filter_present = true;
1241   if (bp.skip_mode ||
1242       block.bp->prediction_parameters->motion_mode == kMotionModeLocalWarp) {
1243     interpolation_filter_present = false;
1244   } else if (!IsBlockDimension4(block.size) &&
1245              bp.y_mode == kPredictionModeGlobalMv) {
1246     interpolation_filter_present =
1247         frame_header_.global_motion[bp.reference_frame[0]].type ==
1248         kGlobalMotionTransformationTypeTranslation;
1249   } else if (!IsBlockDimension4(block.size) &&
1250              bp.y_mode == kPredictionModeGlobalGlobalMv) {
1251     interpolation_filter_present =
1252         frame_header_.global_motion[bp.reference_frame[0]].type ==
1253             kGlobalMotionTransformationTypeTranslation ||
1254         frame_header_.global_motion[bp.reference_frame[1]].type ==
1255             kGlobalMotionTransformationTypeTranslation;
1256   }
1257   for (int i = 0; i < (sequence_header_.enable_dual_filter ? 2 : 1); ++i) {
1258     bp.interpolation_filter[i] =
1259         interpolation_filter_present
1260             ? static_cast<InterpolationFilter>(
1261                   reader_.ReadSymbol<kNumExplicitInterpolationFilters>(
1262                       GetInterpolationFilterCdf(block, i)))
1263             : kInterpolationFilterEightTap;
1264   }
1265   if (!sequence_header_.enable_dual_filter) {
1266     bp.interpolation_filter[1] = bp.interpolation_filter[0];
1267   }
1268 }
1269 
ReadInterBlockModeInfo(const Block & block)1270 bool Tile::ReadInterBlockModeInfo(const Block& block) {
1271   BlockParameters& bp = *block.bp;
1272   bp.palette_mode_info.size[kPlaneTypeY] = 0;
1273   bp.palette_mode_info.size[kPlaneTypeUV] = 0;
1274   ReadReferenceFrames(block);
1275   const bool is_compound = bp.reference_frame[1] > kReferenceFrameIntra;
1276   MvContexts mode_contexts;
1277   FindMvStack(block, is_compound, &mode_contexts);
1278   ReadInterPredictionModeY(block, mode_contexts);
1279   ReadRefMvIndex(block);
1280   if (!AssignInterMv(block, is_compound)) return false;
1281   ReadInterIntraMode(block, is_compound);
1282   ReadMotionMode(block, is_compound);
1283   ReadCompoundType(block, is_compound);
1284   ReadInterpolationFilter(block);
1285   return true;
1286 }
1287 
DecodeInterModeInfo(const Block & block)1288 bool Tile::DecodeInterModeInfo(const Block& block) {
1289   BlockParameters& bp = *block.bp;
1290   block.bp->prediction_parameters->use_intra_block_copy = false;
1291   bp.skip = false;
1292   if (!ReadInterSegmentId(block, /*pre_skip=*/true)) return false;
1293   ReadSkipMode(block);
1294   if (bp.skip_mode) {
1295     bp.skip = true;
1296   } else {
1297     ReadSkip(block);
1298   }
1299   if (!frame_header_.segmentation.segment_id_pre_skip &&
1300       !ReadInterSegmentId(block, /*pre_skip=*/false)) {
1301     return false;
1302   }
1303   ReadCdef(block);
1304   if (read_deltas_) {
1305     ReadQuantizerIndexDelta(block);
1306     ReadLoopFilterDelta(block);
1307     read_deltas_ = false;
1308   }
1309   ReadIsInter(block);
1310   return bp.is_inter ? ReadInterBlockModeInfo(block)
1311                      : ReadIntraBlockModeInfo(block, /*intra_y_mode=*/false);
1312 }
1313 
DecodeModeInfo(const Block & block)1314 bool Tile::DecodeModeInfo(const Block& block) {
1315   return IsIntraFrame(frame_header_.frame_type) ? DecodeIntraModeInfo(block)
1316                                                 : DecodeInterModeInfo(block);
1317 }
1318 
1319 }  // namespace libgav1
1320