Shaka Packager SDK
Loading...
Searching...
No Matches
es_parser_dvb.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/mp2t/es_parser_dvb.h>
8
9#include <packager/media/base/bit_reader.h>
10#include <packager/media/base/text_stream_info.h>
11#include <packager/media/base/timestamp.h>
12#include <packager/media/formats/mp2t/mp2t_common.h>
13
14namespace shaka {
15namespace media {
16namespace mp2t {
17
18namespace {
19
20bool ParseSubtitlingDescriptor(
21 const uint8_t* descriptor,
22 size_t size,
23 std::unordered_map<uint16_t, std::string>* langs) {
24 // See ETSI EN 300 468 Section 6.2.41.
25 BitReader reader(descriptor, size);
26 size_t data_size;
27 RCHECK(reader.SkipBits(8)); // descriptor_tag
28 RCHECK(reader.ReadBits(8, &data_size));
29 RCHECK(data_size + 2 <= size);
30 for (size_t i = 0; i < data_size; i += 8) {
31 uint32_t lang_code;
32 uint16_t page;
33 RCHECK(reader.ReadBits(24, &lang_code));
34 RCHECK(reader.SkipBits(8)); // subtitling_type
35 RCHECK(reader.ReadBits(16, &page));
36 RCHECK(reader.SkipBits(16)); // ancillary_page_id
37
38 // The lang code is a ISO 639-2 code coded in Latin-1.
39 std::string lang(3, '\0');
40 lang[0] = (lang_code >> 16) & 0xff;
41 lang[1] = (lang_code >> 8) & 0xff;
42 lang[2] = (lang_code >> 0) & 0xff;
43 langs->emplace(page, std::move(lang));
44 }
45 return true;
46}
47
48} // namespace
49
50EsParserDvb::EsParserDvb(uint32_t pid,
51 const NewStreamInfoCB& new_stream_info_cb,
52 const EmitTextSampleCB& emit_sample_cb,
53 const uint8_t* descriptor,
54 size_t descriptor_length)
55 : EsParser(pid),
56 new_stream_info_cb_(new_stream_info_cb),
57 emit_sample_cb_(emit_sample_cb) {
58 if (!ParseSubtitlingDescriptor(descriptor, descriptor_length, &languages_)) {
59 LOG(WARNING) << "Error parsing subtitling descriptor";
60 }
61}
62
63EsParserDvb::~EsParserDvb() {}
64
65bool EsParserDvb::Parse(const uint8_t* buf,
66 int size,
67 int64_t pts,
68 int64_t dts) {
69 if (!sent_info_) {
70 sent_info_ = true;
71 std::shared_ptr<TextStreamInfo> info = std::make_shared<TextStreamInfo>(
72 pid(), kMpeg2Timescale, kInfiniteDuration, kCodecText,
73 /* codec_string= */ "", /* codec_config= */ "", /* width= */ 0,
74 /* height= */ 0, /* language= */ "");
75 for (const auto& pair : languages_) {
76 info->AddSubStream(pair.first, {pair.second});
77 }
78
79 new_stream_info_cb_(info);
80 }
81
82 // TODO: Handle buffering and multiple reads? All content so far has been
83 // a whole segment, so it may not be needed.
84 return ParseInternal(buf, size, pts);
85}
86
87bool EsParserDvb::Flush() {
88 for (auto& pair : parsers_) {
89 std::vector<std::shared_ptr<TextSample>> samples;
90 RCHECK(pair.second.Flush(&samples));
91
92 for (auto sample : samples) {
93 sample->set_sub_stream_index(pair.first);
94 emit_sample_cb_(sample);
95 }
96 }
97 return true;
98}
99
100void EsParserDvb::Reset() {
101 parsers_.clear();
102}
103
104bool EsParserDvb::ParseInternal(const uint8_t* data, size_t size, int64_t pts) {
105 // See EN 300 743 Table 3.
106 BitReader reader(data, size);
107 int data_identifier;
108 int subtitle_stream_id;
109 RCHECK(reader.ReadBits(8, &data_identifier));
110 RCHECK(reader.ReadBits(8, &subtitle_stream_id));
111 RCHECK(data_identifier == 0x20);
112 RCHECK(subtitle_stream_id == 0);
113
114 int temp;
115 while (reader.ReadBits(8, &temp) && temp == 0xf) {
116 DvbSubSegmentType segment_type;
117 uint16_t page_id;
118 size_t segment_length;
119 RCHECK(reader.ReadBits(8, &segment_type));
120 RCHECK(reader.ReadBits(16, &page_id));
121 RCHECK(reader.ReadBits(16, &segment_length));
122 RCHECK(reader.bits_available() > segment_length * 8);
123
124 const uint8_t* payload = data + (size - reader.bits_available() / 8);
125 std::vector<std::shared_ptr<TextSample>> samples;
126 RCHECK(parsers_[page_id].Parse(segment_type, pts, payload, segment_length,
127 &samples));
128 for (auto sample : samples) {
129 sample->set_sub_stream_index(page_id);
130 emit_sample_cb_(sample);
131 }
132
133 RCHECK(reader.SkipBytes(segment_length));
134 }
135 return temp == 0xff;
136}
137
138} // namespace mp2t
139} // namespace media
140} // namespace shaka
All the methods that are virtual are virtual for mocking.