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 | #include "FileSink.hh" |
23 | #include <time.h> // for time_t |
24 | |
25 | Boolean MPEG2TransportStreamParser |
26 | ::processStreamPacket(PIDState_STREAM* pidState, Boolean pusi, unsigned numDataBytes) { |
27 | #ifdef DEBUG_CONTENTS |
28 | extern StreamType StreamTypes[]; |
29 | fprintf(stderr, "\t%s stream (stream_type 0x%02x)\n" , |
30 | StreamTypes[pidState->stream_type].description, pidState->stream_type); |
31 | #endif |
32 | do { |
33 | MPEG2TransportStreamDemuxedTrack* streamSource = pidState->streamSource; |
34 | if (streamSource == NULL) { |
35 | // There's no source for this track; just skip the data: |
36 | skipBytes(numDataBytes); |
37 | break; |
38 | } |
39 | |
40 | if (!streamSource->isCurrentlyAwaitingData()) { |
41 | // Wait until the source next gets read from. (The parsing will continue then.) |
42 | return False; |
43 | } |
44 | |
45 | // If the data begins with a PES header, parse it first |
46 | unsigned = 0; |
47 | if (pusi && pidState->stream_type != 0x05/*these special private streams don't have PES hdrs*/) { |
48 | pesHeaderSize = parsePESHeader(pidState, numDataBytes); |
49 | if (pesHeaderSize == 0) break; // PES header parsing failed |
50 | } |
51 | |
52 | // Deliver the data: |
53 | unsigned numBytesToDeliver = numDataBytes - pesHeaderSize; |
54 | if (numBytesToDeliver > streamSource->maxSize()) { |
55 | streamSource->frameSize() = streamSource->maxSize(); |
56 | streamSource->numTruncatedBytes() = numBytesToDeliver - streamSource->maxSize(); |
57 | } else { |
58 | streamSource->frameSize() = numBytesToDeliver; |
59 | streamSource->numTruncatedBytes() = 0; |
60 | } |
61 | getBytes(streamSource->to(), streamSource->frameSize()); |
62 | skipBytes(streamSource->numTruncatedBytes()); |
63 | |
64 | double pts = pidState->lastSeenPTS == 0.0 ? fLastSeenPCR : pidState->lastSeenPTS; |
65 | streamSource->presentationTime().tv_sec = (time_t)pts; |
66 | streamSource->presentationTime().tv_usec = int(pts*1000000.0)%1000000; |
67 | |
68 | FramedSource::afterGetting(streamSource); // completes delivery |
69 | } while (0); |
70 | |
71 | return True; |
72 | } |
73 | |
74 | static Boolean isSpecialStreamId[0x100]; |
75 | |
76 | unsigned MPEG2TransportStreamParser |
77 | ::(PIDState_STREAM* pidState, unsigned numDataBytes) { |
78 | static Boolean haveInitializedIsSpecialStreamId = False; |
79 | if (!haveInitializedIsSpecialStreamId) { |
80 | for (unsigned i = 0; i < 0x100; ++i) isSpecialStreamId[i] = False; |
81 | isSpecialStreamId[0xBC] = True; // program_stream_map |
82 | isSpecialStreamId[0xBE] = True; // padding_stream |
83 | isSpecialStreamId[0xBF] = True; // private_stream_2 |
84 | isSpecialStreamId[0xF0] = True; // ECM_stream |
85 | isSpecialStreamId[0xF1] = True; // EMM_stream |
86 | isSpecialStreamId[0xF2] = True; // DSMCC_stream |
87 | isSpecialStreamId[0xF8] = True; // ITU-T Rec. H.222.1 type E |
88 | isSpecialStreamId[0xFF] = True; // program_stream_directory |
89 | |
90 | haveInitializedIsSpecialStreamId = True; // from now on |
91 | } |
92 | |
93 | #ifdef DEBUG_CONTENTS |
94 | fprintf(stderr, "\t\tPES Header:\n" ); |
95 | #endif |
96 | unsigned startPos = curOffset(); |
97 | |
98 | do { |
99 | u_int32_t startCodePlusStreamId = get4Bytes(); |
100 | if ((startCodePlusStreamId&0xFFFFFF00) != 0x00000100) { |
101 | #ifdef DEBUG_ERRORS |
102 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Bad start code: 0x%06x\n" , |
103 | pidState->PID, numDataBytes, startCodePlusStreamId>>8); |
104 | #endif |
105 | break; |
106 | } |
107 | u_int8_t stream_id = startCodePlusStreamId&0xFF; |
108 | |
109 | #ifdef DEBUG_CONTENTS |
110 | fprintf(stderr, "\t\t\tstream_id: 0x%02x; PES_packet_length: %d\n" , |
111 | stream_id, get2Bytes()); |
112 | #else |
113 | skipBytes(2); |
114 | #endif |
115 | |
116 | if (!isSpecialStreamId[stream_id]) { |
117 | u_int16_t flags = get2Bytes(); |
118 | if ((flags&0xC000) != 0x8000) { |
119 | #ifdef DEBUG_ERRORS |
120 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Bad flags: 0x%04x\n" , |
121 | pidState->PID, numDataBytes, flags); |
122 | #endif |
123 | break; |
124 | } |
125 | u_int8_t PTS_DTS_flags = (flags&0x00C0)>>6; |
126 | Boolean ESCR_flag = (flags&0x0020) != 0; |
127 | Boolean ES_rate_flag = (flags&0x0010) != 0; |
128 | Boolean DSM_trick_mode_flag = (flags&0x0008) != 0; |
129 | Boolean additional_copy_info_flag = (flags&0x0004) != 0; |
130 | Boolean PES_CRC_flag = (flags&0x0002) != 0; |
131 | Boolean PES_extension_flag = (flags&0x0001) != 0; |
132 | #ifdef DEBUG_CONTENTS |
133 | fprintf(stderr, "\t\t\tflags: 0x%04x (PTS_DTS:%d; ESCR:%d; ES_rate:%d; DSM_trick_mode:%d; additional_copy_info:%d; PES_CRC:%d; PES_extension:%d)\n" , |
134 | flags, PTS_DTS_flags, ESCR_flag, ES_rate_flag, DSM_trick_mode_flag, additional_copy_info_flag, PES_CRC_flag, PES_extension_flag); |
135 | #endif |
136 | |
137 | u_int8_t = get1Byte(); |
138 | #ifdef DEBUG_CONTENTS |
139 | fprintf(stderr, "\t\t\tPES_header_data_length: %d\n" , PES_header_data_length); |
140 | #endif |
141 | |
142 | if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { |
143 | // Begin with a PTS: |
144 | u_int8_t first8PTSBits = get1Byte(); |
145 | u_int32_t last32PTSBits = get4Bytes(); |
146 | if ((first8PTSBits&0xF1) != ((PTS_DTS_flags<<4)|0x01) || |
147 | (last32PTSBits&0x00010001) != 0x00010001) { |
148 | #ifdef DEBUG_ERRORS |
149 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Bad PTS bits: 0x%02x,0x%08x\n" , |
150 | pidState->PID, numDataBytes, first8PTSBits, last32PTSBits); |
151 | #endif |
152 | break; |
153 | } |
154 | u_int32_t ptsUpper32 = ((first8PTSBits&0x0E)<<28) | ((last32PTSBits&0xFFFE0000)>>3) | ((last32PTSBits&0x0000FFFC)>>2); |
155 | u_int8_t ptsLowBit = (last32PTSBits&0x00000002)>>1; |
156 | double PTS = ptsUpper32/45000.0; |
157 | if (ptsLowBit) PTS += 1/90000.0; |
158 | #ifdef DEBUG_CONTENTS |
159 | fprintf(stderr, "\t\t\tPTS: 0x%02x%08x => 0x%08x+%d => %.10f\n" , |
160 | first8PTSBits, last32PTSBits, ptsUpper32, ptsLowBit, PTS); |
161 | #endif |
162 | // Record this PTS: |
163 | pidState->lastSeenPTS = PTS; |
164 | } |
165 | |
166 | if (PTS_DTS_flags == 3) { |
167 | // Continue with a DTS: |
168 | u_int8_t first8DTSBits = get1Byte(); |
169 | u_int32_t last32DTSBits = get4Bytes(); |
170 | if ((first8DTSBits&0x11) != 0x11 || |
171 | (last32DTSBits&0x00010001) != 0x00010001) { |
172 | #ifdef DEBUG_ERRORS |
173 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Bad DTS bits: 0x%02x,0x%08x\n" , |
174 | pidState->PID, numDataBytes, first8DTSBits, last32DTSBits); |
175 | #endif |
176 | break; |
177 | } |
178 | u_int32_t dtsUpper32 = ((first8DTSBits&0x0E)<<28) | ((last32DTSBits&0xFFFE0000)>>3) | ((last32DTSBits&0x0000FFFC)>>2); |
179 | u_int8_t dtsLowBit = (last32DTSBits&0x00000002)>>1; |
180 | double DTS = dtsUpper32/45000.0; |
181 | if (dtsLowBit) DTS += 1/90000.0; |
182 | #ifdef DEBUG_CONTENTS |
183 | fprintf(stderr, "\t\t\tDTS: 0x%02x%08x => 0x%08x+%d => %.10f\n" , |
184 | first8DTSBits, last32DTSBits, dtsUpper32, dtsLowBit, DTS); |
185 | #endif |
186 | } |
187 | |
188 | if (ESCR_flag) { |
189 | // Skip over the ESCR |
190 | skipBytes(6); |
191 | } |
192 | |
193 | if (ES_rate_flag) { |
194 | // Skip over the ES_rate |
195 | skipBytes(6); |
196 | } |
197 | |
198 | if (DSM_trick_mode_flag) { |
199 | // Skip over this |
200 | skipBytes(1); |
201 | } |
202 | |
203 | if (additional_copy_info_flag) { |
204 | // Skip over this |
205 | skipBytes(1); |
206 | } |
207 | |
208 | if (PES_CRC_flag) { |
209 | // Skip over this |
210 | skipBytes(2); |
211 | } |
212 | |
213 | if (PES_extension_flag) { |
214 | u_int8_t flags = get1Byte(); |
215 | Boolean PES_private_data_flag = (flags&0x80) != 0; |
216 | Boolean = (flags&0x40) != 0; |
217 | Boolean program_packet_sequence_counter_flag = (flags&0x20) != 0; |
218 | Boolean P_STD_buffer_flag = (flags&0x10) != 0; |
219 | Boolean PES_extension_flag_2 = (flags&0x01) != 0; |
220 | #ifdef DEBUG_CONTENTS |
221 | fprintf(stderr, "\t\t\tPES_extension: flags: 0x%02x (PES_private_data:%d; pack_header_field:%d; program_packet_sequence_counter:%d; P_STD_buffer:%d; PES_extension_2:%d\n" , |
222 | flags, PES_private_data_flag, pack_header_field_flag, program_packet_sequence_counter_flag, P_STD_buffer_flag, PES_extension_flag_2); |
223 | #endif |
224 | if (PES_private_data_flag) { |
225 | // Skip over this |
226 | skipBytes(16); |
227 | } |
228 | if (pack_header_field_flag) { |
229 | // Skip over this |
230 | skipBytes(1 + 12); // "pack_header()" is 12 bytes in size |
231 | } |
232 | if (program_packet_sequence_counter_flag) { |
233 | // Skip over this |
234 | skipBytes(2); |
235 | } |
236 | if (P_STD_buffer_flag) { |
237 | // Skip over this |
238 | skipBytes(2); |
239 | } |
240 | if (PES_extension_flag_2) { |
241 | u_int8_t PES_extension_field_length = get1Byte()&0x7F; |
242 | #ifdef DEBUG_CONTENTS |
243 | fprintf(stderr, "\t\t\t\tPES_extension_field_length: %d\n" , PES_extension_field_length); |
244 | #endif |
245 | skipBytes(PES_extension_field_length); |
246 | } |
247 | } |
248 | |
249 | // Make sure that the number of header bytes parsed is consistent with "PES_header_data_length" |
250 | // (and skip over any remasining 'stuffing' bytes): |
251 | if (curOffset() - startPos > 9 + PES_header_data_length) { |
252 | #ifdef DEBUG_ERRORS |
253 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Error: Parsed %d PES header bytes; expected %d (based on \"PES_header_data_length\": %d)\n" , |
254 | pidState->PID, numDataBytes, curOffset() - startPos, 9 + PES_header_data_length, |
255 | PES_header_data_length); |
256 | #endif |
257 | break; |
258 | } |
259 | skipBytes(9 + PES_header_data_length - (curOffset() - startPos)); // >= 0 |
260 | } |
261 | |
262 | unsigned = curOffset() - startPos; |
263 | #ifdef DEBUG_CONTENTS |
264 | fprintf(stderr, "\t\t\t=> PES header size: %d\n" , PESHeaderSize); |
265 | #endif |
266 | if (PESHeaderSize > numDataBytes) { |
267 | #ifdef DEBUG_ERRORS |
268 | fprintf(stderr, "MPEG2TransportStreamParser::parsePESHeader(0x%02x, %d): Error: PES header size %d is larger than the number of bytes available (%d)\n" , |
269 | pidState->PID, numDataBytes, PESHeaderSize, numDataBytes); |
270 | #endif |
271 | break; |
272 | } |
273 | return PESHeaderSize; |
274 | } while (0); |
275 | |
276 | // An error occurred. Skip over any remaining bytes in the packet: |
277 | int numBytesLeft = numDataBytes - (curOffset() - startPos); |
278 | if (numBytesLeft > 0) skipBytes((unsigned)numBytesLeft); |
279 | return 0; |
280 | } |
281 | |
282 | |
283 | //########## PIDState_STREAM implementation ########## |
284 | |
285 | PIDState_STREAM::PIDState_STREAM(MPEG2TransportStreamParser& parser, |
286 | u_int16_t pid, u_int16_t programNumber, u_int8_t streamType) |
287 | : PIDState(parser, pid, STREAM), |
288 | program_number(programNumber), stream_type(streamType), lastSeenPTS(0.0) { |
289 | // Create the 'source' and 'sink' objects for this track, and 'start playing' them: |
290 | streamSource = new MPEG2TransportStreamDemuxedTrack(parser, pid); |
291 | |
292 | char fileName[100]; |
293 | extern StreamType StreamTypes[]; |
294 | StreamType& st = StreamTypes[streamType]; // alias |
295 | sprintf(fileName, "%s-0x%04x-0x%04x%s" , |
296 | st.dataType == StreamType::AUDIO ? "AUDIO" : |
297 | st.dataType == StreamType::VIDEO ? "VIDEO" : |
298 | st.dataType == StreamType::DATA ? "DATA" : |
299 | st.dataType == StreamType::TEXT ? "TEXT" : |
300 | "UNKNOWN" , |
301 | program_number, pid, st.filenameSuffix); |
302 | fprintf(stderr, "Creating new output file \"%s\"\n" , fileName); |
303 | streamSink = FileSink::createNew(parser.envir(), fileName); |
304 | streamSink->startPlaying(*streamSource, NULL, NULL); |
305 | } |
306 | |
307 | PIDState_STREAM::~PIDState_STREAM() { |
308 | Medium::close(streamSink); |
309 | Medium::close(streamSource); |
310 | } |
311 | |