summaryrefslogtreecommitdiffstats
path: root/mpeglib/lib/mpegplay/tsSystemStream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mpeglib/lib/mpegplay/tsSystemStream.cpp')
-rw-r--r--mpeglib/lib/mpegplay/tsSystemStream.cpp377
1 files changed, 377 insertions, 0 deletions
diff --git a/mpeglib/lib/mpegplay/tsSystemStream.cpp b/mpeglib/lib/mpegplay/tsSystemStream.cpp
new file mode 100644
index 00000000..4c9221ac
--- /dev/null
+++ b/mpeglib/lib/mpegplay/tsSystemStream.cpp
@@ -0,0 +1,377 @@
+/*
+ demux transport stream
+ Copyright (C) 2001 Martin Vogt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation.
+
+ For more information look at the file COPYRIGHT in this package
+
+ */
+
+
+
+#include "tsSystemStream.h"
+
+
+#define PKT_SIZE 188
+
+
+TSSystemStream::TSSystemStream(InputStream* input) {
+ this->input=input;
+
+}
+
+
+TSSystemStream::~TSSystemStream() {
+}
+
+int TSSystemStream::read(char* ptr,int bytes) {
+ if (input->read(ptr,bytes) != bytes) {
+ return false;
+ }
+ paket_read+=bytes;
+
+ return true;
+}
+
+int TSSystemStream::getByteDirect() {
+ unsigned char byte;
+ if (input->read((char*)&byte,1) != 1) {
+ return -1;
+ }
+ paket_read++;
+ return (int)byte;
+}
+
+
+// nuke bytes modulo 10
+int TSSystemStream::nukeBytes(int bytes) {
+ // nukebuffer
+ char nuke[10];
+
+ while(bytes > 0) {
+ int doNuke=10;
+ if (bytes < 10) doNuke=bytes;
+ if (input->read((char*)&nuke,doNuke) != doNuke) {
+ return false;
+ }
+ bytes-=doNuke;
+ paket_read+=doNuke;
+ }
+ return true;
+}
+
+
+int TSSystemStream::skipNextByteInLength() {
+ int length=getByteDirect();
+ if (length < 0) return false;
+
+ /*
+ * Skip read byte in length, but check paket_size
+ */
+ if (paket_read+length > PKT_SIZE) {
+ printf ("demux error! invalid payload size %d\n",length);
+ return false;
+ }
+ if (nukeBytes(length) == false) return false;
+ return true;
+}
+
+
+
+
+int TSSystemStream::processStartCode(MpegSystemHeader* mpegHeader) {
+ paket_len=PKT_SIZE;
+ paket_read=4; // startcode=4 bytes
+
+ mpegHeader->setTSPacketLen(0);
+ mpegHeader->setPacketID(_PAKET_ID_NUKE);
+
+ unsigned int pid=mpegHeader->getPid();
+ unsigned int pmtPID=mpegHeader->getPMTPID();
+ if ( (pmtPID == INVALID_PID) && (pid != 0)) {
+ return false;
+ }
+
+ if ((mpegHeader->getAdaption_field_control() & 0x1)==0) {
+ return true;
+ }
+
+ /*
+ * Has a payload! Calculate & check payload length.
+ */
+ if (mpegHeader->getAdaption_field_control() & 0x2) {
+ if (skipNextByteInLength() == false) return false;
+ }
+
+ /*
+ * Do the demuxing in based on the pids
+ */
+
+ if (pid == mpegHeader->getPMTPID()) {
+ return demux_ts_pmt_parse(mpegHeader);
+ }
+
+ if (pid == 0) {
+ return demux_ts_pat_parse(mpegHeader);
+ }
+ //
+ // ok, no the only things left to do is the
+ // decision what to do with the packet
+ //
+
+ mpegHeader->setTSPacketLen(paket_len-paket_read);
+
+ if (pid == 0x1fff) {
+ printf("Nuke Packet\n");
+ return true;
+ }
+
+
+ MapPidStream* mapPidStream=mpegHeader->lookup(pid);
+
+ if (mapPidStream->isValid == true) {
+ // set to something different from "NUKE_PAKET"
+ mpegHeader->setPacketID(_PAKET_ID_AUDIO_1);
+ return true;
+ }
+ // well the raw stream has a TS header and a PID, but we have not a valid
+ // mapping pid->tsType.
+ // we return false here to have a recovery if our
+ // previous decision that we actually have a TS stream was wrong.
+
+ // force resync
+ return false;
+}
+
+/*
+ * NAME demux_ts_pmt_parse
+ *
+ * Parse a PMT. The PMT is expected to be exactly one section long,
+ * and that section is expected to be contained in a single TS packet.
+ *
+ * In other words, the PMT is assumed to describe a reasonable number of
+ * video, audio and other streams (with descriptors).
+ */
+
+int TSSystemStream::demux_ts_pmt_parse(MpegSystemHeader* mpegHeader) {
+ int sectionLength=processSection(mpegHeader);
+ if (sectionLength == 0) return false;
+
+ //?
+ if (nukeBytes(2) == false) return false;
+ sectionLength-=2;
+
+ /*
+ * ES definitions start here...we are going to learn upto one video
+ * PID and one audio PID.
+ */
+
+
+ unsigned char pkt[2];
+ if (read((char*)pkt,2) == false) return false;
+ sectionLength-=2;
+
+ unsigned int programInfoLength;
+
+ programInfoLength=(((unsigned int)pkt[0] & 0x0f) << 8) | pkt[1];
+ if (paket_read+programInfoLength > paket_len) {
+ printf ("demux error! PMT with inconsistent progInfo length\n");
+ return false;
+ }
+
+ if (nukeBytes(programInfoLength) == false) return false;
+ sectionLength-=programInfoLength;
+
+ return processElementary(sectionLength,mpegHeader);
+
+
+}
+
+/**
+ return false on error or section length info on success
+*/
+int TSSystemStream::processSection(MpegSystemHeader* mpegHeader) {
+ unsigned int pus=mpegHeader->getPayload_unit_start_indicator();
+
+ /*
+ * A PAT in a single section should start with a payload unit start
+ * indicator set.
+ */
+ if (pus==0) {
+ printf ("demux error! PAT without payload unit start\n");
+ return false;
+ }
+ /*
+ * PAT packets with a pus start with a pointer. Skip it!
+ */
+ if (skipNextByteInLength() == false) return false;
+
+ // ??
+ if (nukeBytes(1) == false) return false;
+
+ // read sectionLength
+ unsigned char pkt[2];
+ if (read((char*)pkt,2) ==false) return false;
+
+
+ int sectionLength=(((unsigned int)pkt[0] & 0x3) << 8) | pkt[1];
+ if (paket_read+sectionLength > PKT_SIZE) {
+ printf ("demux error! invalid section size %d\n",sectionLength);
+ return false;
+ }
+
+ // ??
+ if (nukeBytes(2) == false) return false;
+
+ int byte=getByteDirect();
+ if (byte < 0) return false;
+
+ if ((byte & 0x01) == false) {
+ /*
+ * Not current!
+ */
+ return false;
+ }
+ if (read((char*)pkt,2) == false) return false;
+
+ if ((pkt[0]) || (pkt[1])) {
+ printf ("demux error! PAT with invalid section %02x of %02x\n",
+ pkt[0], pkt[1]);
+ return false;
+ }
+
+ /*
+ * TBD: at this point, we should check the CRC. Its not that expensive, and
+ * the consequences of getting it wrong are dire!
+ */
+ return sectionLength-5;
+}
+
+/*
+ * NAME demux_ts_pat_parse
+ *
+ * Parse a PAT. The PAT is expected to be exactly one section long,
+ * and that section is expected to be contained in a single TS packet.
+ *
+ * The PAT is assumed to contain a single program definition, though
+ * we can cope with the stupidity of SPTSs which contain NITs.
+ */
+
+int TSSystemStream::demux_ts_pat_parse(MpegSystemHeader* mpegHeader) {
+ int sectionLength=processSection(mpegHeader);
+ if (sectionLength == 0) return false;
+
+ return processPrograms(sectionLength,mpegHeader);
+
+}
+
+
+/*
+ * Process all programs in the program loop.
+ */
+int TSSystemStream::processPrograms(int sectionLength,
+ MpegSystemHeader* mpegHeader) {
+ int programs=sectionLength / 4;
+ int i;
+ // what happens with the last 4 byte?
+ // seems they have no meaning?
+ programs--;
+
+ for(i=0;i<programs;i++) {
+ unsigned char program[4];
+ if (read((char*)program,4) == false) return false;
+
+
+ unsigned int programNumber;
+ unsigned int pmtPid;
+ unsigned int programCount;
+ programNumber = ((unsigned int)program[0] << 8) | program[1];
+
+ /*
+ * Skip NITs completely.
+ */
+ if (!programNumber)
+ continue;
+
+ pmtPid = (((unsigned int)program[2] & 0x1f) << 8) | program[3];
+
+
+ /*
+ * If we have yet to learn our program number, then learn it.
+ */
+
+ if (mpegHeader->getProgramNumber() == INVALID_PROGRAM) {
+ mpegHeader->setProgramNumber(programNumber);
+ mpegHeader->setPMTPID(pmtPid);
+ }
+
+ if (mpegHeader->getProgramNumber() != programNumber) {
+ printf("demux error! MPTS: programNumber=%u pmtPid=%04x\n",
+ programNumber, pmtPid);
+ }
+
+ if (mpegHeader->getPMTPID() != pmtPid) {
+ printf("pmtPid changed %04x\n", pmtPid);
+ mpegHeader->setPMTPID(pmtPid);
+ }
+
+ }
+ // nuke last four bytes
+ if (nukeBytes(4) == false) return false;
+
+ //
+ // now we can nuke the rest of the PAKET_SIZE (188 byte)
+ //
+ mpegHeader->setTSPacketLen(paket_len-paket_read);
+ return true;
+}
+
+
+
+int TSSystemStream::processElementary(int sectionLength,
+ MpegSystemHeader* mpegHeader) {
+
+
+ /*
+ * Extract the elementary streams.
+ */
+ int mediaIndex=0;
+ // what happens with the last 4 byte?
+ // seems they have no meaning?
+ while (sectionLength > 4) {
+ unsigned int streamInfoLength;
+ unsigned char stream[5];
+ if (read((char*)stream,5) == false) return false;
+ sectionLength-=5;
+
+ unsigned int pid;
+ pid = (((unsigned int)stream[1] & 0x1f) << 8) | stream[2];
+
+ streamInfoLength = (((unsigned int)stream[3] & 0xf) << 8) | stream[4];
+ if(paket_read+streamInfoLength > paket_len) {
+ printf ("demux error! PMT with inconsistent streamInfo length\n");
+ return false;
+ }
+ mpegHeader->insert(pid,stream[0],mpegHeader);
+
+ }
+
+ // nuke last four bytes
+ if (nukeBytes(4) == false) return false;
+ //
+ // now we can nuke the rest of the PAKET_SIZE (188 byte)
+ //
+ mpegHeader->setTSPacketLen(paket_len-paket_read);
+
+ //
+ // now we can be sure that we have in fact an TS stream
+ // so, switch to MPEG2 PES now
+ mpegHeader->setMPEG2(true);
+
+ return true;
+}
+
+