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// Demultiplexer for a MPEG 1 or 2 Program Stream
19// Implementation
20
21#include "MPEG1or2Demux.hh"
22#include "MPEG1or2DemuxedElementaryStream.hh"
23#include "StreamParser.hh"
24#include <stdlib.h>
25
26////////// MPEGProgramStreamParser definition //////////
27
28// An enum representing the current state of the parser:
29enum MPEGParseState {
30 PARSING_PACK_HEADER,
31 PARSING_SYSTEM_HEADER,
32 PARSING_PES_PACKET
33};
34
35class MPEGProgramStreamParser: public StreamParser {
36public:
37 MPEGProgramStreamParser(MPEG1or2Demux* usingDemux, FramedSource* inputSource);
38 virtual ~MPEGProgramStreamParser();
39
40public:
41 unsigned char parse();
42 // returns the stream id of a stream for which a frame was acquired,
43 // or 0 if no such frame was acquired.
44
45private:
46 void setParseState(MPEGParseState parseState);
47
48 void parsePackHeader();
49 void parseSystemHeader();
50 unsigned char parsePESPacket(); // returns as does parse()
51
52 Boolean isSpecialStreamId(unsigned char stream_id) const;
53 // for PES packet header parsing
54
55private:
56 MPEG1or2Demux* fUsingDemux;
57 MPEGParseState fCurrentParseState;
58};
59
60
61////////// MPEG1or2Demux::OutputDescriptor::SavedData definition/implementation //////////
62
63class MPEG1or2Demux::OutputDescriptor::SavedData {
64public:
65 SavedData(unsigned char* buf, unsigned size)
66 : next(NULL), data(buf), dataSize(size), numBytesUsed(0) {
67 }
68 virtual ~SavedData() {
69 delete[] data;
70 delete next;
71 }
72
73 SavedData* next;
74 unsigned char* data;
75 unsigned dataSize, numBytesUsed;
76};
77
78
79////////// MPEG1or2Demux implementation //////////
80
81MPEG1or2Demux
82::MPEG1or2Demux(UsageEnvironment& env,
83 FramedSource* inputSource, Boolean reclaimWhenLastESDies)
84 : Medium(env),
85 fInputSource(inputSource), fMPEGversion(0),
86 fNextAudioStreamNumber(0), fNextVideoStreamNumber(0),
87 fReclaimWhenLastESDies(reclaimWhenLastESDies), fNumOutstandingESs(0),
88 fNumPendingReads(0), fHaveUndeliveredData(False) {
89 fParser = new MPEGProgramStreamParser(this, inputSource);
90 for (unsigned i = 0; i < 256; ++i) {
91 fOutput[i].savedDataHead = fOutput[i].savedDataTail = NULL;
92 fOutput[i].isPotentiallyReadable = False;
93 fOutput[i].isCurrentlyActive = False;
94 fOutput[i].isCurrentlyAwaitingData = False;
95 }
96}
97
98MPEG1or2Demux::~MPEG1or2Demux() {
99 delete fParser;
100 for (unsigned i = 0; i < 256; ++i) delete fOutput[i].savedDataHead;
101 Medium::close(fInputSource);
102}
103
104MPEG1or2Demux* MPEG1or2Demux
105::createNew(UsageEnvironment& env,
106 FramedSource* inputSource, Boolean reclaimWhenLastESDies) {
107 // Need to add source type checking here??? #####
108
109 return new MPEG1or2Demux(env, inputSource, reclaimWhenLastESDies);
110}
111
112MPEG1or2Demux::SCR::SCR()
113 : highBit(0), remainingBits(0), extension(0), isValid(False) {
114}
115
116void MPEG1or2Demux
117::noteElementaryStreamDeletion(MPEG1or2DemuxedElementaryStream* /*es*/) {
118 if (--fNumOutstandingESs == 0 && fReclaimWhenLastESDies) {
119 Medium::close(this);
120 }
121}
122
123void MPEG1or2Demux::flushInput() {
124 fParser->flushInput();
125}
126
127MPEG1or2DemuxedElementaryStream*
128MPEG1or2Demux::newElementaryStream(u_int8_t streamIdTag) {
129 ++fNumOutstandingESs;
130 fOutput[streamIdTag].isPotentiallyReadable = True;
131 return new MPEG1or2DemuxedElementaryStream(envir(), streamIdTag, *this);
132}
133
134MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newAudioStream() {
135 unsigned char newAudioStreamTag = 0xC0 | (fNextAudioStreamNumber++&~0xE0);
136 // MPEG audio stream tags are 110x xxxx (binary)
137 return newElementaryStream(newAudioStreamTag);
138}
139
140MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newVideoStream() {
141 unsigned char newVideoStreamTag = 0xE0 | (fNextVideoStreamNumber++&~0xF0);
142 // MPEG video stream tags are 1110 xxxx (binary)
143 return newElementaryStream(newVideoStreamTag);
144}
145
146// Appropriate one of the reserved stream id tags to mean: return raw PES packets:
147#define RAW_PES 0xFC
148
149MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newRawPESStream() {
150 return newElementaryStream(RAW_PES);
151}
152
153void MPEG1or2Demux::registerReadInterest(u_int8_t streamIdTag,
154 unsigned char* to, unsigned maxSize,
155 FramedSource::afterGettingFunc* afterGettingFunc,
156 void* afterGettingClientData,
157 FramedSource::onCloseFunc* onCloseFunc,
158 void* onCloseClientData) {
159 struct OutputDescriptor& out = fOutput[streamIdTag];
160
161 // Make sure this stream is not already being read:
162 if (out.isCurrentlyAwaitingData) {
163 envir() << "MPEG1or2Demux::registerReadInterest(): attempt to read stream more than once!\n";
164 envir().internalError();
165 }
166
167 out.to = to; out.maxSize = maxSize;
168 out.fAfterGettingFunc = afterGettingFunc;
169 out.afterGettingClientData = afterGettingClientData;
170 out.fOnCloseFunc = onCloseFunc;
171 out.onCloseClientData = onCloseClientData;
172 out.isCurrentlyActive = True;
173 out.isCurrentlyAwaitingData = True;
174 // out.frameSize and out.presentationTime will be set when a frame's read
175
176 ++fNumPendingReads;
177}
178
179Boolean MPEG1or2Demux::useSavedData(u_int8_t streamIdTag,
180 unsigned char* to, unsigned maxSize,
181 FramedSource::afterGettingFunc* afterGettingFunc,
182 void* afterGettingClientData) {
183 struct OutputDescriptor& out = fOutput[streamIdTag];
184 if (out.savedDataHead == NULL) return False; // common case
185
186 unsigned totNumBytesCopied = 0;
187 while (maxSize > 0 && out.savedDataHead != NULL) {
188 OutputDescriptor::SavedData& savedData = *(out.savedDataHead);
189 unsigned char* from = &savedData.data[savedData.numBytesUsed];
190 unsigned numBytesToCopy = savedData.dataSize - savedData.numBytesUsed;
191 if (numBytesToCopy > maxSize) numBytesToCopy = maxSize;
192 memmove(to, from, numBytesToCopy);
193 to += numBytesToCopy;
194 maxSize -= numBytesToCopy;
195 out.savedDataTotalSize -= numBytesToCopy;
196 totNumBytesCopied += numBytesToCopy;
197 savedData.numBytesUsed += numBytesToCopy;
198 if (savedData.numBytesUsed == savedData.dataSize) {
199 out.savedDataHead = savedData.next;
200 if (out.savedDataHead == NULL) out.savedDataTail = NULL;
201 savedData.next = NULL;
202 delete &savedData;
203 }
204 }
205
206 out.isCurrentlyActive = True;
207 if (afterGettingFunc != NULL) {
208 struct timeval presentationTime;
209 presentationTime.tv_sec = 0; presentationTime.tv_usec = 0; // should fix #####
210 (*afterGettingFunc)(afterGettingClientData, totNumBytesCopied,
211 0 /* numTruncatedBytes */, presentationTime,
212 0 /* durationInMicroseconds ?????#####*/);
213 }
214 return True;
215}
216
217void MPEG1or2Demux
218::continueReadProcessing(void* clientData,
219 unsigned char* /*ptr*/, unsigned /*size*/,
220 struct timeval /*presentationTime*/) {
221 MPEG1or2Demux* demux = (MPEG1or2Demux*)clientData;
222 demux->continueReadProcessing();
223}
224
225void MPEG1or2Demux::continueReadProcessing() {
226 while (fNumPendingReads > 0) {
227 unsigned char acquiredStreamIdTag = fParser->parse();
228
229 if (acquiredStreamIdTag != 0) {
230 // We were able to acquire a frame from the input.
231 struct OutputDescriptor& newOut = fOutput[acquiredStreamIdTag];
232 newOut.isCurrentlyAwaitingData = False;
233 // indicates that we can be read again
234 // (This needs to be set before the 'after getting' call below,
235 // in case it tries to read another frame)
236
237 // Call our own 'after getting' function. Because we're not a 'leaf'
238 // source, we can call this directly, without risking infinite recursion.
239 if (newOut.fAfterGettingFunc != NULL) {
240 (*newOut.fAfterGettingFunc)(newOut.afterGettingClientData,
241 newOut.frameSize, 0 /* numTruncatedBytes */,
242 newOut.presentationTime,
243 0 /* durationInMicroseconds ?????#####*/);
244 --fNumPendingReads;
245 }
246 } else {
247 // We were unable to parse a complete frame from the input, because:
248 // - we had to read more data from the source stream, or
249 // - we found a frame for a stream that was being read, but whose
250 // reader is not ready to get the frame right now, or
251 // - the source stream has ended.
252 break;
253 }
254 }
255}
256
257void MPEG1or2Demux::getNextFrame(u_int8_t streamIdTag,
258 unsigned char* to, unsigned maxSize,
259 FramedSource::afterGettingFunc* afterGettingFunc,
260 void* afterGettingClientData,
261 FramedSource::onCloseFunc* onCloseFunc,
262 void* onCloseClientData) {
263 // First, check whether we have saved data for this stream id:
264 if (useSavedData(streamIdTag, to, maxSize,
265 afterGettingFunc, afterGettingClientData)) {
266 return;
267 }
268
269 // Then save the parameters of the specified stream id:
270 registerReadInterest(streamIdTag, to, maxSize,
271 afterGettingFunc, afterGettingClientData,
272 onCloseFunc, onCloseClientData);
273
274 // Next, if we're the only currently pending read, continue looking for data:
275 if (fNumPendingReads == 1 || fHaveUndeliveredData) {
276 fHaveUndeliveredData = 0;
277 continueReadProcessing();
278 } // otherwise the continued read processing has already been taken care of
279}
280
281void MPEG1or2Demux::stopGettingFrames(u_int8_t streamIdTag) {
282 struct OutputDescriptor& out = fOutput[streamIdTag];
283
284 if (out.isCurrentlyAwaitingData && fNumPendingReads > 0) --fNumPendingReads;
285
286 out.isCurrentlyActive = out.isCurrentlyAwaitingData = False;
287}
288
289void MPEG1or2Demux::handleClosure(void* clientData) {
290 MPEG1or2Demux* demux = (MPEG1or2Demux*)clientData;
291
292 demux->fNumPendingReads = 0;
293
294 // Tell all pending readers that our source has closed.
295 // Note that we need to make a copy of our readers' close functions
296 // (etc.) before we start calling any of them, in case one of them
297 // ends up deleting this.
298 struct {
299 FramedSource::onCloseFunc* fOnCloseFunc;
300 void* onCloseClientData;
301 } savedPending[256];
302 unsigned i, numPending = 0;
303 for (i = 0; i < 256; ++i) {
304 struct OutputDescriptor& out = demux->fOutput[i];
305 if (out.isCurrentlyAwaitingData) {
306 if (out.fOnCloseFunc != NULL) {
307 savedPending[numPending].fOnCloseFunc = out.fOnCloseFunc;
308 savedPending[numPending].onCloseClientData = out.onCloseClientData;
309 ++numPending;
310 }
311 }
312 delete out.savedDataHead; out.savedDataHead = out.savedDataTail = NULL;
313 out.savedDataTotalSize = 0;
314 out.isPotentiallyReadable = out.isCurrentlyActive = out.isCurrentlyAwaitingData
315 = False;
316 }
317 for (i = 0; i < numPending; ++i) {
318 (*savedPending[i].fOnCloseFunc)(savedPending[i].onCloseClientData);
319 }
320}
321
322
323////////// MPEGProgramStreamParser implementation //////////
324
325#include <string.h>
326
327MPEGProgramStreamParser::MPEGProgramStreamParser(MPEG1or2Demux* usingDemux,
328 FramedSource* inputSource)
329 : StreamParser(inputSource, MPEG1or2Demux::handleClosure, usingDemux,
330 &MPEG1or2Demux::continueReadProcessing, usingDemux),
331 fUsingDemux(usingDemux), fCurrentParseState(PARSING_PACK_HEADER) {
332}
333
334MPEGProgramStreamParser::~MPEGProgramStreamParser() {
335}
336
337void MPEGProgramStreamParser::setParseState(MPEGParseState parseState) {
338 fCurrentParseState = parseState;
339 saveParserState();
340}
341
342unsigned char MPEGProgramStreamParser::parse() {
343 unsigned char acquiredStreamTagId = 0;
344
345 try {
346 do {
347 switch (fCurrentParseState) {
348 case PARSING_PACK_HEADER: {
349 parsePackHeader();
350 break;
351 }
352 case PARSING_SYSTEM_HEADER: {
353 parseSystemHeader();
354 break;
355 }
356 case PARSING_PES_PACKET: {
357 acquiredStreamTagId = parsePESPacket();
358 break;
359 }
360 }
361 } while(acquiredStreamTagId == 0);
362
363 return acquiredStreamTagId;
364 } catch (int /*e*/) {
365#ifdef DEBUG
366 fprintf(stderr, "MPEGProgramStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
367 fflush(stderr);
368#endif
369 return 0; // the parsing got interrupted
370 }
371}
372
373#define PACK_START_CODE 0x000001BA
374#define SYSTEM_HEADER_START_CODE 0x000001BB
375#define PACKET_START_CODE_PREFIX 0x00000100
376
377static inline Boolean isPacketStartCode(unsigned code) {
378 return (code&0xFFFFFF00) == PACKET_START_CODE_PREFIX
379 && code > SYSTEM_HEADER_START_CODE;
380}
381
382void MPEGProgramStreamParser::parsePackHeader() {
383#ifdef DEBUG
384 fprintf(stderr, "parsing pack header\n"); fflush(stderr);
385#endif
386 unsigned first4Bytes;
387 while (1) {
388 first4Bytes = test4Bytes();
389
390 // We're supposed to have a pack header here, but check also for
391 // a system header or a PES packet, just in case:
392 if (first4Bytes == PACK_START_CODE) {
393 skipBytes(4);
394 break;
395 } else if (first4Bytes == SYSTEM_HEADER_START_CODE) {
396#ifdef DEBUG
397 fprintf(stderr, "found system header instead of pack header\n");
398#endif
399 setParseState(PARSING_SYSTEM_HEADER);
400 return;
401 } else if (isPacketStartCode(first4Bytes)) {
402#ifdef DEBUG
403 fprintf(stderr, "found packet start code 0x%02x instead of pack header\n", first4Bytes);
404#endif
405 setParseState(PARSING_PES_PACKET);
406 return;
407 }
408
409 setParseState(PARSING_PACK_HEADER); // ensures we progress over bad data
410 if ((first4Bytes&0xFF) > 1) { // a system code definitely doesn't start here
411 skipBytes(4);
412 } else {
413 skipBytes(1);
414 }
415 }
416
417 // The size of the pack header differs depending on whether it's
418 // MPEG-1 or MPEG-2. The next byte tells us this:
419 unsigned char nextByte = get1Byte();
420 MPEG1or2Demux::SCR& scr = fUsingDemux->fLastSeenSCR; // alias
421 if ((nextByte&0xF0) == 0x20) { // MPEG-1
422 fUsingDemux->fMPEGversion = 1;
423 scr.highBit = (nextByte&0x08)>>3;
424 scr.remainingBits = (nextByte&0x06)<<29;
425 unsigned next4Bytes = get4Bytes();
426 scr.remainingBits |= (next4Bytes&0xFFFE0000)>>2;
427 scr.remainingBits |= (next4Bytes&0x0000FFFE)>>1;
428 scr.extension = 0;
429 scr.isValid = True;
430 skipBits(24);
431
432#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS)
433 fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x",
434 scr.highBit);
435 fprintf(stderr, "%08x\n", scr.remainingBits);
436#endif
437 } else if ((nextByte&0xC0) == 0x40) { // MPEG-2
438 fUsingDemux->fMPEGversion = 2;
439 scr.highBit = (nextByte&0x20)>>5;
440 scr.remainingBits = (nextByte&0x18)<<27;
441 scr.remainingBits |= (nextByte&0x03)<<28;
442 unsigned next4Bytes = get4Bytes();
443 scr.remainingBits |= (next4Bytes&0xFFF80000)>>4;
444 scr.remainingBits |= (next4Bytes&0x0003FFF8)>>3;
445 scr.extension = (next4Bytes&0x00000003)<<7;
446 next4Bytes = get4Bytes();
447 scr.extension |= (next4Bytes&0xFE000000)>>25;
448 scr.isValid = True;
449 skipBits(5);
450
451#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS)
452 fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x",
453 scr.highBit);
454 fprintf(stderr, "%08x\n", scr.remainingBits);
455 fprintf(stderr, "pack hdr system_clock_reference_extension: 0x%03x\n",
456 scr.extension);
457#endif
458 unsigned char pack_stuffing_length = getBits(3);
459 skipBytes(pack_stuffing_length);
460 } else { // unknown
461 fUsingDemux->envir() << "StreamParser::parsePack() saw strange byte following pack_start_code\n";
462 }
463
464 // Check for a System Header next:
465 setParseState(PARSING_SYSTEM_HEADER);
466}
467
468void MPEGProgramStreamParser::parseSystemHeader() {
469#ifdef DEBUG
470 fprintf(stderr, "parsing system header\n"); fflush(stderr);
471#endif
472 unsigned next4Bytes = test4Bytes();
473 if (next4Bytes != SYSTEM_HEADER_START_CODE) {
474 // The system header was optional. Look for a PES Packet instead:
475 setParseState(PARSING_PES_PACKET);
476 return;
477 }
478
479#ifdef DEBUG
480 fprintf(stderr, "saw system_header_start_code\n"); fflush(stderr);
481#endif
482 skipBytes(4); // we've already seen the system_header_start_code
483
484 unsigned short remaining_header_length = get2Bytes();
485
486 // According to the MPEG-1 and MPEG-2 specs, "remaining_header_length" should be
487 // at least 6 bytes. Check this now:
488 if (remaining_header_length < 6) {
489 fUsingDemux->envir() << "StreamParser::parseSystemHeader(): saw strange header_length: "
490 << remaining_header_length << " < 6\n";
491 }
492 skipBytes(remaining_header_length);
493
494 // Check for a PES Packet next:
495 setParseState(PARSING_PES_PACKET);
496}
497
498#define private_stream_1 0xBD
499#define private_stream_2 0xBF
500
501// A test for stream ids that are exempt from normal PES packet header parsing
502Boolean MPEGProgramStreamParser
503::isSpecialStreamId(unsigned char stream_id) const {
504 if (stream_id == RAW_PES) return True; // hack
505
506 if (fUsingDemux->fMPEGversion == 1) {
507 return stream_id == private_stream_2;
508 } else { // assume MPEG-2
509 if (stream_id <= private_stream_2) {
510 return stream_id != private_stream_1;
511 } else if ((stream_id&0xF0) == 0xF0) {
512 unsigned char lower4Bits = stream_id&0x0F;
513 return lower4Bits <= 2 || lower4Bits == 0x8 || lower4Bits == 0xF;
514 } else {
515 return False;
516 }
517 }
518}
519
520#define READER_NOT_READY 2
521
522unsigned char MPEGProgramStreamParser::parsePESPacket() {
523#ifdef DEBUG
524 fprintf(stderr, "parsing PES packet\n"); fflush(stderr);
525#endif
526 unsigned next4Bytes = test4Bytes();
527 if (!isPacketStartCode(next4Bytes)) {
528 // The PES Packet was optional. Look for a Pack Header instead:
529 setParseState(PARSING_PACK_HEADER);
530 return 0;
531 }
532
533#ifdef DEBUG
534 fprintf(stderr, "saw packet_start_code_prefix\n"); fflush(stderr);
535#endif
536 skipBytes(3); // we've already seen the packet_start_code_prefix
537
538 unsigned char stream_id = get1Byte();
539#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS)
540 unsigned char streamNum = stream_id;
541 char const* streamTypeStr;
542 if ((stream_id&0xE0) == 0xC0) {
543 streamTypeStr = "audio";
544 streamNum = stream_id&~0xE0;
545 } else if ((stream_id&0xF0) == 0xE0) {
546 streamTypeStr = "video";
547 streamNum = stream_id&~0xF0;
548 } else if (stream_id == 0xbc) {
549 streamTypeStr = "reserved";
550 } else if (stream_id == 0xbd) {
551 streamTypeStr = "private_1";
552 } else if (stream_id == 0xbe) {
553 streamTypeStr = "padding";
554 } else if (stream_id == 0xbf) {
555 streamTypeStr = "private_2";
556 } else {
557 streamTypeStr = "unknown";
558 }
559#endif
560#ifdef DEBUG
561 static unsigned frameCount = 1;
562 fprintf(stderr, "%d, saw %s stream: 0x%02x\n", frameCount, streamTypeStr, streamNum); fflush(stderr);
563#endif
564
565 unsigned short PES_packet_length = get2Bytes();
566#ifdef DEBUG
567 fprintf(stderr, "PES_packet_length: %d\n", PES_packet_length); fflush(stderr);
568#endif
569
570 // Parse over the rest of the header, until we get to the packet data itself.
571 // This varies depending upon the MPEG version:
572 if (fUsingDemux->fOutput[RAW_PES].isPotentiallyReadable) {
573 // Hack: We've been asked to return raw PES packets, for every stream:
574 stream_id = RAW_PES;
575 }
576 unsigned savedParserOffset = curOffset();
577#ifdef DEBUG_TIMESTAMPS
578 unsigned char pts_highBit = 0;
579 unsigned pts_remainingBits = 0;
580 unsigned char dts_highBit = 0;
581 unsigned dts_remainingBits = 0;
582#endif
583 if (fUsingDemux->fMPEGversion == 1) {
584 if (!isSpecialStreamId(stream_id)) {
585 unsigned char nextByte;
586 while ((nextByte = get1Byte()) == 0xFF) { // stuffing_byte
587 }
588 if ((nextByte&0xC0) == 0x40) { // '01'
589 skipBytes(1);
590 nextByte = get1Byte();
591 }
592 if ((nextByte&0xF0) == 0x20) { // '0010'
593#ifdef DEBUG_TIMESTAMPS
594 pts_highBit = (nextByte&0x08)>>3;
595 pts_remainingBits = (nextByte&0x06)<<29;
596 unsigned next4Bytes = get4Bytes();
597 pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
598 pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
599#else
600 skipBytes(4);
601#endif
602 } else if ((nextByte&0xF0) == 0x30) { // '0011'
603#ifdef DEBUG_TIMESTAMPS
604 pts_highBit = (nextByte&0x08)>>3;
605 pts_remainingBits = (nextByte&0x06)<<29;
606 unsigned next4Bytes = get4Bytes();
607 pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
608 pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
609
610 nextByte = get1Byte();
611 dts_highBit = (nextByte&0x08)>>3;
612 dts_remainingBits = (nextByte&0x06)<<29;
613 next4Bytes = get4Bytes();
614 dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
615 dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
616#else
617 skipBytes(9);
618#endif
619 }
620 }
621 } else { // assume MPEG-2
622 if (!isSpecialStreamId(stream_id)) {
623 // Fields in the next 3 bytes determine the size of the rest:
624 unsigned next3Bytes = getBits(24);
625#ifdef DEBUG_TIMESTAMPS
626 unsigned char PTS_DTS_flags = (next3Bytes&0x00C000)>>14;
627#endif
628#ifdef undef
629 unsigned char ESCR_flag = (next3Bytes&0x002000)>>13;
630 unsigned char ES_rate_flag = (next3Bytes&0x001000)>>12;
631 unsigned char DSM_trick_mode_flag = (next3Bytes&0x000800)>>11;
632#endif
633 unsigned char PES_header_data_length = (next3Bytes&0x0000FF);
634#ifdef DEBUG
635 fprintf(stderr, "PES_header_data_length: 0x%02x\n", PES_header_data_length); fflush(stderr);
636#endif
637#ifdef DEBUG_TIMESTAMPS
638 if (PTS_DTS_flags == 0x2 && PES_header_data_length >= 5) {
639 unsigned char nextByte = get1Byte();
640 pts_highBit = (nextByte&0x08)>>3;
641 pts_remainingBits = (nextByte&0x06)<<29;
642 unsigned next4Bytes = get4Bytes();
643 pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
644 pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
645
646 skipBytes(PES_header_data_length-5);
647 } else if (PTS_DTS_flags == 0x3 && PES_header_data_length >= 10) {
648 unsigned char nextByte = get1Byte();
649 pts_highBit = (nextByte&0x08)>>3;
650 pts_remainingBits = (nextByte&0x06)<<29;
651 unsigned next4Bytes = get4Bytes();
652 pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
653 pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
654
655 nextByte = get1Byte();
656 dts_highBit = (nextByte&0x08)>>3;
657 dts_remainingBits = (nextByte&0x06)<<29;
658 next4Bytes = get4Bytes();
659 dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2;
660 dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1;
661
662 skipBytes(PES_header_data_length-10);
663 }
664#else
665 skipBytes(PES_header_data_length);
666#endif
667 }
668 }
669#ifdef DEBUG_TIMESTAMPS
670 fprintf(stderr, "%s stream, ", streamTypeStr);
671 fprintf(stderr, "packet presentation_time_stamp: 0x%x", pts_highBit);
672 fprintf(stderr, "%08x\n", pts_remainingBits);
673 fprintf(stderr, "\t\tpacket decoding_time_stamp: 0x%x", dts_highBit);
674 fprintf(stderr, "%08x\n", dts_remainingBits);
675#endif
676
677 // The rest of the packet will be the "PES_packet_data_byte"s
678 // Make sure that "PES_packet_length" was consistent with where we are now:
679 unsigned char acquiredStreamIdTag = 0;
680 unsigned currentParserOffset = curOffset();
681 unsigned bytesSkipped = currentParserOffset - savedParserOffset;
682 if (stream_id == RAW_PES) {
683 restoreSavedParserState(); // so we deliver from the beginning of the PES packet
684 PES_packet_length += 6; // to include the whole of the PES packet
685 bytesSkipped = 0;
686 }
687 if (PES_packet_length < bytesSkipped) {
688 fUsingDemux->envir() << "StreamParser::parsePESPacket(): saw inconsistent PES_packet_length "
689 << PES_packet_length << " < "
690 << bytesSkipped << "\n";
691 } else {
692 PES_packet_length -= bytesSkipped;
693#ifdef DEBUG
694 unsigned next4Bytes = test4Bytes();
695#endif
696
697 // Check whether our using source is interested in this stream type.
698 // If so, deliver the frame to him:
699 MPEG1or2Demux::OutputDescriptor_t& out = fUsingDemux->fOutput[stream_id];
700 if (out.isCurrentlyAwaitingData) {
701 unsigned numBytesToCopy;
702 if (PES_packet_length > out.maxSize) {
703 fUsingDemux->envir() << "MPEGProgramStreamParser::parsePESPacket() error: PES_packet_length ("
704 << PES_packet_length
705 << ") exceeds max frame size asked for ("
706 << out.maxSize << ")\n";
707 numBytesToCopy = out.maxSize;
708 } else {
709 numBytesToCopy = PES_packet_length;
710 }
711
712 getBytes(out.to, numBytesToCopy);
713 out.frameSize = numBytesToCopy;
714#ifdef DEBUG
715 fprintf(stderr, "%d, %d bytes of PES_packet_data (out.maxSize: %d); first 4 bytes: 0x%08x\n", frameCount, numBytesToCopy, out.maxSize, next4Bytes); fflush(stderr);
716#endif
717 // set out.presentationTime later #####
718 acquiredStreamIdTag = stream_id;
719 PES_packet_length -= numBytesToCopy;
720 } else if (out.isCurrentlyActive) {
721 // Someone has been reading this stream, but isn't right now.
722 // We can't deliver this frame until he asks for it, so punt for now.
723 // The next time he asks for a frame, he'll get it.
724#ifdef DEBUG
725 fprintf(stderr, "%d, currently undeliverable PES data; first 4 bytes: 0x%08x - currently undeliverable!\n", frameCount, next4Bytes); fflush(stderr);
726#endif
727 restoreSavedParserState(); // so we read from the beginning next time
728 fUsingDemux->fHaveUndeliveredData = True;
729 throw READER_NOT_READY;
730 } else if (out.isPotentiallyReadable &&
731 out.savedDataTotalSize + PES_packet_length < 1000000 /*limit*/) {
732 // Someone is interested in this stream, but hasn't begun reading it yet.
733 // Save this data, so that the reader will get it when he later asks for it.
734 unsigned char* buf = new unsigned char[PES_packet_length];
735 getBytes(buf, PES_packet_length);
736 MPEG1or2Demux::OutputDescriptor::SavedData* savedData
737 = new MPEG1or2Demux::OutputDescriptor::SavedData(buf, PES_packet_length);
738 if (out.savedDataHead == NULL) {
739 out.savedDataHead = out.savedDataTail = savedData;
740 } else {
741 out.savedDataTail->next = savedData;
742 out.savedDataTail = savedData;
743 }
744 out.savedDataTotalSize += PES_packet_length;
745 PES_packet_length = 0;
746 }
747 skipBytes(PES_packet_length);
748 }
749
750 // Check for another PES Packet next:
751 setParseState(PARSING_PES_PACKET);
752#ifdef DEBUG
753 ++frameCount;
754#endif
755 return acquiredStreamIdTag;
756}
757