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 <cassert>
17 #include <cstdint>
18 #include <cstring>
19 #include <iterator>
20 #include <memory>
21
22 #include "src/obu_parser.h"
23 #include "src/symbol_decoder_context.h"
24 #include "src/tile.h"
25 #include "src/utils/bit_mask_set.h"
26 #include "src/utils/common.h"
27 #include "src/utils/constants.h"
28 #include "src/utils/entropy_decoder.h"
29 #include "src/utils/memory.h"
30 #include "src/utils/types.h"
31
32 namespace libgav1 {
33
GetPaletteCache(const Block & block,PlaneType plane_type,uint16_t * const cache)34 int Tile::GetPaletteCache(const Block& block, PlaneType plane_type,
35 uint16_t* const cache) {
36 const int top_size =
37 (block.top_available[kPlaneY] && Mod64(MultiplyBy4(block.row4x4)) != 0)
38 ? block.bp_top->palette_mode_info.size[plane_type]
39 : 0;
40 const int left_size = block.left_available[kPlaneY]
41 ? block.bp_left->palette_mode_info.size[plane_type]
42 : 0;
43 if (left_size == 0 && top_size == 0) return 0;
44 // Merge the left and top colors in sorted order and store them in |cache|.
45 uint16_t dummy[1];
46 const uint16_t* top = (top_size > 0)
47 ? block.bp_top->palette_mode_info.color[plane_type]
48 : dummy;
49 const uint16_t* left =
50 (left_size > 0) ? block.bp_left->palette_mode_info.color[plane_type]
51 : dummy;
52 std::merge(top, top + top_size, left, left + left_size, cache);
53 // Deduplicate the entries in |cache| and return the number of unique
54 // entries.
55 return static_cast<int>(
56 std::distance(cache, std::unique(cache, cache + left_size + top_size)));
57 }
58
ReadPaletteColors(const Block & block,Plane plane)59 void Tile::ReadPaletteColors(const Block& block, Plane plane) {
60 const PlaneType plane_type = GetPlaneType(plane);
61 uint16_t cache[2 * kMaxPaletteSize];
62 const int n = GetPaletteCache(block, plane_type, cache);
63 BlockParameters& bp = *block.bp;
64 const uint8_t palette_size = bp.palette_mode_info.size[plane_type];
65 uint16_t* const palette_color = bp.palette_mode_info.color[plane];
66 const int8_t bitdepth = sequence_header_.color_config.bitdepth;
67 int index = 0;
68 for (int i = 0; i < n && index < palette_size; ++i) {
69 if (reader_.ReadBit() != 0) { // use_palette_color_cache.
70 palette_color[index++] = cache[i];
71 }
72 }
73 const int merge_pivot = index;
74 if (index < palette_size) {
75 palette_color[index++] =
76 static_cast<uint16_t>(reader_.ReadLiteral(bitdepth));
77 }
78 const int max_value = (1 << bitdepth) - 1;
79 if (index < palette_size) {
80 int bits = bitdepth - 3 + static_cast<int>(reader_.ReadLiteral(2));
81 do {
82 const int delta = static_cast<int>(reader_.ReadLiteral(bits)) +
83 (plane_type == kPlaneTypeY ? 1 : 0);
84 palette_color[index] =
85 std::min(palette_color[index - 1] + delta, max_value);
86 if (palette_color[index] + (plane_type == kPlaneTypeY ? 1 : 0) >=
87 max_value) {
88 // Once the color exceeds max_value, all others can be set to max_value
89 // (since they are computed as a delta on top of the current color and
90 // then clipped).
91 Memset(&palette_color[index + 1], max_value, palette_size - index - 1);
92 break;
93 }
94 const int range = (1 << bitdepth) - palette_color[index] -
95 (plane_type == kPlaneTypeY ? 1 : 0);
96 bits = std::min(bits, CeilLog2(range));
97 } while (++index < palette_size);
98 }
99 // Palette colors are generated using two ascending arrays. So sorting them is
100 // simply a matter of merging the two sorted portions of the array.
101 std::inplace_merge(palette_color, palette_color + merge_pivot,
102 palette_color + palette_size);
103 if (plane_type == kPlaneTypeUV) {
104 uint16_t* const palette_color_v = bp.palette_mode_info.color[kPlaneV];
105 if (reader_.ReadBit() != 0) { // delta_encode_palette_colors_v.
106 const int bits = bitdepth - 4 + static_cast<int>(reader_.ReadLiteral(2));
107 palette_color_v[0] = reader_.ReadLiteral(bitdepth);
108 for (int i = 1; i < palette_size; ++i) {
109 int delta = static_cast<int>(reader_.ReadLiteral(bits));
110 if (delta != 0 && reader_.ReadBit() != 0) delta = -delta;
111 // This line is equivalent to the following lines in the spec:
112 // val = palette_colors_v[ idx - 1 ] + palette_delta_v
113 // if ( val < 0 ) val += maxVal
114 // if ( val >= maxVal ) val -= maxVal
115 // palette_colors_v[ idx ] = Clip1( val )
116 //
117 // The difference is that in the code, max_value is (1 << bitdepth) - 1.
118 // So "& max_value" has the desired effect of computing both the "if"
119 // conditions and the Clip.
120 palette_color_v[i] = (palette_color_v[i - 1] + delta) & max_value;
121 }
122 } else {
123 for (int i = 0; i < palette_size; ++i) {
124 palette_color_v[i] =
125 static_cast<uint16_t>(reader_.ReadLiteral(bitdepth));
126 }
127 }
128 }
129 }
130
ReadPaletteModeInfo(const Block & block)131 void Tile::ReadPaletteModeInfo(const Block& block) {
132 BlockParameters& bp = *block.bp;
133 bp.palette_mode_info.size[kPlaneTypeY] = 0;
134 bp.palette_mode_info.size[kPlaneTypeUV] = 0;
135 if (IsBlockSmallerThan8x8(block.size) || block.size > kBlock64x64 ||
136 !frame_header_.allow_screen_content_tools) {
137 return;
138 }
139 const int block_size_context =
140 k4x4WidthLog2[block.size] + k4x4HeightLog2[block.size] - 2;
141 if (bp.y_mode == kPredictionModeDc) {
142 const int context =
143 static_cast<int>(block.top_available[kPlaneY] &&
144 block.bp_top->palette_mode_info.size[kPlaneTypeY] >
145 0) +
146 static_cast<int>(block.left_available[kPlaneY] &&
147 block.bp_left->palette_mode_info.size[kPlaneTypeY] >
148 0);
149 const bool has_palette_y = reader_.ReadSymbol(
150 symbol_decoder_context_.has_palette_y_cdf[block_size_context][context]);
151 if (has_palette_y) {
152 bp.palette_mode_info.size[kPlaneTypeY] =
153 kMinPaletteSize +
154 reader_.ReadSymbol<kPaletteSizeSymbolCount>(
155 symbol_decoder_context_.palette_y_size_cdf[block_size_context]);
156 ReadPaletteColors(block, kPlaneY);
157 }
158 }
159 if (block.HasChroma() && bp.uv_mode == kPredictionModeDc) {
160 const int context =
161 static_cast<int>(bp.palette_mode_info.size[kPlaneTypeY] > 0);
162 const bool has_palette_uv =
163 reader_.ReadSymbol(symbol_decoder_context_.has_palette_uv_cdf[context]);
164 if (has_palette_uv) {
165 bp.palette_mode_info.size[kPlaneTypeUV] =
166 kMinPaletteSize +
167 reader_.ReadSymbol<kPaletteSizeSymbolCount>(
168 symbol_decoder_context_.palette_uv_size_cdf[block_size_context]);
169 ReadPaletteColors(block, kPlaneU);
170 }
171 }
172 }
173
PopulatePaletteColorContexts(const Block & block,PlaneType plane_type,int i,int start,int end,uint8_t color_order[kMaxPaletteSquare][kMaxPaletteSize],uint8_t color_context[kMaxPaletteSquare])174 void Tile::PopulatePaletteColorContexts(
175 const Block& block, PlaneType plane_type, int i, int start, int end,
176 uint8_t color_order[kMaxPaletteSquare][kMaxPaletteSize],
177 uint8_t color_context[kMaxPaletteSquare]) {
178 const PredictionParameters& prediction_parameters =
179 *block.bp->prediction_parameters;
180 for (int column = start, counter = 0; column >= end; --column, ++counter) {
181 const int row = i - column;
182 assert(row > 0 || column > 0);
183 const uint8_t top =
184 (row > 0)
185 ? prediction_parameters.color_index_map[plane_type][row - 1][column]
186 : 0;
187 const uint8_t left =
188 (column > 0)
189 ? prediction_parameters.color_index_map[plane_type][row][column - 1]
190 : 0;
191 uint8_t index_mask;
192 static_assert(kMaxPaletteSize <= 8, "");
193 int index;
194 if (column <= 0) {
195 color_context[counter] = 0;
196 color_order[counter][0] = top;
197 index_mask = 1 << top;
198 index = 1;
199 } else if (row <= 0) {
200 color_context[counter] = 0;
201 color_order[counter][0] = left;
202 index_mask = 1 << left;
203 index = 1;
204 } else {
205 const uint8_t top_left =
206 prediction_parameters
207 .color_index_map[plane_type][row - 1][column - 1];
208 index_mask = (1 << top) | (1 << left) | (1 << top_left);
209 if (top == left && top == top_left) {
210 color_context[counter] = 4;
211 color_order[counter][0] = top;
212 index = 1;
213 } else if (top == left) {
214 color_context[counter] = 3;
215 color_order[counter][0] = top;
216 color_order[counter][1] = top_left;
217 index = 2;
218 } else if (top == top_left) {
219 color_context[counter] = 2;
220 color_order[counter][0] = top_left;
221 color_order[counter][1] = left;
222 index = 2;
223 } else if (left == top_left) {
224 color_context[counter] = 2;
225 color_order[counter][0] = top_left;
226 color_order[counter][1] = top;
227 index = 2;
228 } else {
229 color_context[counter] = 1;
230 color_order[counter][0] = std::min(top, left);
231 color_order[counter][1] = std::max(top, left);
232 color_order[counter][2] = top_left;
233 index = 3;
234 }
235 }
236 // Even though only the first |palette_size| entries of this array are ever
237 // used, it is faster to populate all 8 because of the vectorization of the
238 // constant sized loop.
239 for (uint8_t j = 0; j < kMaxPaletteSize; ++j) {
240 if (BitMaskSet::MaskContainsValue(index_mask, j)) continue;
241 color_order[counter][index++] = j;
242 }
243 }
244 }
245
ReadPaletteTokens(const Block & block)246 bool Tile::ReadPaletteTokens(const Block& block) {
247 const PaletteModeInfo& palette_mode_info = block.bp->palette_mode_info;
248 PredictionParameters& prediction_parameters =
249 *block.bp->prediction_parameters;
250 for (int plane_type = kPlaneTypeY;
251 plane_type < (block.HasChroma() ? kNumPlaneTypes : kPlaneTypeUV);
252 ++plane_type) {
253 const int palette_size = palette_mode_info.size[plane_type];
254 if (palette_size == 0) continue;
255 int block_height = block.height;
256 int block_width = block.width;
257 int screen_height = std::min(
258 block_height, MultiplyBy4(frame_header_.rows4x4 - block.row4x4));
259 int screen_width = std::min(
260 block_width, MultiplyBy4(frame_header_.columns4x4 - block.column4x4));
261 if (plane_type == kPlaneTypeUV) {
262 block_height >>= sequence_header_.color_config.subsampling_y;
263 block_width >>= sequence_header_.color_config.subsampling_x;
264 screen_height >>= sequence_header_.color_config.subsampling_y;
265 screen_width >>= sequence_header_.color_config.subsampling_x;
266 if (block_height < 4) {
267 block_height += 2;
268 screen_height += 2;
269 }
270 if (block_width < 4) {
271 block_width += 2;
272 screen_width += 2;
273 }
274 }
275 if (!prediction_parameters.color_index_map[plane_type].Reset(
276 block_height, block_width, /*zero_initialize=*/false)) {
277 return false;
278 }
279 int first_value = 0;
280 reader_.DecodeUniform(palette_size, &first_value);
281 prediction_parameters.color_index_map[plane_type][0][0] = first_value;
282 for (int i = 1; i < screen_height + screen_width - 1; ++i) {
283 const int start = std::min(i, screen_width - 1);
284 const int end = std::max(0, i - screen_height + 1);
285 uint8_t color_order[kMaxPaletteSquare][kMaxPaletteSize];
286 uint8_t color_context[kMaxPaletteSquare];
287 PopulatePaletteColorContexts(block, static_cast<PlaneType>(plane_type), i,
288 start, end, color_order, color_context);
289 for (int j = start, counter = 0; j >= end; --j, ++counter) {
290 uint16_t* const cdf =
291 symbol_decoder_context_
292 .palette_color_index_cdf[plane_type]
293 [palette_size - kMinPaletteSize]
294 [color_context[counter]];
295 const int color_order_index = reader_.ReadSymbol(cdf, palette_size);
296 prediction_parameters.color_index_map[plane_type][i - j][j] =
297 color_order[counter][color_order_index];
298 }
299 }
300 if (screen_width < block_width) {
301 for (int i = 0; i < screen_height; ++i) {
302 memset(
303 &prediction_parameters.color_index_map[plane_type][i][screen_width],
304 prediction_parameters
305 .color_index_map[plane_type][i][screen_width - 1],
306 block_width - screen_width);
307 }
308 }
309 for (int i = screen_height; i < block_height; ++i) {
310 memcpy(
311 prediction_parameters.color_index_map[plane_type][i],
312 prediction_parameters.color_index_map[plane_type][screen_height - 1],
313 block_width);
314 }
315 }
316 return true;
317 }
318
319 } // namespace libgav1
320