1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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
25Boolean 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 pesHeaderSize = 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
74static Boolean isSpecialStreamId[0x100];
75
76unsigned MPEG2TransportStreamParser
77::parsePESHeader(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 PES_header_data_length = 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 pack_header_field_flag = (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 PESHeaderSize = 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
285PIDState_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
307PIDState_STREAM::~PIDState_STREAM() {
308 Medium::close(streamSink);
309 Medium::close(streamSource);
310}
311