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 <cassert>
16 #include <cstdint>
17 
18 #include "src/symbol_decoder_context.h"
19 #include "src/tile.h"
20 #include "src/utils/block_parameters_holder.h"
21 #include "src/utils/common.h"
22 #include "src/utils/constants.h"
23 #include "src/utils/entropy_decoder.h"
24 #include "src/utils/types.h"
25 
26 namespace libgav1 {
27 namespace {
28 
PartitionCdfGatherHorizontalAlike(const uint16_t * const partition_cdf,BlockSize block_size)29 uint16_t PartitionCdfGatherHorizontalAlike(const uint16_t* const partition_cdf,
30                                            BlockSize block_size) {
31   // The spec computes the cdf value using the following formula (not writing
32   // partition_cdf[] and using short forms for partition names for clarity):
33   //   cdf = None - H + V - S + S - HTS + HTS - HBS + HBS - VLS;
34   //   if (block_size != 128x128) {
35   //     cdf += VRS - H4;
36   //   }
37   // After canceling out the repeated terms with opposite signs, we have:
38   //   cdf = None - H + V - VLS;
39   //   if (block_size != 128x128) {
40   //     cdf += VRS - H4;
41   //   }
42   uint16_t cdf = partition_cdf[kPartitionNone] -
43                  partition_cdf[kPartitionHorizontal] +
44                  partition_cdf[kPartitionVertical] -
45                  partition_cdf[kPartitionVerticalWithLeftSplit];
46   if (block_size != kBlock128x128) {
47     cdf += partition_cdf[kPartitionVerticalWithRightSplit] -
48            partition_cdf[kPartitionHorizontal4];
49   }
50   return cdf;
51 }
52 
PartitionCdfGatherVerticalAlike(const uint16_t * const partition_cdf,BlockSize block_size)53 uint16_t PartitionCdfGatherVerticalAlike(const uint16_t* const partition_cdf,
54                                          BlockSize block_size) {
55   // The spec computes the cdf value using the following formula (not writing
56   // partition_cdf[] and using short forms for partition names for clarity):
57   //   cdf = H - V + V - S + HBS - VLS + VLS - VRS + S - HTS;
58   //   if (block_size != 128x128) {
59   //     cdf += H4 - V4;
60   //   }
61   // V4 is always zero. So, after canceling out the repeated terms with opposite
62   // signs, we have:
63   //   cdf = H + HBS - VRS - HTS;
64   //   if (block_size != 128x128) {
65   //     cdf += H4;
66   //   }
67   // VRS is zero for 128x128 blocks. So, further simplifying we have:
68   //   cdf = H + HBS - HTS;
69   //   if (block_size != 128x128) {
70   //     cdf += H4 - VRS;
71   //   }
72   uint16_t cdf = partition_cdf[kPartitionHorizontal] +
73                  partition_cdf[kPartitionHorizontalWithBottomSplit] -
74                  partition_cdf[kPartitionHorizontalWithTopSplit];
75   if (block_size != kBlock128x128) {
76     cdf += partition_cdf[kPartitionHorizontal4] -
77            partition_cdf[kPartitionVerticalWithRightSplit];
78   }
79   return cdf;
80 }
81 
82 }  // namespace
83 
GetPartitionCdf(int row4x4,int column4x4,BlockSize block_size)84 uint16_t* Tile::GetPartitionCdf(int row4x4, int column4x4,
85                                 BlockSize block_size) {
86   const int block_size_log2 = k4x4WidthLog2[block_size];
87   int top = 0;
88   if (IsTopInside(row4x4)) {
89     top = static_cast<int>(
90         k4x4WidthLog2[block_parameters_holder_.Find(row4x4 - 1, column4x4)
91                           ->size] < block_size_log2);
92   }
93   int left = 0;
94   if (IsLeftInside(column4x4)) {
95     left = static_cast<int>(
96         k4x4HeightLog2[block_parameters_holder_.Find(row4x4, column4x4 - 1)
97                            ->size] < block_size_log2);
98   }
99   const int context = left * 2 + top;
100   return symbol_decoder_context_.partition_cdf[block_size_log2 - 1][context];
101 }
102 
ReadPartition(int row4x4,int column4x4,BlockSize block_size,bool has_rows,bool has_columns,Partition * const partition)103 bool Tile::ReadPartition(int row4x4, int column4x4, BlockSize block_size,
104                          bool has_rows, bool has_columns,
105                          Partition* const partition) {
106   if (IsBlockSmallerThan8x8(block_size)) {
107     *partition = kPartitionNone;
108     return true;
109   }
110   if (!has_rows && !has_columns) {
111     *partition = kPartitionSplit;
112     return true;
113   }
114   uint16_t* const partition_cdf =
115       GetPartitionCdf(row4x4, column4x4, block_size);
116   if (partition_cdf == nullptr) {
117     return false;
118   }
119   if (has_rows && has_columns) {
120     const int bsize_log2 = k4x4WidthLog2[block_size];
121     // The partition block size should be 8x8 or above.
122     assert(bsize_log2 > 0);
123     if (bsize_log2 == 1) {
124       *partition = static_cast<Partition>(
125           reader_.ReadSymbol<kPartitionSplit + 1>(partition_cdf));
126     } else if (bsize_log2 == 5) {
127       *partition = static_cast<Partition>(
128           reader_.ReadSymbol<kPartitionVerticalWithRightSplit + 1>(
129               partition_cdf));
130     } else {
131       *partition = static_cast<Partition>(
132           reader_.ReadSymbol<kMaxPartitionTypes>(partition_cdf));
133     }
134   } else if (has_columns) {
135     const uint16_t cdf =
136         PartitionCdfGatherVerticalAlike(partition_cdf, block_size);
137     *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
138                                                          : kPartitionHorizontal;
139   } else {
140     const uint16_t cdf =
141         PartitionCdfGatherHorizontalAlike(partition_cdf, block_size);
142     *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
143                                                          : kPartitionVertical;
144   }
145   return true;
146 }
147 
148 }  // namespace libgav1
149