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