Shaka Packager SDK
dvb_sub_parser.cc
1 // Copyright 2020 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/media/formats/dvb/dvb_sub_parser.h>
8 
9 #include <algorithm>
10 
11 #include <absl/log/check.h>
12 #include <absl/log/log.h>
13 
14 #include <packager/media/formats/mp2t/mp2t_common.h>
15 
16 namespace shaka {
17 namespace media {
18 
19 namespace {
20 
21 RgbaColor ConvertYuv(uint8_t Y, uint8_t Cr, uint8_t Cb, uint8_t T) {
22  // Converts based on ITU-R BT.601.
23  // See https://en.wikipedia.org/wiki/YCbCr
24  //
25  // Note that the T value should be interpolated based on a full transparency
26  // being 256. This means that T=255 should not be fully transparent. Y=0 is
27  // used to signal full transparency.
28  // Values for Y<16 (except Y=0) are invalid, so clamp to 16.
29  RgbaColor color;
30  const double y_transform = 255.0 / 219 * (std::max<uint8_t>(Y, 16) - 16);
31  const double cb_transform = 255.0 / 244 * 1.772 * (Cb - 128);
32  const double cr_transform = 255.0 / 244 * 1.402 * (Cr - 128);
33  const double f1 = 0.114 / 0.587;
34  const double f2 = 0.299 / 0.587;
35  color.r = static_cast<uint8_t>(y_transform + cr_transform);
36  color.g =
37  static_cast<uint8_t>(y_transform - cb_transform * f1 - cr_transform * f2);
38  color.b = static_cast<uint8_t>(y_transform + cb_transform);
39  color.a = Y == 0 ? 0 : (T == 0 ? 255 : 256 - T);
40  return color;
41 }
42 
43 } // namespace
44 
45 DvbSubParser::DvbSubParser() : last_pts_(0), timeout_(0) {}
46 
47 DvbSubParser::~DvbSubParser() {}
48 
49 bool DvbSubParser::Parse(DvbSubSegmentType segment_type,
50  int64_t pts,
51  const uint8_t* payload,
52  size_t size,
53  std::vector<std::shared_ptr<TextSample>>* samples) {
54  switch (segment_type) {
55  case DvbSubSegmentType::kPageComposition:
56  return ParsePageComposition(pts, payload, size, samples);
57  case DvbSubSegmentType::kRegionComposition:
58  return ParseRegionComposition(payload, size);
59  case DvbSubSegmentType::kClutDefinition:
60  return ParseClutDefinition(payload, size);
61  case DvbSubSegmentType::kObjectData:
62  return ParseObjectData(pts, payload, size);
63  case DvbSubSegmentType::kDisplayDefinition:
64  return ParseDisplayDefinition(payload, size);
65  case DvbSubSegmentType::kEndOfDisplay:
66  // This signals all the current objects are available. But we need to
67  // know the end time, so we do nothing for now.
68  return true;
69  default:
70  LOG(WARNING) << "Unknown DVB-sub segment_type=0x" << std::hex
71  << static_cast<uint32_t>(segment_type);
72  return true;
73  }
74 }
75 
76 bool DvbSubParser::Flush(std::vector<std::shared_ptr<TextSample>>* samples) {
77  RCHECK(composer_.GetSamples(last_pts_, last_pts_ + timeout_ * kMpeg2Timescale,
78  samples));
79  composer_.ClearObjects();
80  return true;
81 }
82 
83 const DvbImageColorSpace* DvbSubParser::GetColorSpace(uint8_t clut_id) {
84  return composer_.GetColorSpace(clut_id);
85 }
86 
87 const DvbImageBuilder* DvbSubParser::GetImageForObject(uint16_t object_id) {
88  return composer_.GetObjectImage(object_id);
89 }
90 
91 bool DvbSubParser::ParsePageComposition(
92  int64_t pts,
93  const uint8_t* data,
94  size_t size,
95  std::vector<std::shared_ptr<TextSample>>* samples) {
96  // See ETSI EN 300 743 Section 7.2.2.
97  BitReader reader(data, size);
98 
99  uint8_t page_state;
100  RCHECK(reader.ReadBits(8, &timeout_));
101  RCHECK(reader.SkipBits(4)); // page_version_number
102  RCHECK(reader.ReadBits(2, &page_state));
103  RCHECK(reader.SkipBits(2)); // reserved
104  if (page_state == 0x1 || page_state == 0x2) {
105  // If this is a "acquisition point" or a "mode change", then this is a new
106  // page and we should clear the old data.
107  RCHECK(composer_.GetSamples(last_pts_, pts, samples));
108  composer_.ClearObjects();
109  last_pts_ = pts;
110  }
111 
112  while (reader.bits_available() > 0u) {
113  uint8_t region_id;
114  uint16_t x, y;
115  RCHECK(reader.ReadBits(8, &region_id));
116  RCHECK(reader.SkipBits(8)); // reserved
117  RCHECK(reader.ReadBits(16, &x));
118  RCHECK(reader.ReadBits(16, &y));
119 
120  RCHECK(composer_.SetRegionPosition(region_id, x, y));
121  }
122 
123  return true;
124 }
125 
126 bool DvbSubParser::ParseRegionComposition(const uint8_t* data, size_t size) {
127  // See ETSI EN 300 743 Section 7.2.3.
128  BitReader reader(data, size);
129 
130  uint8_t region_id, clut_id;
131  uint16_t region_width, region_height;
132  bool region_fill_flag;
133  int background_pixel_code;
134  RCHECK(reader.ReadBits(8, &region_id));
135  RCHECK(reader.SkipBits(4)); // region_version_number
136  RCHECK(reader.ReadBits(1, &region_fill_flag));
137  RCHECK(reader.SkipBits(3)); // reserved
138  RCHECK(reader.ReadBits(16, &region_width));
139  RCHECK(reader.ReadBits(16, &region_height));
140  RCHECK(reader.SkipBits(3)); // region_level_of_compatibility
141  RCHECK(reader.SkipBits(3)); // region_depth
142  RCHECK(reader.SkipBits(2)); // reserved
143  RCHECK(reader.ReadBits(8, &clut_id));
144  RCHECK(reader.ReadBits(8, &background_pixel_code));
145  RCHECK(reader.SkipBits(4)); // region_4-bit_pixel_code
146  RCHECK(reader.SkipBits(2)); // region_2-bit_pixel_code
147  RCHECK(reader.SkipBits(2)); // reserved
148  RCHECK(
149  composer_.SetRegionInfo(region_id, clut_id, region_width, region_height));
150  if (!region_fill_flag)
151  background_pixel_code = -1;
152 
153  while (reader.bits_available() > 0) {
154  uint16_t object_id, x, y;
155  uint8_t object_type;
156  RCHECK(reader.ReadBits(16, &object_id));
157  RCHECK(reader.ReadBits(2, &object_type));
158  RCHECK(reader.SkipBits(2)); // object_provider_flag
159  RCHECK(reader.ReadBits(12, &x));
160  RCHECK(reader.SkipBits(4)); // reserved
161  RCHECK(reader.ReadBits(12, &y));
162 
163  if (object_type == 0x01 || object_type == 0x02) {
164  RCHECK(reader.SkipBits(8)); // foreground_pixel_code
165  RCHECK(reader.SkipBits(8)); // background_pixel_code
166  }
167  RCHECK(composer_.SetObjectInfo(object_id, region_id, x, y,
168  background_pixel_code));
169  }
170 
171  return true;
172 }
173 
174 bool DvbSubParser::ParseClutDefinition(const uint8_t* data, size_t size) {
175  // See ETSI EN 300 743 Section 7.2.4.
176  BitReader reader(data, size);
177 
178  uint8_t clut_id;
179  RCHECK(reader.ReadBits(8, &clut_id));
180  auto* color_space = composer_.GetColorSpace(clut_id);
181  RCHECK(reader.SkipBits(4)); // CLUT_version_number
182  RCHECK(reader.SkipBits(4)); // reserved
183  while (reader.bits_available() > 0) {
184  uint8_t clut_entry_id;
185  uint8_t has_2_bit;
186  uint8_t has_4_bit;
187  uint8_t has_8_bit;
188  uint8_t full_range_flag;
189  RCHECK(reader.ReadBits(8, &clut_entry_id));
190  RCHECK(reader.ReadBits(1, &has_2_bit));
191  RCHECK(reader.ReadBits(1, &has_4_bit));
192  RCHECK(reader.ReadBits(1, &has_8_bit));
193  RCHECK(reader.SkipBits(4)); // reserved
194  RCHECK(reader.ReadBits(1, &full_range_flag));
195 
196  if (has_2_bit + has_4_bit + has_8_bit != 1) {
197  LOG(ERROR) << "Must specify exactly one bit depth in CLUT definition";
198  return false;
199  }
200  const BitDepth bit_depth =
201  has_2_bit ? BitDepth::k2Bit
202  : (has_4_bit ? BitDepth::k4Bit : BitDepth::k8Bit);
203 
204  uint8_t Y, Cr, Cb, T;
205  if (full_range_flag) {
206  RCHECK(reader.ReadBits(8, &Y));
207  RCHECK(reader.ReadBits(8, &Cr));
208  RCHECK(reader.ReadBits(8, &Cb));
209  RCHECK(reader.ReadBits(8, &T));
210  } else {
211  // These store the most-significant bits, so shift them up.
212  RCHECK(reader.ReadBits(6, &Y));
213  Y <<= 2;
214  RCHECK(reader.ReadBits(4, &Cr));
215  Cr <<= 4;
216  RCHECK(reader.ReadBits(4, &Cb));
217  Cb <<= 4;
218  RCHECK(reader.ReadBits(2, &T));
219  T <<= 6;
220  }
221  color_space->SetColor(bit_depth, clut_entry_id, ConvertYuv(Y, Cr, Cb, T));
222  }
223 
224  return true;
225 }
226 
227 bool DvbSubParser::ParseObjectData(int64_t pts,
228  const uint8_t* data,
229  size_t size) {
230  // See ETSI EN 300 743 Section 7.2.5 Table 17.
231  BitReader reader(data, size);
232 
233  uint16_t object_id;
234  uint8_t object_coding_method;
235  RCHECK(reader.ReadBits(16, &object_id));
236  RCHECK(reader.SkipBits(4)); // object_version_number
237  RCHECK(reader.ReadBits(2, &object_coding_method));
238  RCHECK(reader.SkipBits(1)); // non_modifying_colour_flag
239  RCHECK(reader.SkipBits(1)); // reserved
240 
241  auto* image = composer_.GetObjectImage(object_id);
242  auto* color_space = composer_.GetColorSpaceForObject(object_id);
243  if (!image || !color_space)
244  return false;
245 
246  if (object_coding_method == 0) {
247  uint16_t top_field_length;
248  uint16_t bottom_field_length;
249  RCHECK(reader.ReadBits(16, &top_field_length));
250  RCHECK(reader.ReadBits(16, &bottom_field_length));
251 
252  RCHECK(ParsePixelDataSubObject(top_field_length, true, &reader, color_space,
253  image));
254  RCHECK(ParsePixelDataSubObject(bottom_field_length, false, &reader,
255  color_space, image));
256  // Ignore 8_stuff_bits since we don't need to read to the end.
257 
258  if (bottom_field_length == 0) {
259  // If there are no bottom rows, then the top rows are used instead. See
260  // beginning of section 7.2.5.1.
261  image->MirrorToBottomRows();
262  }
263  } else {
264  LOG(ERROR) << "Unsupported DVB-sub object coding method: "
265  << static_cast<int>(object_coding_method);
266  return false;
267  }
268  return true;
269 }
270 
271 bool DvbSubParser::ParseDisplayDefinition(const uint8_t* data, size_t size) {
272  // See ETSI EN 300 743 Section 7.2.1.
273  BitReader reader(data, size);
274 
275  uint16_t width, height;
276  RCHECK(reader.SkipBits(4)); // dds_version_number
277  RCHECK(reader.SkipBits(1)); // display_window_flag
278  RCHECK(reader.SkipBits(3)); // reserved
279  RCHECK(reader.ReadBits(16, &width));
280  RCHECK(reader.ReadBits(16, &height));
281  // Size is stored as -1.
282  composer_.SetDisplaySize(width + 1, height + 1);
283 
284  return true;
285 }
286 
287 bool DvbSubParser::ParsePixelDataSubObject(size_t sub_object_length,
288  bool is_top_fields,
289  BitReader* reader,
290  DvbImageColorSpace* color_space,
291  DvbImageBuilder* image) {
292  const size_t start = reader->bit_position() / 8;
293  while (reader->bit_position() / 8 < start + sub_object_length) {
294  // See ETSI EN 300 743 Section 7.2.5.1 Table 20
295  uint8_t data_type;
296  RCHECK(reader->ReadBits(8, &data_type));
297  uint8_t temp[16];
298  switch (data_type) {
299  case 0x10:
300  RCHECK(Parse2BitPixelData(is_top_fields, reader, image));
301  reader->SkipToNextByte();
302  break;
303  case 0x11:
304  RCHECK(Parse4BitPixelData(is_top_fields, reader, image));
305  reader->SkipToNextByte();
306  break;
307  case 0x12:
308  RCHECK(Parse8BitPixelData(is_top_fields, reader, image));
309  break;
310  case 0x20:
311  for (int i = 0; i < 4; i++) {
312  RCHECK(reader->ReadBits(4, &temp[i]));
313  }
314  color_space->Set2To4BitDepthMap(temp);
315  break;
316  case 0x21:
317  for (int i = 0; i < 4; i++) {
318  RCHECK(reader->ReadBits(8, &temp[i]));
319  }
320  color_space->Set2To8BitDepthMap(temp);
321  break;
322  case 0x22:
323  for (int i = 0; i < 16; i++) {
324  RCHECK(reader->ReadBits(8, &temp[i]));
325  }
326  color_space->Set4To8BitDepthMap(temp);
327  break;
328  case 0xf0:
329  image->NewRow(is_top_fields);
330  break;
331  default:
332  LOG(ERROR) << "Unsupported DVB-sub pixel data format: 0x" << std::hex
333  << static_cast<int>(data_type);
334  return false;
335  }
336  }
337  return true;
338 }
339 
340 bool DvbSubParser::Parse2BitPixelData(bool is_top_fields,
341  BitReader* reader,
342  DvbImageBuilder* image) {
343  // 2-bit/pixel code string, Section 7.2.5.2.1, Table 22.
344  while (true) {
345  uint8_t peek;
346  RCHECK(reader->ReadBits(2, &peek));
347  if (peek != 0) {
348  RCHECK(image->AddPixel(BitDepth::k2Bit, peek, is_top_fields));
349  } else {
350  uint8_t switch_1;
351  RCHECK(reader->ReadBits(1, &switch_1));
352  if (switch_1 == 1) {
353  uint8_t count_minus_3;
354  RCHECK(reader->ReadBits(3, &count_minus_3));
355  RCHECK(reader->ReadBits(2, &peek));
356  for (uint8_t i = 0; i < count_minus_3 + 3; i++)
357  RCHECK(image->AddPixel(BitDepth::k2Bit, peek, is_top_fields));
358  } else {
359  uint8_t switch_2;
360  RCHECK(reader->ReadBits(1, &switch_2));
361  if (switch_2 == 1) {
362  RCHECK(image->AddPixel(BitDepth::k2Bit, 0, is_top_fields));
363  } else {
364  uint8_t switch_3;
365  RCHECK(reader->ReadBits(2, &switch_3));
366  if (switch_3 == 0) {
367  break;
368  } else if (switch_3 == 1) {
369  RCHECK(image->AddPixel(BitDepth::k2Bit, 0, is_top_fields));
370  RCHECK(image->AddPixel(BitDepth::k2Bit, 0, is_top_fields));
371  } else if (switch_3 == 2) {
372  uint8_t count_minus_12;
373  RCHECK(reader->ReadBits(4, &count_minus_12));
374  RCHECK(reader->ReadBits(2, &peek));
375  for (uint8_t i = 0; i < count_minus_12 + 12; i++)
376  RCHECK(image->AddPixel(BitDepth::k2Bit, peek, is_top_fields));
377  } else if (switch_3 == 3) {
378  uint8_t count_minus_29;
379  RCHECK(reader->ReadBits(8, &count_minus_29));
380  RCHECK(reader->ReadBits(2, &peek));
381  for (uint8_t i = 0; i < count_minus_29 + 29; i++)
382  RCHECK(image->AddPixel(BitDepth::k2Bit, peek, is_top_fields));
383  }
384  }
385  }
386  }
387  }
388 
389  return true;
390 }
391 
392 bool DvbSubParser::Parse4BitPixelData(bool is_top_fields,
393  BitReader* reader,
394  DvbImageBuilder* image) {
395  // 4-bit/pixel code string, Section 7.2.5.2.2, Table 24.
396  DCHECK(reader->bits_available() % 8 == 0);
397  while (true) {
398  uint8_t peek;
399  RCHECK(reader->ReadBits(4, &peek));
400  if (peek != 0) {
401  RCHECK(image->AddPixel(BitDepth::k4Bit, peek, is_top_fields));
402  } else {
403  uint8_t switch_1;
404  RCHECK(reader->ReadBits(1, &switch_1));
405  if (switch_1 == 0) {
406  RCHECK(reader->ReadBits(3, &peek));
407  if (peek != 0) {
408  for (int i = 0; i < peek + 2; i++)
409  RCHECK(image->AddPixel(BitDepth::k4Bit, 0, is_top_fields));
410  } else {
411  break;
412  }
413  } else {
414  uint8_t switch_2;
415  RCHECK(reader->ReadBits(1, &switch_2));
416  if (switch_2 == 0) {
417  RCHECK(reader->ReadBits(2, &peek)); // run_length_4-7
418  uint8_t code;
419  RCHECK(reader->ReadBits(4, &code));
420  for (int i = 0; i < peek + 4; i++)
421  RCHECK(image->AddPixel(BitDepth::k4Bit, code, is_top_fields));
422  } else {
423  uint8_t switch_3;
424  RCHECK(reader->ReadBits(2, &switch_3));
425  if (switch_3 == 0) {
426  RCHECK(image->AddPixel(BitDepth::k4Bit, 0, is_top_fields));
427  } else if (switch_3 == 1) {
428  RCHECK(image->AddPixel(BitDepth::k4Bit, 0, is_top_fields));
429  RCHECK(image->AddPixel(BitDepth::k4Bit, 0, is_top_fields));
430  } else if (switch_3 == 2) {
431  RCHECK(reader->ReadBits(4, &peek)); // run_length_9-24
432  uint8_t code;
433  RCHECK(reader->ReadBits(4, &code));
434  for (int i = 0; i < peek + 9; i++)
435  RCHECK(image->AddPixel(BitDepth::k4Bit, code, is_top_fields));
436  } else {
437  // switch_3 == 3
438  RCHECK(reader->ReadBits(8, &peek)); // run_length_25-280
439  uint8_t code;
440  RCHECK(reader->ReadBits(4, &code));
441  for (int i = 0; i < peek + 25; i++)
442  RCHECK(image->AddPixel(BitDepth::k4Bit, code, is_top_fields));
443  }
444  }
445  }
446  }
447  }
448  return true;
449 }
450 
451 bool DvbSubParser::Parse8BitPixelData(bool is_top_fields,
452  BitReader* reader,
453  DvbImageBuilder* image) {
454  // 8-bit/pixel code string, Section 7.2.5.2.3, Table 26.
455  while (true) {
456  uint8_t peek;
457  RCHECK(reader->ReadBits(8, &peek));
458  if (peek != 0) {
459  RCHECK(image->AddPixel(BitDepth::k8Bit, peek, is_top_fields));
460  } else {
461  uint8_t switch_1;
462  RCHECK(reader->ReadBits(1, &switch_1));
463  if (switch_1 == 0) {
464  RCHECK(reader->ReadBits(7, &peek));
465  if (peek != 0) {
466  for (uint8_t i = 0; i < peek; i++)
467  RCHECK(image->AddPixel(BitDepth::k8Bit, 0, is_top_fields));
468  } else {
469  break;
470  }
471  } else {
472  uint8_t count;
473  RCHECK(reader->ReadBits(7, &count));
474  RCHECK(reader->ReadBits(8, &peek));
475  for (uint8_t i = 0; i < count; i++)
476  RCHECK(image->AddPixel(BitDepth::k8Bit, peek, is_top_fields));
477  }
478  }
479  }
480 
481  return true;
482 }
483 
484 } // namespace media
485 } // namespace shaka
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66