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