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