• 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 <cstdint>
17 #include <cstring>
18 
19 #include "src/dsp/constants.h"
20 #include "src/obu_parser.h"
21 #include "src/symbol_decoder_context.h"
22 #include "src/tile.h"
23 #include "src/utils/array_2d.h"
24 #include "src/utils/block_parameters_holder.h"
25 #include "src/utils/common.h"
26 #include "src/utils/constants.h"
27 #include "src/utils/entropy_decoder.h"
28 #include "src/utils/segmentation.h"
29 #include "src/utils/stack.h"
30 #include "src/utils/types.h"
31 
32 namespace libgav1 {
33 namespace {
34 
35 constexpr uint8_t kMaxVariableTransformTreeDepth = 2;
36 // Max_Tx_Depth array from section 5.11.5 in the spec with the following
37 // modification: If the element is not zero, it is subtracted by one. That is
38 // the only way in which this array is being used.
39 constexpr int kTxDepthCdfIndex[kMaxBlockSizes] = {
40     0, 0, 1, 0, 0, 1, 2, 1, 1, 1, 2, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3};
41 
42 constexpr TransformSize kMaxTransformSizeRectangle[kMaxBlockSizes] = {
43     kTransformSize4x4,   kTransformSize4x8,   kTransformSize4x16,
44     kTransformSize8x4,   kTransformSize8x8,   kTransformSize8x16,
45     kTransformSize8x32,  kTransformSize16x4,  kTransformSize16x8,
46     kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
47     kTransformSize32x8,  kTransformSize32x16, kTransformSize32x32,
48     kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
49     kTransformSize64x64, kTransformSize64x64, kTransformSize64x64,
50     kTransformSize64x64};
51 
GetSquareTransformSize(uint8_t pixels)52 TransformSize GetSquareTransformSize(uint8_t pixels) {
53   switch (pixels) {
54     case 128:
55     case 64:
56       return kTransformSize64x64;
57     case 32:
58       return kTransformSize32x32;
59     case 16:
60       return kTransformSize16x16;
61     case 8:
62       return kTransformSize8x8;
63     default:
64       return kTransformSize4x4;
65   }
66 }
67 
68 }  // namespace
69 
GetTopTransformWidth(const Block & block,int row4x4,int column4x4,bool ignore_skip)70 int Tile::GetTopTransformWidth(const Block& block, int row4x4, int column4x4,
71                                bool ignore_skip) {
72   if (row4x4 == block.row4x4) {
73     if (!block.top_available[kPlaneY]) return 64;
74     const BlockParameters& bp_top =
75         *block_parameters_holder_.Find(row4x4 - 1, column4x4);
76     if ((ignore_skip || bp_top.skip) && bp_top.is_inter) {
77       return kBlockWidthPixels[bp_top.size];
78     }
79   }
80   return kTransformWidth[inter_transform_sizes_[row4x4 - 1][column4x4]];
81 }
82 
GetLeftTransformHeight(const Block & block,int row4x4,int column4x4,bool ignore_skip)83 int Tile::GetLeftTransformHeight(const Block& block, int row4x4, int column4x4,
84                                  bool ignore_skip) {
85   if (column4x4 == block.column4x4) {
86     if (!block.left_available[kPlaneY]) return 64;
87     const BlockParameters& bp_left =
88         *block_parameters_holder_.Find(row4x4, column4x4 - 1);
89     if ((ignore_skip || bp_left.skip) && bp_left.is_inter) {
90       return kBlockHeightPixels[bp_left.size];
91     }
92   }
93   return kTransformHeight[inter_transform_sizes_[row4x4][column4x4 - 1]];
94 }
95 
ReadFixedTransformSize(const Block & block)96 TransformSize Tile::ReadFixedTransformSize(const Block& block) {
97   BlockParameters& bp = *block.bp;
98   if (frame_header_.segmentation.lossless[bp.segment_id]) {
99     return kTransformSize4x4;
100   }
101   const TransformSize max_rect_tx_size = kMaxTransformSizeRectangle[block.size];
102   const bool allow_select = !bp.skip || !bp.is_inter;
103   if (block.size == kBlock4x4 || !allow_select ||
104       frame_header_.tx_mode != kTxModeSelect) {
105     return max_rect_tx_size;
106   }
107   const int max_tx_width = kTransformWidth[max_rect_tx_size];
108   const int max_tx_height = kTransformHeight[max_rect_tx_size];
109   const int top_width =
110       block.top_available[kPlaneY]
111           ? GetTopTransformWidth(block, block.row4x4, block.column4x4, true)
112           : 0;
113   const int left_height =
114       block.left_available[kPlaneY]
115           ? GetLeftTransformHeight(block, block.row4x4, block.column4x4, true)
116           : 0;
117   const auto context = static_cast<int>(top_width >= max_tx_width) +
118                        static_cast<int>(left_height >= max_tx_height);
119   const int cdf_index = kTxDepthCdfIndex[block.size];
120   uint16_t* const cdf =
121       symbol_decoder_context_.tx_depth_cdf[cdf_index][context];
122   const int tx_depth = (cdf_index == 0)
123                            ? static_cast<int>(reader_.ReadSymbol(cdf))
124                            : reader_.ReadSymbol<3>(cdf);
125   assert(tx_depth < 3);
126   TransformSize tx_size = max_rect_tx_size;
127   if (tx_depth == 0) return tx_size;
128   tx_size = kSplitTransformSize[tx_size];
129   if (tx_depth == 1) return tx_size;
130   return kSplitTransformSize[tx_size];
131 }
132 
ReadVariableTransformTree(const Block & block,int row4x4,int column4x4,TransformSize tx_size)133 void Tile::ReadVariableTransformTree(const Block& block, int row4x4,
134                                      int column4x4, TransformSize tx_size) {
135   const uint8_t pixels = std::max(block.width, block.height);
136   const TransformSize max_tx_size = GetSquareTransformSize(pixels);
137   const int context_delta = (kNumSquareTransformSizes - 1 -
138                              TransformSizeToSquareTransformIndex(max_tx_size)) *
139                             6;
140 
141   // Branching factor is 4 and maximum depth is 2. So the maximum stack size
142   // necessary is (4 - 1) + 4 = 7.
143   Stack<TransformTreeNode, 7> stack;
144   stack.Push(TransformTreeNode(column4x4, row4x4, tx_size, 0));
145 
146   do {
147     TransformTreeNode node = stack.Pop();
148     const int tx_width4x4 = kTransformWidth4x4[node.tx_size];
149     const int tx_height4x4 = kTransformHeight4x4[node.tx_size];
150     if (node.tx_size != kTransformSize4x4 &&
151         node.depth != kMaxVariableTransformTreeDepth) {
152       const auto top =
153           static_cast<int>(GetTopTransformWidth(block, node.y, node.x, false) <
154                            kTransformWidth[node.tx_size]);
155       const auto left = static_cast<int>(
156           GetLeftTransformHeight(block, node.y, node.x, false) <
157           kTransformHeight[node.tx_size]);
158       const int context =
159           static_cast<int>(max_tx_size > kTransformSize8x8 &&
160                            kTransformSizeSquareMax[node.tx_size] !=
161                                max_tx_size) *
162               3 +
163           context_delta + top + left;
164       // tx_split.
165       if (reader_.ReadSymbol(symbol_decoder_context_.tx_split_cdf[context])) {
166         const TransformSize sub_tx_size = kSplitTransformSize[node.tx_size];
167         const int step_width4x4 = kTransformWidth4x4[sub_tx_size];
168         const int step_height4x4 = kTransformHeight4x4[sub_tx_size];
169         // The loops have to run in reverse order because we use a stack for
170         // DFS.
171         for (int i = tx_height4x4 - step_height4x4; i >= 0;
172              i -= step_height4x4) {
173           for (int j = tx_width4x4 - step_width4x4; j >= 0;
174                j -= step_width4x4) {
175             if (node.y + i >= frame_header_.rows4x4 ||
176                 node.x + j >= frame_header_.columns4x4) {
177               continue;
178             }
179             stack.Push(TransformTreeNode(node.x + j, node.y + i, sub_tx_size,
180                                          node.depth + 1));
181           }
182         }
183         continue;
184       }
185     }
186     // tx_split is false.
187     for (int i = 0; i < tx_height4x4; ++i) {
188       static_assert(sizeof(TransformSize) == 1, "");
189       memset(&inter_transform_sizes_[node.y + i][node.x], node.tx_size,
190              tx_width4x4);
191     }
192     block_parameters_holder_.Find(node.y, node.x)->transform_size =
193         node.tx_size;
194   } while (!stack.Empty());
195 }
196 
DecodeTransformSize(const Block & block)197 void Tile::DecodeTransformSize(const Block& block) {
198   BlockParameters& bp = *block.bp;
199   if (frame_header_.tx_mode == kTxModeSelect && block.size > kBlock4x4 &&
200       bp.is_inter && !bp.skip &&
201       !frame_header_.segmentation.lossless[bp.segment_id]) {
202     const TransformSize max_tx_size = kMaxTransformSizeRectangle[block.size];
203     const int tx_width4x4 = kTransformWidth4x4[max_tx_size];
204     const int tx_height4x4 = kTransformHeight4x4[max_tx_size];
205     for (int row = block.row4x4; row < block.row4x4 + block.height4x4;
206          row += tx_height4x4) {
207       for (int column = block.column4x4;
208            column < block.column4x4 + block.width4x4; column += tx_width4x4) {
209         ReadVariableTransformTree(block, row, column, max_tx_size);
210       }
211     }
212   } else {
213     bp.transform_size = ReadFixedTransformSize(block);
214     for (int row = block.row4x4; row < block.row4x4 + block.height4x4; ++row) {
215       static_assert(sizeof(TransformSize) == 1, "");
216       memset(&inter_transform_sizes_[row][block.column4x4], bp.transform_size,
217              block.width4x4);
218     }
219   }
220 }
221 
222 }  // namespace libgav1
223