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