From 5c14995c9a08198bfcc93456b4138ed766a23120 Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Mon, 5 Nov 2012 08:30:39 +0100 Subject: [PATCH] Fix bug in pts_expected (Thanks to hondansx for spotting this) --- demuxerts.cc | 1909 +++++++++++++++++++++++++------------------------- 1 file changed, 955 insertions(+), 954 deletions(-) diff --git a/demuxerts.cc b/demuxerts.cc index 97ab760..70375b4 100644 --- a/demuxerts.cc +++ b/demuxerts.cc @@ -1,954 +1,955 @@ -/* - Copyright 2006-2008 Mark Calderbank - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "demuxerts.h" -#include "log.h" -#include "video.h" -#include "vdr.h" -#include "audio.h" - -#define PTS_JUMP_MARGIN 10000 -#define PTS_ALLOWANCE 90000 - -// TODO: PTS class to handle wrapping arithmetic & comparisons? -static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2) -{ - // Assume pts1, pts2 < 2^33; calculate shortest distance between - ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1; - if (ret > (1LL<<32)) ret = (1LL<<33) - ret; - return ret; -} - -static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2) -{ - // Assume pts1, pts2 < 2^33; calculate pts1 - pts2 - if (pts1 > pts2) - return pts1 - pts2; - else - return (1LL<<33) + pts1 - pts2; -} - -DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID) -{ - vID = p_vID; vActive = false; - aID = p_aID; aActive = false; - subID = p_subID; subActive = false; - atype = 0; - subLength = 0; - tID = p_tID; - havechannelinfo=false; - //doubledframerate=false; - framereserve=0; -} - -void DemuxerTS::flush() -{ - partPacket = 0; - parsed = false; - havechannelinfo=false; - Demuxer::flush(); - vPacket.init(PESTYPE_VID0); - switch (atype) - { - case 1: - aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); - break; - default: - case 0: - aPacket.init(PESTYPE_AUD0); - break; - } - subPacket.init(PESTYPE_PRIVATE_1); -tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); - - vActive = false; - aActive = false; - subActive = false; - subLength = 0; - tActive = false; - // doubledframerate=false; - framereserve=0; -} - -int DemuxerTS::scan(UCHAR *buf, int len) -{ - switch (atype) - { - case 1: - return PESTYPE_PRIVATE_1; - default: - case 0: - return PESTYPE_AUD0; - } -} - -void DemuxerTS::setVID(int p_vID) -{ - vID = p_vID; - vPacket.init(PESTYPE_VID0); - vActive = false; -} - -void DemuxerTS::setAID(int p_aID, int type, int streamtype) -{ - aID = p_aID; - atype = type; - astreamtype = streamtype; - switch (atype) - { - case 1: - aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); - setAudioStream(PESTYPE_SUBSTREAM_AC30); - break; - default: - case 0: - aPacket.init(PESTYPE_AUD0); - setAudioStream(PESTYPE_AUD0); - break; - } - aActive = false; -} - -void DemuxerTS::setSubID(int p_subID) -{ - subID = p_subID; - subPacket.init(PESTYPE_PRIVATE_1); - subActive = false; - subLength = 0; -} - -void DemuxerTS::setTID(int p_tID) -{ - tID = p_tID; - tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); - tActive = false; - -} - - - - -int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest) -{ - int scanaid=0; - - while (len >= TS_SIZE) - { - if (*buf != TS_SIG) {buf++;len--; continue;} - - //Pattern scanning won't work for ts - - - int datalen = TS_SIZE - 4; - int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; - UCHAR payload = buf[1] & 0x40; - - if (buf[3] & 0x20) // Adaptation field is present - datalen -= (buf[4] + 1); - - UCHAR* curbuf =buf+ (TS_SIZE - datalen); - - - if (payload) { - if (pid == 0x00) {//PAT, only take first program number, ignore the rest - int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12); - if ((pmtpid >> 13) != 0x07) - { - Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); - } - else - { - pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits - PMTPID = pmtpid; - } - - } else if (pid == PMTPID) { //PMT - int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3); - //sectionlength += 4; //include header but subtract crc in the end... - int p = 13; //skip fixed part of pmt - while ( p < sectionlength) { - int streamtype = *(curbuf+p); - p++; - int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1); - p += 2; //skip ES Pid - int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1); - p += 2; //skip ES length - if ((foundpid >> 13) != 0x07) - { - Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); - } - else - { - foundpid = foundpid & 0x1FFF; //clear upper 3 bits - //int pos=0; UNUSED? - if (streamtype==3 || streamtype ==4) { - scanaid=foundpid; - } - } - p += eslength; //skip es descriptor - } - } else if (pid == scanaid) { - // UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; UNUSED? - - if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present - { - *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) | - ( (ULLONG)(curbuf[10]) << 22 ) | - ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) | - ( (ULLONG)(curbuf[12]) << 7 ) | - ( (ULLONG)(curbuf[13] & 0xFE) >> 1 ); - return 1; - } - } - } - len-=TS_SIZE; - buf+=TS_SIZE; - } - // No PTS found. - return 0; -} - -void DemuxerTS::setFrameNum(ULONG frame) -{ - frameCounting = true; - frameNumber = frame; - framereserve=0; - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame); -} - -void DemuxerTS::setPacketNum(ULONG npacket) -{ - packetCounting = true; - packetNumber = npacket; - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket); -} - -int DemuxerTS::put(UCHAR* buf, int len) -{ - int ret = 0; // return number of bytes consumed - - bool misaligned_mess=false; - while (partPacket) - { - if (len >= TS_SIZE + 1 - partPacket) - { // Remainder of partial packet is available, plus one - memcpy(store+partPacket, buf, TS_SIZE - partPacket); - ret += TS_SIZE - partPacket; - buf += TS_SIZE - partPacket; - len -= TS_SIZE - partPacket; - partPacket = TS_SIZE; - if (*buf == TS_SIG) - { // Packet is properly terminated - int rc = processTS(store); - if (rc) - partPacket = 0; // Successfully processed - else - return ret; // Try again later. - } - else - { // Packet not terminated. Find another candidate, and shift store - if (!misaligned_mess) { - Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!A"); - misaligned_mess=true; // do not alarm more than once - } - int search = 1; - while (search < partPacket && store[search] != TS_SIG) - search++; - partPacket -= search; - if (partPacket) memcpy(store, store+search, partPacket); - } - } - else - { // Still don't have complete packet. Consume what we do have. - memcpy(store+partPacket, buf, len); - partPacket += len; - ret += len; - return ret; - } - } - - // Position ourselves at a candidate TS packet - while (len > 0 && *buf != TS_SIG) - { - if (!misaligned_mess) { - Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!B"); - misaligned_mess=true; // do not alarm more than once - } - buf++; ret++; len--; - } - - while (len) - { - if (len < TS_SIZE + 1) - { // Not enough data. Store what we have. - memcpy(store, buf, len); - partPacket = len; - ret += len; - return ret; - } - - if (buf[TS_SIZE] != TS_SIG) - { // Not terminated correctly. - buf++; ret++; len--; - while (len > 0 && *buf != TS_SIG) - { - buf++; ret++; len--; - } - } - else - { - int rc = processTS(buf); - if (rc) - { // Successfully processed - buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE; - } - else - { // Processing failed. - return ret; - } - } - } - return ret; -} - - -int DemuxerTS::processTS(UCHAR* buf) -{ - int datalen = TS_SIZE - 4; - - int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; - UCHAR payload = buf[1] & 0x40; - - - if (buf[3] & 0x20) // Adaptation field is present - datalen -= (buf[4] + 1); - if (datalen < 0) // Error in stream TODO log this - return 1; - if (datalen == 0) // Null packet - return 1; - // if (!(buf[3] &0x10)) return 1; // no payload - buf += (TS_SIZE - datalen); - - if (payload) - { - int rc = 1; - if (pid == 0x00) {//PAT, only take first program number, ignore the rest - int pmtpid = (*(buf+11)<< 8) | *(buf+12); - if ((pmtpid >> 13) != 0x07) - { - Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13)); - } - else - { - pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits - PMTPID = pmtpid; - } - return 1; - } - if (pid == PMTPID) - { //PMT - int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3); - //sectionlength += 4; //include header but subtract crc in the end... - int p = 13; //skip fixed part of pmt - Channel new_channelinfo; - new_channelinfo.numAPids=0; - new_channelinfo.numDPids=0; - new_channelinfo.numSPids=0; - new_channelinfo.number=0; - new_channelinfo.type=VDR::RADIO; - new_channelinfo.name=NULL; - new_channelinfo.tpid=0xFFFFF; //unused, check this - new_channelinfo.vpid=0xFFFFF; //unused, check this - new_channelinfo.index=0; - - new_channelinfo.apids.clear(); - new_channelinfo.dpids.clear(); - new_channelinfo.spids.clear(); - - while ( p < sectionlength) { - int streamtype = *(buf+p); - p++; - int foundpid = (*(buf+p)<< 8) | *(buf+p+1); - p += 2; //skip ES Pid - int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1); - p += 2; //skip ES length - if ((foundpid >> 13) != 0x07) - { - Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); - } - else - { - foundpid = foundpid & 0x1FFF; //clear upper 3 bits - bool notfound=false; - bool nolang=true; - int pos=0; - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x %x", foundpid,streamtype); - switch (streamtype) - { - case 0x1B: //MPEG 4 for future use - case 1: - case 2: { //video - if (foundpid != getVID()) - setVID(foundpid); - new_channelinfo.type=VDR::VIDEO; - new_channelinfo.vstreamtype=streamtype; - new_channelinfo.vpid=foundpid; - if (streamtype==0x1b) h264=true; - else h264=false; - - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid); - }break; - case 0x0F: //AAC ADTS packaging - case 0x11: // LATM packaging - case 3: - case 4: { //audio - apid newapid; - newapid.pid = foundpid; - newapid.desc[0]=0; - newapid.type=streamtype; - pos=0; - nolang=true; - while (pos< eslength && nolang) { - switch (buf[p+pos]) { - case 0x0A: { - newapid.desc[0]=buf[p+pos+2]; - newapid.desc[1]=buf[p+pos+3]; - newapid.desc[2]=buf[p+pos+4]; - newapid.desc[3]=0; - nolang=false; - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDLANG is %s", newapid.desc); - } break; - }; - - pos+=2+buf[p+pos+1]; - } - - new_channelinfo.apids.push_back(newapid); - new_channelinfo.numAPids++; - if (getAID() == 0 && Audio::getInstance()->streamTypeSupported(streamtype)) { //set unset AID to first audio pid that reports itself - setAID(foundpid,0,streamtype); - Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid); - } - } break; - case 5: - case 6: { //Private Data - apid newapid; - newapid.pid = foundpid; - newapid.desc[0]=0; //set it in player - pos=0; - notfound=true; - nolang=true; - int type=0; - - while (pos< eslength && (notfound || nolang)) { - switch (buf[p+pos]) { - case 0x7A: // Enhanced Ac3 Desriptor - case 0x6A: {//Ac3 descriptor - newapid.type=buf[p+pos]; - type=1; - - notfound=false; - } break; - case 0x59: {//SubtitlingDescriptor - type=2; - newapid.type=buf[p+pos]; - newapid.desc[0]=buf[p+pos+2]; - newapid.desc[1]=buf[p+pos+3]; - newapid.desc[2]=buf[p+pos+4]; - newapid.desc[3]=0; - newapid.data1=(buf[p+pos+5]<<8) |(buf[p+pos+6]); - newapid.data2=(buf[p+pos+7]<<8) |(buf[p+pos+8]); - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDSUB is %s", newapid.desc); - notfound=false; - nolang=false; - } break; - case 0x0A: { - newapid.desc[0]=buf[p+pos+2]; - newapid.desc[1]=buf[p+pos+3]; - newapid.desc[2]=buf[p+pos+4]; - newapid.desc[3]=0; - nolang=false; - // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDLANG is %s", newapid.desc); - } break; - case 0x56: { - type=3; - new_channelinfo.tpid=foundpid; - notfound=false; - } break; - }; - pos+=2+buf[p+pos+1]; - } - if (type==1) { - new_channelinfo.dpids.push_back(newapid); - new_channelinfo.numDPids++; - } else if (type==2) { - new_channelinfo.spids.push_back(newapid); - new_channelinfo.numSPids++; - } - - } break; - default://TODO how about subtitles and second audio pids - break; - } - } - - p += eslength; //skip es descriptor - - - } - bool audioPIDpresent=false; //Check if pids chnages - ULONG i; - for (i=0;i0) { - int j=0; - while (jstreamTypeSupported(channelinfo.apids[j].type)) { - found =true; - setAID(channelinfo.apids[j].pid,0,channelinfo.apids[j].type); - } - j++; - } - - } - if (channelinfo.numDPids>0 && !found) { - int j=0; - while (jstreamTypeSupported(channelinfo.dpids[j].type)) { - found =true; - setAID(channelinfo.dpids[j].pid,1,channelinfo.dpids[j].type); - } - i++; - } - } - } - - channelinfo=new_channelinfo; - - - havechannelinfo=true; - - return 1; - } - - - - - if (pid == vID) - { - if (vActive) - { - if (!parsed) - { - parseTSPacketDetails(vPacket); - parsed = true; - } - rc = submitPacket(vPacket); - } - vActive = true; - } - if (pid == aID) - { - if (aActive) - { - if (!parsed) - { - parseTSPacketDetails(aPacket); - parsed = true; - } - rc = submitPacket(aPacket); - } - aActive = true; - } - if (pid == subID) - { - if (subActive) - { - if (!parsed) - { - parseTSPacketDetails(subPacket); - parsed = true; - } - rc = submitPacket(subPacket); - } - subActive = true; - } - if (isteletextdecoded && pid == tID) - { - if (tActive) - { - if (!parsed) - { - parseTSPacketDetails(tPacket); - parsed = true; - } - rc = submitPacket(tPacket); - } - tActive = true; - } - if (rc == 0) return 0; - - parsed = false; - if (pid == vID) - { - vPacket.init(PESTYPE_VID0); - buf += 6; datalen -= 6; - } - if (pid == aID) - { - switch (atype) - { - case 1: - aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); - break; - default: - case 0: - aPacket.init(PESTYPE_AUD0); - break; - } - buf += 6; datalen -= 6; - } - if (pid == subID) - { - subPacket.init(PESTYPE_PRIVATE_1); - subLength = (buf[4] << 8) + buf[5]; - buf += 6; datalen -= 6; - } - if (isteletextdecoded && pid == tID) - { - tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); - buf += 6; datalen -= 6; - } - } - - if ( (pid == vID && vActive) || - (pid == aID && aActive) || - (pid == tID && tActive) || - (pid == subID && subActive) ) - { - PESPacket* packet = NULL; - if (pid == vID) packet = &vPacket; - if (pid == aID) packet = &aPacket; - if (pid == subID) { - packet = &subPacket; - } - if (pid == tID) packet = &tPacket; - if (packet != NULL) - { - if (packet->write(buf, datalen) == 0) - { // Writing to packet failed. It has overflowed. - if (!parsed) - { - parseTSPacketDetails(*packet); - parsed = true; - } - if (submitPacket(*packet) == 0) return 0; - parsed = false; - packet->truncate(); - packet->write((UCHAR*)"\200\000\000", 3); - packet->write(buf, datalen); - } - } - } - - if (pid == subID && subActive && subPacket.getLength() == subLength) - { - parsePacketDetails(subPacket); -Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream()); - submitPacket(subPacket); - subActive = false; - } - - return 1; -} - -ULONG DemuxerTS::getPacketNum() -{ - return packetNumber; -} - -ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts) -{ - ULLONG difference = (1LL<<33); - ULONG ref_frame = 0; - int total = 0, actual = 0; - if (pts==0) return 0; //we are in startup - pts_map_mutex.Lock(); - PTSMap::iterator iter = pts_map.begin(); - while (iter != pts_map.end()) - { - ++total; - //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts); - if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE) - { - difference = 0; - ref_frame = iter->frame; - actual = total; - break; - } - ULLONG newdiff = PTSDifference(pts, iter->pts); - if (newdiff < difference) - { - difference = newdiff; - ref_frame = iter->frame; - actual = total; - } - ++iter; - } - if (total > 1 && actual == 1) // We are using the most recent PTS ref. - { // Delete the rest. - iter = pts_map.begin(); iter++; - pts_map.erase(iter, pts_map.end()); - } - pts_map_mutex.Unlock(); - - //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference); - - if (difference == (1LL<<33)) - return 0; // We cannot make sense of the pts - else - return ref_frame + difference * fps / 90000; -} - - -void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas -{ - parsePacketDetails(packet); - if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 && - packet.getPacketType() <= PESTYPE_AUDMAX) - { - packetNumber++; - } - UINT pictsinpacket=packet.countPictureHeaders(h264); - - UINT numpicts=0; - /* if (!doubledframerate) - {*/ - numpicts=pictsinpacket; - /* } - else - { - numpicts=(pictsinpacket+framereserve)>>1; - framereserve=(pictsinpacket+framereserve)%2; - }*/ - - - if (frameCounting && numpicts && - packet.getPacketType() >= PESTYPE_VID0 && - packet.getPacketType() <= PESTYPE_VIDMAX) - { - frameNumber+=numpicts; - ULONG frame_num = frameNumber; - if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS()) - { - PTSMapEntry me; - pts_map_mutex.Lock(); - if (pts_map.empty()) - { - me.pts = packet.getPTS(); - me.frame = frame_num; - pts_map_mutex.Unlock(); - pts_map_mutex.Lock(); - pts_map.push_front(me); - } - me = pts_map.front(); - pts_map_mutex.Unlock(); - - //UINT fps = Video::getInstance()->getFPS(); - double tfps=fps; - // if (doubledframerate) tfps*=2.; - ULLONG pts_expected = me.pts + 90000*((int)(((double)(frame_num - me.frame)) / tfps)); - - while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33); - - // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file - - /* - if (!doubledframerate - &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 - || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) { - doubledframerate=true; //Detected p50 or p60 - }*/ - - if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump! - { - me.pts = packet.getPTS(); - me.frame = frame_num; - pts_map_mutex.Lock(); - pts_map.push_front(me); - pts_map_mutex.Unlock(); - } - } - } -} - - -bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264) -{ - int pmtpidy=0; - - while (len >= TS_SIZE) - { - if (*buf != TS_SIG) {buf++;len--; continue;} - - //Pattern scanning won't work for ts - - - int datalen = TS_SIZE - 4; - int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; - UCHAR payload = buf[1] & 0x40; - - if (buf[3] & 0x20) // Adaptation field is present - datalen -= (buf[4] + 1); - - UCHAR* curbuf =buf+ (TS_SIZE - datalen); - - if (payload) { - if (pid == 0x00) {//PAT, only take first program number, ignore the rest - int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12); - if ((pmtpid >> 13) != 0x07) - { - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); - } - else - { - pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits - pmtpidy = pmtpid; - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid ); - } - - } else if (pid == pmtpidy) { //PMT - int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3); - //sectionlength += 4; //include header but subtract crc in the end... - int p = 13; //skip fixed part of pmt - while ( p < sectionlength) { - int streamtype = *(curbuf+p); - p++; - int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1); - p += 2; //skip ES Pid - int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1); - p += 2; //skip ES length - if ((foundpid >> 13) != 0x07) - { - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); - } - else - { - foundpid = foundpid & 0x1FFF; //clear upper 3 bits - // int pos=0; UNUSED? - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype); - if (streamtype==1 || streamtype ==2) { - ish264=false; - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video"); - return true; - } - if (streamtype==0x1b) { - ish264=true; - Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video"); - return true; - } - } - p += eslength; //skip es descriptor - } - ish264=false; - return false; - } - } - len-=TS_SIZE; - buf+=TS_SIZE; - } - ish264=false; - return false; -} - -UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted -{ - //This function strips all TS Headers and non video payload - UINT readpos=0; - UINT writepos=0; - PESPacket destpaket; - bool started=true; - while (readpos < len ) { - if (buf[readpos] != TS_SIG) {readpos++; continue;} - UINT oldreadpos=readpos; - - int datalen = TS_SIZE - 4; - int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2]; - UCHAR payload = buf[readpos+1] & 0x40; - if (buf[readpos+3] & 0x20) { // Adaptation field is present - datalen -= (buf[readpos+4] + 1); - } - if (datalen < 0) {// Error in stream TODO log this - return 0; - } - if (datalen == 0) {// Null packet - readpos=oldreadpos+TS_SIZE; - continue; - } - readpos += (TS_SIZE - datalen); - UINT towrite=min(datalen,len-readpos); - if (pid == vID) { - if (payload) { - if (started) { - parsePacketDetails(destpaket); - memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); - writepos+=destpaket.getSize(); - } - destpaket.init(PESTYPE_VID0); - readpos += 6; towrite -= 6; - started=true; - } - - if (started) { - if (!destpaket.write(buf+readpos,towrite)) { - parsePacketDetails(destpaket); - memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); - writepos+=destpaket.getSize(); - destpaket.truncate(); - destpaket.write((UCHAR*)"\200\000\000", 3); - destpaket.write(buf+readpos,towrite); - - } - } - - - - } - readpos=oldreadpos+TS_SIZE; - } - parsePacketDetails(destpaket); - memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); - writepos+=destpaket.getSize(); - - return writepos; -} - - - +/* + Copyright 2006-2008 Mark Calderbank + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "demuxerts.h" +#include "log.h" +#include "video.h" +#include "vdr.h" +#include "audio.h" + +#define PTS_JUMP_MARGIN 10000 +#define PTS_ALLOWANCE 90000 + +// TODO: PTS class to handle wrapping arithmetic & comparisons? +static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2) +{ + // Assume pts1, pts2 < 2^33; calculate shortest distance between + ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1; + if (ret > (1LL<<32)) ret = (1LL<<33) - ret; + return ret; +} + +static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2) +{ + // Assume pts1, pts2 < 2^33; calculate pts1 - pts2 + if (pts1 > pts2) + return pts1 - pts2; + else + return (1LL<<33) + pts1 - pts2; +} + +DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID) +{ + vID = p_vID; vActive = false; + aID = p_aID; aActive = false; + subID = p_subID; subActive = false; + atype = 0; + subLength = 0; + tID = p_tID; + havechannelinfo=false; + //doubledframerate=false; + framereserve=0; +} + +void DemuxerTS::flush() +{ + partPacket = 0; + parsed = false; + havechannelinfo=false; + Demuxer::flush(); + vPacket.init(PESTYPE_VID0); + switch (atype) + { + case 1: + aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); + break; + default: + case 0: + aPacket.init(PESTYPE_AUD0); + break; + } + subPacket.init(PESTYPE_PRIVATE_1); +tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); + + vActive = false; + aActive = false; + subActive = false; + subLength = 0; + tActive = false; + // doubledframerate=false; + framereserve=0; +} + +int DemuxerTS::scan(UCHAR *buf, int len) +{ + switch (atype) + { + case 1: + return PESTYPE_PRIVATE_1; + default: + case 0: + return PESTYPE_AUD0; + } +} + +void DemuxerTS::setVID(int p_vID) +{ + vID = p_vID; + vPacket.init(PESTYPE_VID0); + vActive = false; +} + +void DemuxerTS::setAID(int p_aID, int type, int streamtype) +{ + aID = p_aID; + atype = type; + astreamtype = streamtype; + switch (atype) + { + case 1: + aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); + setAudioStream(PESTYPE_SUBSTREAM_AC30); + break; + default: + case 0: + aPacket.init(PESTYPE_AUD0); + setAudioStream(PESTYPE_AUD0); + break; + } + aActive = false; +} + +void DemuxerTS::setSubID(int p_subID) +{ + subID = p_subID; + subPacket.init(PESTYPE_PRIVATE_1); + subActive = false; + subLength = 0; +} + +void DemuxerTS::setTID(int p_tID) +{ + tID = p_tID; + tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); + tActive = false; + +} + + + + +int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest) +{ + int scanaid=0; + + while (len >= TS_SIZE) + { + if (*buf != TS_SIG) {buf++;len--; continue;} + + //Pattern scanning won't work for ts + + + int datalen = TS_SIZE - 4; + int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; + UCHAR payload = buf[1] & 0x40; + + if (buf[3] & 0x20) // Adaptation field is present + datalen -= (buf[4] + 1); + + UCHAR* curbuf =buf+ (TS_SIZE - datalen); + + + if (payload) { + if (pid == 0x00) {//PAT, only take first program number, ignore the rest + int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12); + if ((pmtpid >> 13) != 0x07) + { + Log::getInstance()->log("findPTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); + } + else + { + pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits + PMTPID = pmtpid; + } + + } else if (pid == PMTPID) { //PMT + int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3); + //sectionlength += 4; //include header but subtract crc in the end... + int p = 13; //skip fixed part of pmt + while ( p < sectionlength) { + int streamtype = *(curbuf+p); + p++; + int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1); + p += 2; //skip ES Pid + int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1); + p += 2; //skip ES length + if ((foundpid >> 13) != 0x07) + { + Log::getInstance()->log("findPTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); + } + else + { + foundpid = foundpid & 0x1FFF; //clear upper 3 bits + //int pos=0; UNUSED? + if (streamtype==3 || streamtype ==4) { + scanaid=foundpid; + } + } + p += eslength; //skip es descriptor + } + } else if (pid == scanaid) { + // UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; UNUSED? + + if ( curbuf[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present + { + *dest = ( (ULLONG)(curbuf[9] & 0x0E) << 29 ) | + ( (ULLONG)(curbuf[10]) << 22 ) | + ( (ULLONG)(curbuf[11] & 0xFE) << 14 ) | + ( (ULLONG)(curbuf[12]) << 7 ) | + ( (ULLONG)(curbuf[13] & 0xFE) >> 1 ); + return 1; + } + } + } + len-=TS_SIZE; + buf+=TS_SIZE; + } + // No PTS found. + return 0; +} + +void DemuxerTS::setFrameNum(ULONG frame) +{ + frameCounting = true; + frameNumber = frame; + framereserve=0; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setFrameNum %d", frame); +} + +void DemuxerTS::setPacketNum(ULONG npacket) +{ + packetCounting = true; + packetNumber = npacket; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "setPacketNum %d", npacket); +} + +int DemuxerTS::put(UCHAR* buf, int len) +{ + int ret = 0; // return number of bytes consumed + + bool misaligned_mess=false; + while (partPacket) + { + if (len >= TS_SIZE + 1 - partPacket) + { // Remainder of partial packet is available, plus one + memcpy(store+partPacket, buf, TS_SIZE - partPacket); + ret += TS_SIZE - partPacket; + buf += TS_SIZE - partPacket; + len -= TS_SIZE - partPacket; + partPacket = TS_SIZE; + if (*buf == TS_SIG) + { // Packet is properly terminated + int rc = processTS(store); + if (rc) + partPacket = 0; // Successfully processed + else + return ret; // Try again later. + } + else + { // Packet not terminated. Find another candidate, and shift store + if (!misaligned_mess) { + Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!A"); + misaligned_mess=true; // do not alarm more than once + } + int search = 1; + while (search < partPacket && store[search] != TS_SIG) + search++; + partPacket -= search; + if (partPacket) memcpy(store, store+search, partPacket); + } + } + else + { // Still don't have complete packet. Consume what we do have. + memcpy(store+partPacket, buf, len); + partPacket += len; + ret += len; + return ret; + } + } + + // Position ourselves at a candidate TS packet + while (len > 0 && *buf != TS_SIG) + { + if (!misaligned_mess) { + Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!B"); + misaligned_mess=true; // do not alarm more than once + } + buf++; ret++; len--; + } + + while (len) + { + if (len < TS_SIZE + 1) + { // Not enough data. Store what we have. + memcpy(store, buf, len); + partPacket = len; + ret += len; + return ret; + } + + if (buf[TS_SIZE] != TS_SIG) + { // Not terminated correctly. + buf++; ret++; len--; + while (len > 0 && *buf != TS_SIG) + { + buf++; ret++; len--; + } + } + else + { + int rc = processTS(buf); + if (rc) + { // Successfully processed + buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE; + } + else + { // Processing failed. + return ret; + } + } + } + return ret; +} + + +int DemuxerTS::processTS(UCHAR* buf) +{ + int datalen = TS_SIZE - 4; + + int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; + UCHAR payload = buf[1] & 0x40; + + + if (buf[3] & 0x20) // Adaptation field is present + datalen -= (buf[4] + 1); + if (datalen < 0) // Error in stream TODO log this + return 1; + if (datalen == 0) // Null packet + return 1; + // if (!(buf[3] &0x10)) return 1; // no payload + buf += (TS_SIZE - datalen); + + if (payload) + { + int rc = 1; + if (pid == 0x00) {//PAT, only take first program number, ignore the rest + int pmtpid = (*(buf+11)<< 8) | *(buf+12); + if ((pmtpid >> 13) != 0x07) + { + Log::getInstance()->log("ProcessTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(buf+11),*(buf+12), (pmtpid >> 13)); + } + else + { + pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits + PMTPID = pmtpid; + } + return 1; + } + if (pid == PMTPID) + { //PMT + int sectionlength = ((*(buf+2) << 8) & 0x0F ) | *(buf+3); + //sectionlength += 4; //include header but subtract crc in the end... + int p = 13; //skip fixed part of pmt + Channel new_channelinfo; + new_channelinfo.numAPids=0; + new_channelinfo.numDPids=0; + new_channelinfo.numSPids=0; + new_channelinfo.number=0; + new_channelinfo.type=VDR::RADIO; + new_channelinfo.name=NULL; + new_channelinfo.tpid=0xFFFFF; //unused, check this + new_channelinfo.vpid=0xFFFFF; //unused, check this + new_channelinfo.index=0; + + new_channelinfo.apids.clear(); + new_channelinfo.dpids.clear(); + new_channelinfo.spids.clear(); + + while ( p < sectionlength) { + int streamtype = *(buf+p); + p++; + int foundpid = (*(buf+p)<< 8) | *(buf+p+1); + p += 2; //skip ES Pid + int eslength = ((*(buf+p) << 8) & 0x0F ) | *(buf+p+1); + p += 2; //skip ES length + if ((foundpid >> 13) != 0x07) + { + Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); + } + else + { + foundpid = foundpid & 0x1FFF; //clear upper 3 bits + bool notfound=false; + bool nolang=true; + int pos=0; + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x %x", foundpid,streamtype); + switch (streamtype) + { + case 0x1B: //MPEG 4 for future use + case 1: + case 2: { //video + if (foundpid != getVID()) + setVID(foundpid); + new_channelinfo.type=VDR::VIDEO; + new_channelinfo.vstreamtype=streamtype; + new_channelinfo.vpid=foundpid; + if (streamtype==0x1b) h264=true; + else h264=false; + + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid); + }break; + case 0x0F: //AAC ADTS packaging + case 0x11: // LATM packaging + case 3: + case 4: { //audio + apid newapid; + newapid.pid = foundpid; + newapid.desc[0]=0; + newapid.type=streamtype; + pos=0; + nolang=true; + while (pos< eslength && nolang) { + switch (buf[p+pos]) { + case 0x0A: { + newapid.desc[0]=buf[p+pos+2]; + newapid.desc[1]=buf[p+pos+3]; + newapid.desc[2]=buf[p+pos+4]; + newapid.desc[3]=0; + nolang=false; + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDLANG is %s", newapid.desc); + } break; + }; + + pos+=2+buf[p+pos+1]; + } + + new_channelinfo.apids.push_back(newapid); + new_channelinfo.numAPids++; + if (getAID() == 0 && Audio::getInstance()->streamTypeSupported(streamtype)) { //set unset AID to first audio pid that reports itself + setAID(foundpid,0,streamtype); + Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set audio PID to %x", foundpid); + } + } break; + case 5: + case 6: { //Private Data + apid newapid; + newapid.pid = foundpid; + newapid.desc[0]=0; //set it in player + pos=0; + notfound=true; + nolang=true; + int type=0; + + while (pos< eslength && (notfound || nolang)) { + switch (buf[p+pos]) { + case 0x7A: // Enhanced Ac3 Desriptor + case 0x6A: {//Ac3 descriptor + newapid.type=buf[p+pos]; + type=1; + + notfound=false; + } break; + case 0x59: {//SubtitlingDescriptor + type=2; + newapid.type=buf[p+pos]; + newapid.desc[0]=buf[p+pos+2]; + newapid.desc[1]=buf[p+pos+3]; + newapid.desc[2]=buf[p+pos+4]; + newapid.desc[3]=0; + newapid.data1=(buf[p+pos+5]<<8) |(buf[p+pos+6]); + newapid.data2=(buf[p+pos+7]<<8) |(buf[p+pos+8]); + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDSUB is %s", newapid.desc); + notfound=false; + nolang=false; + } break; + case 0x0A: { + newapid.desc[0]=buf[p+pos+2]; + newapid.desc[1]=buf[p+pos+3]; + newapid.desc[2]=buf[p+pos+4]; + newapid.desc[3]=0; + nolang=false; + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDLANG is %s", newapid.desc); + } break; + case 0x56: { + type=3; + new_channelinfo.tpid=foundpid; + notfound=false; + } break; + }; + pos+=2+buf[p+pos+1]; + } + if (type==1) { + new_channelinfo.dpids.push_back(newapid); + new_channelinfo.numDPids++; + } else if (type==2) { + new_channelinfo.spids.push_back(newapid); + new_channelinfo.numSPids++; + } + + } break; + default://TODO how about subtitles and second audio pids + break; + } + } + + p += eslength; //skip es descriptor + + + } + bool audioPIDpresent=false; //Check if pids chnages + ULONG i; + for (i=0;i0) { + int j=0; + while (jstreamTypeSupported(channelinfo.apids[j].type)) { + found =true; + setAID(channelinfo.apids[j].pid,0,channelinfo.apids[j].type); + } + j++; + } + + } + if (channelinfo.numDPids>0 && !found) { + int j=0; + while (jstreamTypeSupported(channelinfo.dpids[j].type)) { + found =true; + setAID(channelinfo.dpids[j].pid,1,channelinfo.dpids[j].type); + } + i++; + } + } + } + + channelinfo=new_channelinfo; + + + havechannelinfo=true; + + return 1; + } + + + + + if (pid == vID) + { + if (vActive) + { + if (!parsed) + { + parseTSPacketDetails(vPacket); + parsed = true; + } + rc = submitPacket(vPacket); + } + vActive = true; + } + if (pid == aID) + { + if (aActive) + { + if (!parsed) + { + parseTSPacketDetails(aPacket); + parsed = true; + } + rc = submitPacket(aPacket); + } + aActive = true; + } + if (pid == subID) + { + if (subActive) + { + if (!parsed) + { + parseTSPacketDetails(subPacket); + parsed = true; + } + rc = submitPacket(subPacket); + } + subActive = true; + } + if (isteletextdecoded && pid == tID) + { + if (tActive) + { + if (!parsed) + { + parseTSPacketDetails(tPacket); + parsed = true; + } + rc = submitPacket(tPacket); + } + tActive = true; + } + if (rc == 0) return 0; + + parsed = false; + if (pid == vID) + { + vPacket.init(PESTYPE_VID0); + buf += 6; datalen -= 6; + } + if (pid == aID) + { + switch (atype) + { + case 1: + aPacket.init(PESTYPE_PRIVATE_1, PESTYPE_SUBSTREAM_AC30); + break; + default: + case 0: + aPacket.init(PESTYPE_AUD0); + break; + } + buf += 6; datalen -= 6; + } + if (pid == subID) + { + subPacket.init(PESTYPE_PRIVATE_1); + subLength = (buf[4] << 8) + buf[5]; + buf += 6; datalen -= 6; + } + if (isteletextdecoded && pid == tID) + { + tPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_TELETEXTMAX); + buf += 6; datalen -= 6; + } + } + + if ( (pid == vID && vActive) || + (pid == aID && aActive) || + (pid == tID && tActive) || + (pid == subID && subActive) ) + { + PESPacket* packet = NULL; + if (pid == vID) packet = &vPacket; + if (pid == aID) packet = &aPacket; + if (pid == subID) { + packet = &subPacket; + } + if (pid == tID) packet = &tPacket; + if (packet != NULL) + { + if (packet->write(buf, datalen) == 0) + { // Writing to packet failed. It has overflowed. + if (!parsed) + { + parseTSPacketDetails(*packet); + parsed = true; + } + if (submitPacket(*packet) == 0) return 0; + parsed = false; + packet->truncate(); + packet->write((UCHAR*)"\200\000\000", 3); + packet->write(buf, datalen); + } + } + } + + if (pid == subID && subActive && subPacket.getLength() == subLength) + { + parsePacketDetails(subPacket); +Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET %d %x", subLength, subPacket.getSubstream()); + submitPacket(subPacket); + subActive = false; + } + + return 1; +} + +ULONG DemuxerTS::getPacketNum() +{ + return packetNumber; +} + +ULONG DemuxerTS::getFrameNumFromPTS(ULLONG pts) +{ + ULLONG difference = (1LL<<33); + ULONG ref_frame = 0; + int total = 0, actual = 0; + if (pts==0) return 0; //we are in startup + pts_map_mutex.Lock(); + PTSMap::iterator iter = pts_map.begin(); + while (iter != pts_map.end()) + { + ++total; + //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts1 %lld pts2 %lld", pts, iter->pts); + if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE) + { + difference = 0; + ref_frame = iter->frame; + actual = total; + break; + } + ULLONG newdiff = PTSDifference(pts, iter->pts); + if (newdiff < difference) + { + difference = newdiff; + ref_frame = iter->frame; + actual = total; + } + ++iter; + } + if (total > 1 && actual == 1) // We are using the most recent PTS ref. + { // Delete the rest. + iter = pts_map.begin(); iter++; + pts_map.erase(iter, pts_map.end()); + } + pts_map_mutex.Unlock(); + + //Log::getInstance()->log("DemuxerTS", Log::DEBUG, "getFrameNumfromPTS pts %lld deleted %d difference %lld", pts, total,difference); + + if (difference == (1LL<<33)) + return 0; // We cannot make sense of the pts + else + return ref_frame + difference * fps / 90000; +} + + +void DemuxerTS::parseTSPacketDetails(PESPacket &packet) // Only important stuff for paket counting reminas +{ + parsePacketDetails(packet); + if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 && + packet.getPacketType() <= PESTYPE_AUDMAX) + { + packetNumber++; + } + UINT pictsinpacket=packet.countPictureHeaders(h264); + + UINT numpicts=0; + /* if (!doubledframerate) + {*/ + numpicts=pictsinpacket; + /* } + else + { + numpicts=(pictsinpacket+framereserve)>>1; + framereserve=(pictsinpacket+framereserve)%2; + }*/ + + + if (frameCounting && numpicts && + packet.getPacketType() >= PESTYPE_VID0 && + packet.getPacketType() <= PESTYPE_VIDMAX) + { + frameNumber+=numpicts; + ULONG frame_num = frameNumber; + if ((h264 || packet.findSeqHeader(h264) > 1) && packet.hasPTS()) + { + PTSMapEntry me; + pts_map_mutex.Lock(); + if (pts_map.empty()) + { + me.pts = packet.getPTS(); + me.frame = frame_num; + pts_map_mutex.Unlock(); + pts_map_mutex.Lock(); + pts_map.push_front(me); + } + me = pts_map.front(); + pts_map_mutex.Unlock(); + + //UINT fps = Video::getInstance()->getFPS(); + double tfps=fps; + // if (doubledframerate) tfps*=2.; + long long pts_expected = me.pts + 90000LL*((long long)(((double)(frame_num - me.frame)) / tfps)); + + while (pts_expected < 0) pts_expected += (1LL<<33); + while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33); + + // this was a workaround for a vdr bug, now fixed, for older recordings deleter the index file + + /* + if (!doubledframerate + &&(abs((long long)PTSDistance(pts_expected, packet.getPTS())-1800) <= 1 + || abs((long long)PTSDistance(pts_expected, packet.getPTS())-1501) <= 1)) { + doubledframerate=true; //Detected p50 or p60 + }*/ + + if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump! + { + me.pts = packet.getPTS(); + me.frame = frame_num; + pts_map_mutex.Lock(); + pts_map.push_front(me); + pts_map_mutex.Unlock(); + } + } + } +} + + +bool DemuxerTS::scanForVideo(UCHAR* buf, UINT len, bool &ish264) +{ + int pmtpidy=0; + + while (len >= TS_SIZE) + { + if (*buf != TS_SIG) {buf++;len--; continue;} + + //Pattern scanning won't work for ts + + + int datalen = TS_SIZE - 4; + int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; + UCHAR payload = buf[1] & 0x40; + + if (buf[3] & 0x20) // Adaptation field is present + datalen -= (buf[4] + 1); + + UCHAR* curbuf =buf+ (TS_SIZE - datalen); + + if (payload) { + if (pid == 0x00) {//PAT, only take first program number, ignore the rest + int pmtpid = (*(curbuf+11)<< 8) | *(curbuf+12); + if ((pmtpid >> 13) != 0x07) + { + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMTPID=%02x %02x TRAILING 111 not set but %x", *(curbuf+11),*(curbuf+12), (pmtpid >> 13)); + } + else + { + pmtpid = pmtpid & 0x1FFF; //clear upper 3 bits + pmtpidy = pmtpid; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "PMT pid%02x",pmtpid ); + } + + } else if (pid == pmtpidy) { //PMT + int sectionlength = ((*(curbuf+2) << 8) & 0x0F ) | *(buf+3); + //sectionlength += 4; //include header but subtract crc in the end... + int p = 13; //skip fixed part of pmt + while ( p < sectionlength) { + int streamtype = *(curbuf+p); + p++; + int foundpid = (*(curbuf+p)<< 8) | *(curbuf+p+1); + p += 2; //skip ES Pid + int eslength = ((*(curbuf+p) << 8) & 0x0F ) | *(curbuf+p+1); + p += 2; //skip ES length + if ((foundpid >> 13) != 0x07) + { + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "FOUNDPID=%02x %02x TRAILING 111 not set but %x", *(buf+p),*(buf+p+1), (foundpid >> 13)); + } + else + { + foundpid = foundpid & 0x1FFF; //clear upper 3 bits + // int pos=0; UNUSED? + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Pid found %02x type %02x",foundpid ,streamtype); + if (streamtype==1 || streamtype ==2) { + ish264=false; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found Mpeg2 Video"); + return true; + } + if (streamtype==0x1b) { + ish264=true; + Log::getInstance()->log("DemuxerTS", Log::DEBUG, "Found h264 Video"); + return true; + } + } + p += eslength; //skip es descriptor + } + ish264=false; + return false; + } + } + len-=TS_SIZE; + buf+=TS_SIZE; + } + ish264=false; + return false; +} + +UINT DemuxerTS::stripAudio(UCHAR* buf, UINT len) //it has to be adapted +{ + //This function strips all TS Headers and non video payload + UINT readpos=0; + UINT writepos=0; + PESPacket destpaket; + bool started=true; + while (readpos < len ) { + if (buf[readpos] != TS_SIG) {readpos++; continue;} + UINT oldreadpos=readpos; + + int datalen = TS_SIZE - 4; + int pid = ( (buf[readpos+1] & 0x1F) << 8 ) | buf[readpos+2]; + UCHAR payload = buf[readpos+1] & 0x40; + if (buf[readpos+3] & 0x20) { // Adaptation field is present + datalen -= (buf[readpos+4] + 1); + } + if (datalen < 0) {// Error in stream TODO log this + return 0; + } + if (datalen == 0) {// Null packet + readpos=oldreadpos+TS_SIZE; + continue; + } + readpos += (TS_SIZE - datalen); + UINT towrite=min(datalen,len-readpos); + if (pid == vID) { + if (payload) { + if (started) { + parsePacketDetails(destpaket); + memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); + writepos+=destpaket.getSize(); + } + destpaket.init(PESTYPE_VID0); + readpos += 6; towrite -= 6; + started=true; + } + + if (started) { + if (!destpaket.write(buf+readpos,towrite)) { + parsePacketDetails(destpaket); + memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); + writepos+=destpaket.getSize(); + destpaket.truncate(); + destpaket.write((UCHAR*)"\200\000\000", 3); + destpaket.write(buf+readpos,towrite); + + } + } + + + + } + readpos=oldreadpos+TS_SIZE; + } + parsePacketDetails(destpaket); + memcpy(buf+writepos,destpaket.getData(),destpaket.getSize()); + writepos+=destpaket.getSize(); + + return writepos; +} + + + -- 2.39.2