Shaka Packager SDK
Loading...
Searching...
No Matches
ts_packet.cc
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <packager/media/formats/mp2t/ts_packet.h>
6
7#include <cstddef>
8#include <cstdint>
9#include <ios>
10#include <memory>
11
12#include <absl/log/check.h>
13#include <absl/log/log.h>
14
15#include <packager/media/base/bit_reader.h>
16#include <packager/media/formats/mp2t/mp2t_common.h>
17
18namespace shaka {
19namespace media {
20namespace mp2t {
21
22static const uint8_t kTsHeaderSyncword = 0x47;
23
24// static
25int TsPacket::Sync(const uint8_t* buf, int size) {
26 int k = 0;
27 for (; k < size; k++) {
28 // Verify that we have 4 syncwords in a row when possible,
29 // this should improve synchronization robustness.
30 bool is_header = true;
31 for (int i = 0; i < 4; i++) {
32 int idx = k + i * kPacketSize;
33 if (idx >= size)
34 break;
35 if (buf[idx] != kTsHeaderSyncword) {
36 DVLOG(LOG_LEVEL_TS) << "ByteSync" << idx << ": " << std::hex
37 << static_cast<int>(buf[idx]) << std::dec;
38 is_header = false;
39 break;
40 }
41 }
42 if (is_header)
43 break;
44 }
45
46 if (k != 0) {
47 DVLOG(1) << "SYNC: nbytes_skipped=" << k;
48 }
49 return k;
50}
51
52// static
53TsPacket* TsPacket::Parse(const uint8_t* buf, int size) {
54 if (size < kPacketSize) {
55 DVLOG(1) << "Buffer does not hold one full TS packet:"
56 << " buffer_size=" << size;
57 return NULL;
58 }
59
60 DCHECK_EQ(buf[0], kTsHeaderSyncword);
61 if (buf[0] != kTsHeaderSyncword) {
62 DVLOG(1) << "Not on a TS syncword:"
63 << " buf[0]=" << std::hex << static_cast<int>(buf[0]) << std::dec;
64 return NULL;
65 }
66
67 std::unique_ptr<TsPacket> ts_packet(new TsPacket());
68 bool status = ts_packet->ParseHeader(buf);
69 if (!status) {
70 DVLOG(1) << "Parsing header failed";
71 return NULL;
72 }
73 return ts_packet.release();
74}
75
76TsPacket::TsPacket() {}
77
78TsPacket::~TsPacket() {}
79
80bool TsPacket::ParseHeader(const uint8_t* buf) {
81 BitReader bit_reader(buf, kPacketSize);
82 payload_ = buf;
83 payload_size_ = kPacketSize;
84
85 // Read the TS header: 4 bytes.
86 int syncword;
87 int transport_error_indicator;
88 int payload_unit_start_indicator;
89 int transport_priority;
90 int transport_scrambling_control;
91 int adaptation_field_control;
92 RCHECK(bit_reader.ReadBits(8, &syncword));
93 RCHECK(bit_reader.ReadBits(1, &transport_error_indicator));
94 RCHECK(bit_reader.ReadBits(1, &payload_unit_start_indicator));
95 RCHECK(bit_reader.ReadBits(1, &transport_priority));
96 RCHECK(bit_reader.ReadBits(13, &pid_));
97 RCHECK(bit_reader.ReadBits(2, &transport_scrambling_control));
98 RCHECK(bit_reader.ReadBits(2, &adaptation_field_control));
99 RCHECK(bit_reader.ReadBits(4, &continuity_counter_));
100 payload_unit_start_indicator_ = (payload_unit_start_indicator != 0);
101 payload_ += 4;
102 payload_size_ -= 4;
103
104 // Default values when no adaptation field.
105 discontinuity_indicator_ = false;
106 random_access_indicator_ = false;
107
108 // Done since no adaptation field.
109 if ((adaptation_field_control & 0x2) == 0)
110 return true;
111
112 // Read the adaptation field if needed.
113 int adaptation_field_length;
114 RCHECK(bit_reader.ReadBits(8, &adaptation_field_length));
115 DVLOG(LOG_LEVEL_TS) << "adaptation_field_length=" << adaptation_field_length;
116 payload_ += 1;
117 payload_size_ -= 1;
118 if ((adaptation_field_control & 0x1) == 0 && adaptation_field_length != 183) {
119 DVLOG(1) << "adaptation_field_length=" << adaptation_field_length;
120 return false;
121 }
122 if ((adaptation_field_control & 0x1) == 1 && adaptation_field_length > 182) {
123 DVLOG(1) << "adaptation_field_length=" << adaptation_field_length;
124 // This is not allowed by the spec.
125 // However, some badly encoded streams are using
126 // adaptation_field_length = 183
127 return false;
128 }
129
130 // adaptation_field_length = '0' is used to insert a single stuffing byte
131 // in the adaptation field of a transport stream packet.
132 if (adaptation_field_length == 0)
133 return true;
134
135 bool status = ParseAdaptationField(&bit_reader, adaptation_field_length);
136 payload_ += adaptation_field_length;
137 payload_size_ -= adaptation_field_length;
138 return status;
139}
140
141bool TsPacket::ParseAdaptationField(BitReader* bit_reader,
142 int adaptation_field_length) {
143 DCHECK_GT(adaptation_field_length, 0);
144 int adaptation_field_start_marker =
145 static_cast<int>(bit_reader->bits_available()) / 8;
146
147 int discontinuity_indicator;
148 int random_access_indicator;
149 int elementary_stream_priority_indicator;
150 int pcr_flag;
151 int opcr_flag;
152 int splicing_point_flag;
153 int transport_private_data_flag;
154 int adaptation_field_extension_flag;
155 RCHECK(bit_reader->ReadBits(1, &discontinuity_indicator));
156 RCHECK(bit_reader->ReadBits(1, &random_access_indicator));
157 RCHECK(bit_reader->ReadBits(1, &elementary_stream_priority_indicator));
158 RCHECK(bit_reader->ReadBits(1, &pcr_flag));
159 RCHECK(bit_reader->ReadBits(1, &opcr_flag));
160 RCHECK(bit_reader->ReadBits(1, &splicing_point_flag));
161 RCHECK(bit_reader->ReadBits(1, &transport_private_data_flag));
162 RCHECK(bit_reader->ReadBits(1, &adaptation_field_extension_flag));
163 discontinuity_indicator_ = (discontinuity_indicator != 0);
164 random_access_indicator_ = (random_access_indicator != 0);
165
166 if (pcr_flag) {
167 int64_t program_clock_reference_base;
168 int reserved;
169 int program_clock_reference_extension;
170 RCHECK(bit_reader->ReadBits(33, &program_clock_reference_base));
171 RCHECK(bit_reader->ReadBits(6, &reserved));
172 RCHECK(bit_reader->ReadBits(9, &program_clock_reference_extension));
173 }
174
175 if (opcr_flag) {
176 int64_t original_program_clock_reference_base;
177 int reserved;
178 int original_program_clock_reference_extension;
179 RCHECK(bit_reader->ReadBits(33, &original_program_clock_reference_base));
180 RCHECK(bit_reader->ReadBits(6, &reserved));
181 RCHECK(
182 bit_reader->ReadBits(9, &original_program_clock_reference_extension));
183 }
184
185 if (splicing_point_flag) {
186 int splice_countdown;
187 RCHECK(bit_reader->ReadBits(8, &splice_countdown));
188 }
189
190 if (transport_private_data_flag) {
191 int transport_private_data_length;
192 RCHECK(bit_reader->ReadBits(8, &transport_private_data_length));
193 RCHECK(bit_reader->SkipBits(8 * transport_private_data_length));
194 }
195
196 if (adaptation_field_extension_flag) {
197 int adaptation_field_extension_length;
198 RCHECK(bit_reader->ReadBits(8, &adaptation_field_extension_length));
199 RCHECK(bit_reader->SkipBits(8 * adaptation_field_extension_length));
200 }
201
202 // The rest of the adaptation field should be stuffing bytes.
203 int adaptation_field_remaining_size =
204 adaptation_field_length -
205 (adaptation_field_start_marker -
206 static_cast<int>(bit_reader->bits_available()) / 8);
207 RCHECK(adaptation_field_remaining_size >= 0);
208 for (int k = 0; k < adaptation_field_remaining_size; k++) {
209 int stuffing_byte;
210 RCHECK(bit_reader->ReadBits(8, &stuffing_byte));
211 RCHECK(stuffing_byte == 0xff);
212 }
213
214 DVLOG(LOG_LEVEL_TS) << "random_access_indicator=" << random_access_indicator_;
215 return true;
216}
217
218} // namespace mp2t
219} // namespace media
220} // namespace shaka
All the methods that are virtual are virtual for mocking.