• 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 <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