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