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