1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | **********/ |
16 | // "liveMedia" |
17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
18 | // A parser for a MPEG Transport Stream |
19 | // Implementation |
20 | |
21 | #include "MPEG2TransportStreamParser.hh" |
22 | |
23 | #define NUM_PIDS 0x10000 |
24 | |
25 | StreamType StreamTypes[0x100]; |
26 | |
27 | MPEG2TransportStreamParser |
28 | ::MPEG2TransportStreamParser(FramedSource* inputSource, |
29 | FramedSource::onCloseFunc* onEndFunc, void* onEndClientData) |
30 | : StreamParser(inputSource, onEndFunc, onEndClientData, continueParsing, this), |
31 | fInputSource(inputSource), fAmCurrentlyParsing(False), |
32 | fOnEndFunc(onEndFunc), fOnEndClientData(onEndClientData), |
33 | fLastSeenPCR(0.0) { |
34 | if (StreamTypes[0x01].dataType == StreamType::UNKNOWN) { // initialize array with known values |
35 | StreamTypes[0x01] = StreamType("MPEG-1 video" , StreamType::VIDEO, ".mpv" ); |
36 | StreamTypes[0x02] = StreamType("MPEG-2 video" , StreamType::VIDEO, ".mpv" ); |
37 | StreamTypes[0x03] = StreamType("MPEG-1 audio" , StreamType::AUDIO, ".mpa" ); |
38 | StreamTypes[0x04] = StreamType("MPEG-2 audio" , StreamType::AUDIO, ".mpa" ); |
39 | StreamTypes[0x05] = StreamType("privately-defined data" , StreamType::DATA); |
40 | StreamTypes[0x06] = StreamType("privately-defined data" , StreamType::DATA); |
41 | StreamTypes[0x0F] = StreamType("AAC audio" , StreamType::AUDIO, ".aac" ); |
42 | StreamTypes[0x10] = StreamType("MPEG-4 H.263 based video" , StreamType::VIDEO, ".mpv" ); |
43 | StreamTypes[0x1B] = StreamType("H.264 video" , StreamType::VIDEO, ".h264" ); |
44 | StreamTypes[0x1C] = StreamType("MPEG-4 raw audio" , StreamType::AUDIO, ".mpa" ); |
45 | StreamTypes[0x1D] = StreamType("MPEG-4 text" , StreamType::TEXT, ".txt" ); |
46 | StreamTypes[0x21] = StreamType("JPEG 2000 video" , StreamType::VIDEO, ".mjpg" ); |
47 | StreamTypes[0x24] = StreamType("H.265 video" , StreamType::VIDEO, ".h265" ); |
48 | StreamTypes[0x81] = StreamType("AC-3 audio" , StreamType::AUDIO, ".ac3" ); |
49 | } |
50 | |
51 | // Create our 'PID state' array: |
52 | fPIDState = new PIDState*[NUM_PIDS]; |
53 | for (unsigned i = 0; i < NUM_PIDS; ++i) fPIDState[i] = NULL; |
54 | |
55 | // Initially, the only PID we know is 0x0000: a Program Association Table: |
56 | fPIDState[0x0000] = new PIDState_PAT(*this, 0x0000); |
57 | |
58 | // Begin parsing: |
59 | continueParsing(); |
60 | } |
61 | |
62 | MPEG2TransportStreamParser::~MPEG2TransportStreamParser() { |
63 | for (unsigned i = 0; i < NUM_PIDS; ++i) delete fPIDState[i]; |
64 | delete[] fPIDState; |
65 | } |
66 | |
67 | UsageEnvironment& MPEG2TransportStreamParser::envir() { |
68 | return fInputSource->envir(); |
69 | } |
70 | |
71 | void MPEG2TransportStreamParser |
72 | ::continueParsing(void* clientData, unsigned char* ptr, unsigned size, struct timeval presentationTime) { |
73 | ((MPEG2TransportStreamParser*)clientData)->continueParsing(); |
74 | } |
75 | |
76 | void MPEG2TransportStreamParser::continueParsing() { |
77 | if (fAmCurrentlyParsing) return; // don't allow recursive calls to parse() |
78 | |
79 | if (fInputSource != NULL) { |
80 | fAmCurrentlyParsing = True; |
81 | Boolean parseSucceeded = parse(); |
82 | fAmCurrentlyParsing = False; |
83 | |
84 | if (!parseSucceeded) { |
85 | // We didn't complete the parsing, because we had to read more data from the source, |
86 | // or because we're waiting for another read from downstream. |
87 | // Once that happens, we'll get called again. |
88 | return; |
89 | } |
90 | } |
91 | |
92 | // We successfully parsed the file. Call our 'done' function now: |
93 | if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData); |
94 | } |
95 | |
96 | #define TRANSPORT_SYNC_BYTE 0x47 |
97 | #define TRANSPORT_PACKET_SIZE 188 |
98 | |
99 | Boolean MPEG2TransportStreamParser::parse() { |
100 | if (fInputSource->isCurrentlyAwaitingData()) return False; |
101 | // Our input source is currently being read. Wait until that read completes |
102 | |
103 | try { |
104 | while (1) { |
105 | // Make sure we start with a 'sync byte': |
106 | do { |
107 | saveParserState(); |
108 | } while (get1Byte() != TRANSPORT_SYNC_BYTE); |
109 | |
110 | // Parse and process each (remaining 187 bytes of a) 'Transport Stream Packet' at a time. |
111 | // (Because these are a lot smaller than the "StreamParser" BANK_SIZE, we don't save |
112 | // parser state in the middle of processing each such 'Transport Stream Packet'. |
113 | // Therefore, processing of each 'Transport Stream Packet' needs to be idempotent.) |
114 | |
115 | u_int16_t flagsPlusPID = get2Bytes(); |
116 | // Check the "transport_error_indicator" flag; reject the packet if it's set: |
117 | if ((flagsPlusPID&0x8000) != 0) { |
118 | #ifdef DEBUG_ERRORS |
119 | fprintf(stderr, "MPEG2TransportStreamParser::parse() Rejected packet with \"transport_error_indicator\" flag set!\n" ); |
120 | #endif |
121 | continue; |
122 | } |
123 | Boolean pusi = (flagsPlusPID&0x4000) != 0; // payload_unit_start_indicator |
124 | // Ignore "transport_priority" |
125 | u_int16_t PID = flagsPlusPID&0x1FFF; |
126 | #ifdef DEBUG_CONTENTS |
127 | fprintf(stderr, "\nTransport Packet: payload_unit_start_indicator: %d; PID: 0x%04x\n" , |
128 | pusi, PID); |
129 | #endif |
130 | |
131 | u_int8_t controlPlusContinuity_counter = get1Byte(); |
132 | // Reject any packets where the "transport_scrambling_control" field is not zero: |
133 | if ((controlPlusContinuity_counter&0xC0) != 0) { |
134 | #ifdef DEBUG_ERRORS |
135 | fprintf(stderr, "MPEG2TransportStreamParser::parse() Rejected packet with \"transport_scrambling_control\" set to non-zero value %d!\n" , (controlPlusContinuity_counter&0xC0)>>6); |
136 | #endif |
137 | continue; |
138 | } |
139 | u_int8_t adaptation_field_control = (controlPlusContinuity_counter&0x30)>>4; // 2 bits |
140 | #ifdef DEBUG_CONTENTS |
141 | u_int8_t continuity_counter = (controlPlusContinuity_counter&0x0F); // 4 bits |
142 | fprintf(stderr, "adaptation_field_control: %d; continuity_counter: 0x%X\n" , adaptation_field_control, continuity_counter); |
143 | #endif |
144 | |
145 | u_int8_t totalAdaptationFieldSize = adaptation_field_control < 2 ? 0 : parseAdaptationField(); |
146 | #ifdef DEBUG_ERRORS |
147 | if (adaptation_field_control == 2 && totalAdaptationFieldSize != 1+183) { |
148 | fprintf(stderr, "MPEG2TransportStreamParser::parse() Warning: Got an inconsistent \"totalAdaptationFieldSize\" %d for adaptation_field_control == 2\n" , totalAdaptationFieldSize); |
149 | } |
150 | #endif |
151 | |
152 | int numDataBytes = TRANSPORT_PACKET_SIZE-4-totalAdaptationFieldSize; |
153 | if (numDataBytes > 0) { |
154 | #ifdef DEBUG_CONTENTS |
155 | fprintf(stderr, "+%d data bytes:\n" , numDataBytes); |
156 | #endif |
157 | if (!processDataBytes(PID, pusi, numDataBytes)) { |
158 | // The parsing got deferred (to be resumed later when a pending read happens) |
159 | restoreSavedParserState(); // so that we later resume parsing at the start of the packet |
160 | return False; |
161 | } |
162 | } |
163 | } |
164 | } catch (int /*e*/) { |
165 | #ifdef DEBUG_CONTENTS |
166 | fprintf(stderr, "MPEG2TransportStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n" ); |
167 | #endif |
168 | return False; // the parsing got interrupted |
169 | } |
170 | } |
171 | |
172 | u_int8_t MPEG2TransportStreamParser::parseAdaptationField() { |
173 | unsigned startPos = curOffset(); |
174 | #ifdef DEBUG_CONTENTS |
175 | fprintf(stderr, "\tAdaptation Field:\n" ); |
176 | #endif |
177 | u_int8_t adaptation_field_length = get1Byte(); |
178 | #ifdef DEBUG_CONTENTS |
179 | fprintf(stderr, "\t\tadaptation_field_length: %d\n" , adaptation_field_length); |
180 | #endif |
181 | if (adaptation_field_length > 0) { |
182 | u_int8_t flags = get1Byte(); |
183 | #ifdef DEBUG_CONTENTS |
184 | fprintf(stderr, "\t\tadaptation field flags: 0x%02x\n" , flags); |
185 | #endif |
186 | if ((flags&0x10) != 0) { // PCR_flag |
187 | u_int32_t first32PCRBits = get4Bytes(); |
188 | u_int16_t last16PCRBits = get2Bytes(); |
189 | // program_clock_reference_base = "first32PCRBits" and high bit of "last16PCRBits" (33 bits) |
190 | // program_clock_reference_extension = last 9 bits of "last16PCRBits" (9 bits) |
191 | double PCR = first32PCRBits/45000.0; |
192 | if ((last16PCRBits&0x8000) != 0) PCR += 1/90000.0; // add in low-bit (if set) |
193 | PCR += (last16PCRBits&0x01FF)/27000000.0; // add in extension |
194 | #ifdef DEBUG_CONTENTS |
195 | fprintf(stderr, "\t\tPCR: %.10f\n" , PCR); |
196 | #endif |
197 | } |
198 | if ((flags&0x08) != 0) { // OPCR_flag |
199 | u_int32_t first32OPCRBits = get4Bytes(); |
200 | u_int16_t last16OPCRBits = get2Bytes(); |
201 | // original_program_clock_reference_base = "first32OPCRBits" and high bit of "last16OPCRBits" (33 bits) |
202 | // original_program_clock_reference_extension = last 9 bits of "last16OPCRBits" (9 bits) |
203 | double OPCR = first32OPCRBits/45000.0; |
204 | if ((last16OPCRBits&0x8000) != 0) OPCR += 1/90000.0; // add in low-bit (if set) |
205 | OPCR += (last16OPCRBits&0x01FF)/27000000.0; // add in extension |
206 | #ifdef DEBUG_CONTENTS |
207 | fprintf(stderr, "\t\tOPCR: %.10f\n" , OPCR); |
208 | #endif |
209 | } |
210 | if ((flags&0x04) != 0) { // splicing_point_flag |
211 | skipBytes(1); // splice_countdown |
212 | } |
213 | if ((flags&0x02) != 0) { // transport_private_data_flag |
214 | u_int8_t transport_private_data_length = get1Byte(); |
215 | #ifdef DEBUG_CONTENTS |
216 | fprintf(stderr, "\t\ttransport_private_data_length: %d\n" , transport_private_data_length); |
217 | #endif |
218 | skipBytes(transport_private_data_length); // "private_data_byte"s |
219 | } |
220 | if ((flags&0x01) != 0) { // adaptation_field_extension_flag |
221 | #ifdef DEBUG_CONTENTS |
222 | u_int8_t adaptation_field_extension_length = get1Byte(); |
223 | fprintf(stderr, "\t\tadaptation_field_extension_length: %d\n" , adaptation_field_extension_length); |
224 | #else |
225 | skipBytes(1); // adaptation_field_extension_length |
226 | #endif |
227 | u_int8_t flagsPlusReserved = get1Byte(); |
228 | #ifdef DEBUG_CONTENTS |
229 | fprintf(stderr, "\t\t\tflagsPlusReserved: 0x%02x\n" , flagsPlusReserved); |
230 | #endif |
231 | if ((flagsPlusReserved&0x80) != 0) { // ltw_flag |
232 | skipBytes(2); // "ltw_valid_flag" + "ltw_offset" |
233 | } |
234 | if ((flagsPlusReserved&0x40) != 0) { // piecewise_rate_flag |
235 | skipBytes(3); // reserved + "piecewise_rate" |
236 | } |
237 | if ((flagsPlusReserved&0x20) != 0) { // seamless_splice_flag |
238 | skipBytes(5); // DTS_next_... |
239 | } |
240 | // Skip reserved bytes to the end of the adaptation_field: |
241 | int numBytesLeft = (1 + adaptation_field_length) - (curOffset() - startPos); |
242 | if (numBytesLeft > 0) { |
243 | #ifdef DEBUG_CONTENTS |
244 | fprintf(stderr, "\t\t+%d reserved bytes\n" , numBytesLeft); |
245 | #endif |
246 | skipBytes(numBytesLeft); |
247 | } |
248 | } |
249 | // Skip "stuffing_byte"s to the end of the adaptation_field: |
250 | int numBytesLeft = (1 + adaptation_field_length) - (curOffset() - startPos); |
251 | if (numBytesLeft > 0) { |
252 | #ifdef DEBUG_CONTENTS |
253 | fprintf(stderr, "\t\t+%d stuffing bytes\n" , numBytesLeft); |
254 | #endif |
255 | #ifdef DEBUG_ERRORS |
256 | for (int i = 0; i < numBytesLeft; ++i) { |
257 | if (get1Byte() != 0xFF) { |
258 | fprintf(stderr, "WARNING: non-stuffing byte in adaptation_field\n" ); |
259 | } |
260 | } |
261 | #else |
262 | skipBytes(numBytesLeft); |
263 | #endif |
264 | } |
265 | } |
266 | |
267 | // Finally, figure out how many bytes we parsed, and compare it to what we expected: |
268 | unsigned totalAdaptationFieldSize = curOffset() - startPos; |
269 | #ifdef DEBUG_ERRORS |
270 | if (totalAdaptationFieldSize != 1 + adaptation_field_length) { |
271 | fprintf(stderr, "MPEG2TransportStreamParser::parseAdaptationField() Warning: Got an inconsistent \"totalAdaptationFieldSize\" %d; expected %d\n" , totalAdaptationFieldSize, 1 + adaptation_field_length); |
272 | } |
273 | #endif |
274 | return totalAdaptationFieldSize; |
275 | } |
276 | |
277 | Boolean MPEG2TransportStreamParser |
278 | ::processDataBytes(u_int16_t PID, Boolean pusi, unsigned numDataBytes) { |
279 | PIDState* pidState = fPIDState[PID]; |
280 | |
281 | if (pidState == NULL) { // unknown PID |
282 | #ifdef DEBUG_CONTENTS |
283 | fprintf(stderr, "\tUnknown PID\n" ); |
284 | #endif |
285 | skipBytes(numDataBytes); |
286 | return True; |
287 | } |
288 | |
289 | switch (pidState->type) { |
290 | case PAT: { |
291 | parsePAT(pusi, numDataBytes); |
292 | return True; |
293 | } |
294 | case PMT: { |
295 | parsePMT((PIDState_PMT*)pidState, pusi, numDataBytes); |
296 | return True; |
297 | } |
298 | case STREAM: { |
299 | return processStreamPacket((PIDState_STREAM*)pidState, pusi, numDataBytes); |
300 | } |
301 | default: { // Never reached, but eliminates a possible error with dumb compilers |
302 | return False; |
303 | } |
304 | } |
305 | } |
306 | |
307 | void MPEG2TransportStreamParser::restoreSavedParserState() { |
308 | StreamParser::restoreSavedParserState(); |
309 | fAmCurrentlyParsing = False; |
310 | } |
311 | |
312 | |
313 | //########## PIDState implementation ########## |
314 | |
315 | PIDState::PIDState(MPEG2TransportStreamParser& parser, u_int16_t pid, PIDType pidType) |
316 | : ourParser(parser), PID(pid), type(pidType) { |
317 | } |
318 | |
319 | PIDState::~PIDState() { |
320 | } |
321 | |
322 | |
323 | //######### StreamType implementation ######## |
324 | |
325 | StreamType |
326 | ::StreamType(char const* description, enum dataType dataType, char const* filenameSuffix) |
327 | : description(description), dataType(dataType), filenameSuffix(filenameSuffix) { |
328 | } |
329 | |