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
11#include <absl/log/check.h>
12#include <absl/log/log.h>
13
14#include <packager/media/formats/mp2t/mp2t_common.h>
15
16namespace shaka {
17namespace media {
18
19namespace {
20
21RgbaColor 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
45DvbSubParser::DvbSubParser() : last_pts_(0), timeout_(0) {}
46
47DvbSubParser::~DvbSubParser() {}
48
49bool 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
76bool 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
83const DvbImageColorSpace* DvbSubParser::GetColorSpace(uint8_t clut_id) {
84 return composer_.GetColorSpace(clut_id);
85}
86
87const DvbImageBuilder* DvbSubParser::GetImageForObject(uint16_t object_id) {
88 return composer_.GetObjectImage(object_id);
89}
90
91bool 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
126bool 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
174bool 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
227bool 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
271bool 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
287bool 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
340bool 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
392bool 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
451bool 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.