1*09537850SAkhilesh Sanikop // Copyright 2019 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include <cassert>
16*09537850SAkhilesh Sanikop #include <cstdint>
17*09537850SAkhilesh Sanikop
18*09537850SAkhilesh Sanikop #include "src/symbol_decoder_context.h"
19*09537850SAkhilesh Sanikop #include "src/tile.h"
20*09537850SAkhilesh Sanikop #include "src/utils/block_parameters_holder.h"
21*09537850SAkhilesh Sanikop #include "src/utils/common.h"
22*09537850SAkhilesh Sanikop #include "src/utils/constants.h"
23*09537850SAkhilesh Sanikop #include "src/utils/entropy_decoder.h"
24*09537850SAkhilesh Sanikop #include "src/utils/types.h"
25*09537850SAkhilesh Sanikop
26*09537850SAkhilesh Sanikop namespace libgav1 {
27*09537850SAkhilesh Sanikop namespace {
28*09537850SAkhilesh Sanikop
PartitionCdfGatherHorizontalAlike(const uint16_t * const partition_cdf,BlockSize block_size)29*09537850SAkhilesh Sanikop uint16_t PartitionCdfGatherHorizontalAlike(const uint16_t* const partition_cdf,
30*09537850SAkhilesh Sanikop BlockSize block_size) {
31*09537850SAkhilesh Sanikop // The spec computes the cdf value using the following formula (not writing
32*09537850SAkhilesh Sanikop // partition_cdf[] and using short forms for partition names for clarity):
33*09537850SAkhilesh Sanikop // cdf = None - H + V - S + S - HTS + HTS - HBS + HBS - VLS;
34*09537850SAkhilesh Sanikop // if (block_size != 128x128) {
35*09537850SAkhilesh Sanikop // cdf += VRS - H4;
36*09537850SAkhilesh Sanikop // }
37*09537850SAkhilesh Sanikop // After canceling out the repeated terms with opposite signs, we have:
38*09537850SAkhilesh Sanikop // cdf = None - H + V - VLS;
39*09537850SAkhilesh Sanikop // if (block_size != 128x128) {
40*09537850SAkhilesh Sanikop // cdf += VRS - H4;
41*09537850SAkhilesh Sanikop // }
42*09537850SAkhilesh Sanikop uint16_t cdf = partition_cdf[kPartitionNone] -
43*09537850SAkhilesh Sanikop partition_cdf[kPartitionHorizontal] +
44*09537850SAkhilesh Sanikop partition_cdf[kPartitionVertical] -
45*09537850SAkhilesh Sanikop partition_cdf[kPartitionVerticalWithLeftSplit];
46*09537850SAkhilesh Sanikop if (block_size != kBlock128x128) {
47*09537850SAkhilesh Sanikop cdf += partition_cdf[kPartitionVerticalWithRightSplit] -
48*09537850SAkhilesh Sanikop partition_cdf[kPartitionHorizontal4];
49*09537850SAkhilesh Sanikop }
50*09537850SAkhilesh Sanikop return cdf;
51*09537850SAkhilesh Sanikop }
52*09537850SAkhilesh Sanikop
PartitionCdfGatherVerticalAlike(const uint16_t * const partition_cdf,BlockSize block_size)53*09537850SAkhilesh Sanikop uint16_t PartitionCdfGatherVerticalAlike(const uint16_t* const partition_cdf,
54*09537850SAkhilesh Sanikop BlockSize block_size) {
55*09537850SAkhilesh Sanikop // The spec computes the cdf value using the following formula (not writing
56*09537850SAkhilesh Sanikop // partition_cdf[] and using short forms for partition names for clarity):
57*09537850SAkhilesh Sanikop // cdf = H - V + V - S + HBS - VLS + VLS - VRS + S - HTS;
58*09537850SAkhilesh Sanikop // if (block_size != 128x128) {
59*09537850SAkhilesh Sanikop // cdf += H4 - V4;
60*09537850SAkhilesh Sanikop // }
61*09537850SAkhilesh Sanikop // V4 is always zero. So, after canceling out the repeated terms with opposite
62*09537850SAkhilesh Sanikop // signs, we have:
63*09537850SAkhilesh Sanikop // cdf = H + HBS - VRS - HTS;
64*09537850SAkhilesh Sanikop // if (block_size != 128x128) {
65*09537850SAkhilesh Sanikop // cdf += H4;
66*09537850SAkhilesh Sanikop // }
67*09537850SAkhilesh Sanikop // VRS is zero for 128x128 blocks. So, further simplifying we have:
68*09537850SAkhilesh Sanikop // cdf = H + HBS - HTS;
69*09537850SAkhilesh Sanikop // if (block_size != 128x128) {
70*09537850SAkhilesh Sanikop // cdf += H4 - VRS;
71*09537850SAkhilesh Sanikop // }
72*09537850SAkhilesh Sanikop uint16_t cdf = partition_cdf[kPartitionHorizontal] +
73*09537850SAkhilesh Sanikop partition_cdf[kPartitionHorizontalWithBottomSplit] -
74*09537850SAkhilesh Sanikop partition_cdf[kPartitionHorizontalWithTopSplit];
75*09537850SAkhilesh Sanikop if (block_size != kBlock128x128) {
76*09537850SAkhilesh Sanikop cdf += partition_cdf[kPartitionHorizontal4] -
77*09537850SAkhilesh Sanikop partition_cdf[kPartitionVerticalWithRightSplit];
78*09537850SAkhilesh Sanikop }
79*09537850SAkhilesh Sanikop return cdf;
80*09537850SAkhilesh Sanikop }
81*09537850SAkhilesh Sanikop
82*09537850SAkhilesh Sanikop } // namespace
83*09537850SAkhilesh Sanikop
GetPartitionCdf(int row4x4,int column4x4,BlockSize block_size)84*09537850SAkhilesh Sanikop uint16_t* Tile::GetPartitionCdf(int row4x4, int column4x4,
85*09537850SAkhilesh Sanikop BlockSize block_size) {
86*09537850SAkhilesh Sanikop const int block_size_log2 = k4x4WidthLog2[block_size];
87*09537850SAkhilesh Sanikop int top = 0;
88*09537850SAkhilesh Sanikop if (IsTopInside(row4x4)) {
89*09537850SAkhilesh Sanikop top = static_cast<int>(
90*09537850SAkhilesh Sanikop k4x4WidthLog2[block_parameters_holder_.Find(row4x4 - 1, column4x4)
91*09537850SAkhilesh Sanikop ->size] < block_size_log2);
92*09537850SAkhilesh Sanikop }
93*09537850SAkhilesh Sanikop int left = 0;
94*09537850SAkhilesh Sanikop if (IsLeftInside(column4x4)) {
95*09537850SAkhilesh Sanikop left = static_cast<int>(
96*09537850SAkhilesh Sanikop k4x4HeightLog2[block_parameters_holder_.Find(row4x4, column4x4 - 1)
97*09537850SAkhilesh Sanikop ->size] < block_size_log2);
98*09537850SAkhilesh Sanikop }
99*09537850SAkhilesh Sanikop const int context = left * 2 + top;
100*09537850SAkhilesh Sanikop return symbol_decoder_context_.partition_cdf[block_size_log2 - 1][context];
101*09537850SAkhilesh Sanikop }
102*09537850SAkhilesh Sanikop
ReadPartition(int row4x4,int column4x4,BlockSize block_size,bool has_rows,bool has_columns,Partition * const partition)103*09537850SAkhilesh Sanikop bool Tile::ReadPartition(int row4x4, int column4x4, BlockSize block_size,
104*09537850SAkhilesh Sanikop bool has_rows, bool has_columns,
105*09537850SAkhilesh Sanikop Partition* const partition) {
106*09537850SAkhilesh Sanikop if (IsBlockSmallerThan8x8(block_size)) {
107*09537850SAkhilesh Sanikop *partition = kPartitionNone;
108*09537850SAkhilesh Sanikop return true;
109*09537850SAkhilesh Sanikop }
110*09537850SAkhilesh Sanikop if (!has_rows && !has_columns) {
111*09537850SAkhilesh Sanikop *partition = kPartitionSplit;
112*09537850SAkhilesh Sanikop return true;
113*09537850SAkhilesh Sanikop }
114*09537850SAkhilesh Sanikop uint16_t* const partition_cdf =
115*09537850SAkhilesh Sanikop GetPartitionCdf(row4x4, column4x4, block_size);
116*09537850SAkhilesh Sanikop if (partition_cdf == nullptr) {
117*09537850SAkhilesh Sanikop return false;
118*09537850SAkhilesh Sanikop }
119*09537850SAkhilesh Sanikop if (has_rows && has_columns) {
120*09537850SAkhilesh Sanikop const int bsize_log2 = k4x4WidthLog2[block_size];
121*09537850SAkhilesh Sanikop // The partition block size should be 8x8 or above.
122*09537850SAkhilesh Sanikop assert(bsize_log2 > 0);
123*09537850SAkhilesh Sanikop if (bsize_log2 == 1) {
124*09537850SAkhilesh Sanikop *partition = static_cast<Partition>(
125*09537850SAkhilesh Sanikop reader_.ReadSymbol<kPartitionSplit + 1>(partition_cdf));
126*09537850SAkhilesh Sanikop } else if (bsize_log2 == 5) {
127*09537850SAkhilesh Sanikop *partition = static_cast<Partition>(
128*09537850SAkhilesh Sanikop reader_.ReadSymbol<kPartitionVerticalWithRightSplit + 1>(
129*09537850SAkhilesh Sanikop partition_cdf));
130*09537850SAkhilesh Sanikop } else {
131*09537850SAkhilesh Sanikop *partition = static_cast<Partition>(
132*09537850SAkhilesh Sanikop reader_.ReadSymbol<kMaxPartitionTypes>(partition_cdf));
133*09537850SAkhilesh Sanikop }
134*09537850SAkhilesh Sanikop } else if (has_columns) {
135*09537850SAkhilesh Sanikop const uint16_t cdf =
136*09537850SAkhilesh Sanikop PartitionCdfGatherVerticalAlike(partition_cdf, block_size);
137*09537850SAkhilesh Sanikop *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
138*09537850SAkhilesh Sanikop : kPartitionHorizontal;
139*09537850SAkhilesh Sanikop } else {
140*09537850SAkhilesh Sanikop const uint16_t cdf =
141*09537850SAkhilesh Sanikop PartitionCdfGatherHorizontalAlike(partition_cdf, block_size);
142*09537850SAkhilesh Sanikop *partition = reader_.ReadSymbolWithoutCdfUpdate(cdf) ? kPartitionSplit
143*09537850SAkhilesh Sanikop : kPartitionVertical;
144*09537850SAkhilesh Sanikop }
145*09537850SAkhilesh Sanikop return true;
146*09537850SAkhilesh Sanikop }
147*09537850SAkhilesh Sanikop
148*09537850SAkhilesh Sanikop } // namespace libgav1
149