From 90c65f30d6391bdf62fa8a3d077007eb87e2529d Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sat, 30 May 2009 14:30:47 +0000 Subject: [PATCH] VDR 1.7.7 compatibility --- demuxer.h | 6 +- demuxerts.cc | 511 ++++++++++++++++++++++++++++++++++++++++++++++--- demuxerts.h | 32 +++- player.cc | 45 ++++- player.h | 7 +- playerradio.cc | 7 +- playerradio.h | 2 +- recording.cc | 9 +- recording.h | 1 + vdr.cc | 11 +- vdr.h | 2 +- videowin.cc | 8 +- vradiorec.cc | 6 +- vvideorec.cc | 157 ++++++++++++--- 14 files changed, 721 insertions(+), 83 deletions(-) diff --git a/demuxer.h b/demuxer.h index bef9e79..54cd1b3 100644 --- a/demuxer.h +++ b/demuxer.h @@ -88,6 +88,8 @@ class Demuxer void flushAudio(); void seek(); void setVideoStream(int id); + //TODO HANS next virtual necessary? + //virtual void setAudioStream(int id); void setAudioStream(int id); void setTeletextStream(int id); void setDVBSubtitleStream(int id); @@ -125,8 +127,8 @@ class Demuxer // Remove all data from a buffer apart from video PES packets. // Returns the length of the reduced data. - // *static function* - static UINT stripAudio(UCHAR* buf, UINT len); + // removed *static function*, due to DemuxerTS + virtual UINT stripAudio(UCHAR* buf, UINT len); // Scan a buffer to see if video packets are present. // Returns true if video exists; false if not. diff --git a/demuxerts.cc b/demuxerts.cc index 9738e6b..252aa64 100644 --- a/demuxerts.cc +++ b/demuxerts.cc @@ -20,6 +20,29 @@ #include "demuxerts.h" #include "log.h" +#include "video.h" +#include "vdr.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) { @@ -29,12 +52,14 @@ DemuxerTS::DemuxerTS(int p_vID, int p_aID, int p_subID, int p_tID) atype = 0; subLength = 0; tID = p_tID; + havechannelinfo=false; } void DemuxerTS::flush() { partPacket = 0; parsed = false; + havechannelinfo=false; Demuxer::flush(); vPacket.init(PESTYPE_VID0); switch (atype) @@ -111,36 +136,104 @@ void DemuxerTS::setTID(int p_tID) } -int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest) -{ - UINT LoPattern = 0x100 | PESTYPE_VID0, - HiPattern = 0x100 | PESTYPE_VIDMAX; - while (len >= 14) - { - UINT pattern = *(UINT*)buf; - buf++; len--; - if (pattern < LoPattern || pattern > HiPattern) continue; - UINT framelength = ((UINT)buf[3] << 8) | buf[4]; - buf += 5; len -= 5; - if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present - { - *dest = ( (ULLONG)(buf[3] & 0x0E) << 29 ) | - ( (ULLONG)(buf[4]) << 22 ) | - ( (ULLONG)(buf[5] & 0xFE) << 14 ) | - ( (ULLONG)(buf[6]) << 7 ) | - ( (ULLONG)(buf[7] & 0xFE) >> 1 ); - return 1; - } +int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest) +{ + int scanaid=0; - buf += framelength; len -= framelength; + 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; + if (streamtype==3 || streamtype ==4) { + scanaid=foundpid; + } + } + p += eslength; //skip es descriptor + } + } else if (pid == scanaid) { + UINT framelength = ((UINT)curbuf[4] << 8) | curbuf[5]; + + 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; + 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 @@ -225,6 +318,7 @@ int DemuxerTS::put(UCHAR* buf, int len) int DemuxerTS::processTS(UCHAR* buf) { int datalen = TS_SIZE - 4; + int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2]; UCHAR payload = buf[1] & 0x40; @@ -238,7 +332,147 @@ int DemuxerTS::processTS(UCHAR* buf) if (payload) { - int rc = 1; + 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=NULL; + + 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; + int pos=0; + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "FOUNDPID is %x", foundpid); + 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.vpid=foundpid; + + // Log::getInstance()->log("ProcessTS", Log::DEBUG, "Set video PID to %x", foundpid); + }break; + case 3: + case 4: { //audio + apid newapid; + newapid.pid = foundpid; + newapid.name = NULL; //set it in player + new_channelinfo.apids.push_back(newapid); + new_channelinfo.numAPids++; + if (getAID() == 0) { //set unset AID to first audio pid that reports itself + setAID(foundpid,0); + 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.name = NULL; //set it in player + pos=0; + notfound=true; + + while (pos< eslength && notfound) { + switch (buf[p+pos]) { + case 0x6A: {//Ac3 descriptor + new_channelinfo.dpids.push_back(newapid); + new_channelinfo.numDPids++; + notfound=false; + } break; + case 0x59: {//SubtitlingDescriptor + new_channelinfo.spids.push_back(newapid); + new_channelinfo.numSPids++; + notfound=false; + } break; + case 0x56: { + new_channelinfo.tpid=foundpid; + notfound=false; + } break; + }; + pos+=2+buf[p+pos+1]; + } + + } break; + default://TODO how about subtitles and second audio pids + break; + } + } + + p += eslength; //skip es descriptor + + + } + bool audioPIDpresent=false; //Check if pids chnages + int i; + for (i=0;i0) { + setAID(channelinfo.apids[0].pid,0); + } else if (channelinfo.numDPids>0) { + setAID(channelinfo.dpids[0].pid,1); + } + } + + channelinfo=new_channelinfo; + havechannelinfo=true; + + return 1; + } + + + if (pid == vID) { @@ -246,7 +480,7 @@ int DemuxerTS::processTS(UCHAR* buf) { if (!parsed) { - parsePacketDetails(vPacket); + parseTSPacketDetails(vPacket); parsed = true; } rc = submitPacket(vPacket); @@ -259,7 +493,7 @@ int DemuxerTS::processTS(UCHAR* buf) { if (!parsed) { - parsePacketDetails(aPacket); + parseTSPacketDetails(aPacket); parsed = true; } rc = submitPacket(aPacket); @@ -272,7 +506,7 @@ int DemuxerTS::processTS(UCHAR* buf) { if (!parsed) { - parsePacketDetails(subPacket); + parseTSPacketDetails(subPacket); parsed = true; } rc = submitPacket(subPacket); @@ -285,7 +519,7 @@ int DemuxerTS::processTS(UCHAR* buf) { if (!parsed) { - parsePacketDetails(tPacket); + parseTSPacketDetails(tPacket); parsed = true; } rc = submitPacket(tPacket); @@ -345,7 +579,7 @@ int DemuxerTS::processTS(UCHAR* buf) { // Writing to packet failed. It has overflowed. if (!parsed) { - parsePacketDetails(*packet); + parseTSPacketDetails(*packet); parsed = true; } if (submitPacket(*packet) == 0) return 0; @@ -367,3 +601,226 @@ Log::getInstance()->log("DEMUXERTS", Log::DEBUG, "SUBMITTING A SUBTITLE PACKET % 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; + pts_map_mutex.Lock(); + PTSMap::iterator iter = pts_map.begin(); + while (iter != pts_map.end()) + { + ++total; + 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(); + + if (difference == (1LL<<33)) + return 0; // We cannot make sense of the pts + else + return ref_frame + difference * Video::getInstance()->getFPS() / 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++; + } + + if (frameCounting && packet.findPictureHeader() && + packet.getPacketType() >= PESTYPE_VID0 && + packet.getPacketType() <= PESTYPE_VIDMAX) + { + ULONG frame_num = (frameNumber)++; + if (packet.findSeqHeader() > 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(); + ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps; + while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33); + + 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) +{ + 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("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 + pmtpidy = 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("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; + if (streamtype==1 || streamtype ==2) { + return true; + } + } + p += eslength; //skip es descriptor + } + return false; + } + } + len-=TS_SIZE; + buf+=TS_SIZE; + } + 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; +} + + + diff --git a/demuxerts.h b/demuxerts.h index e1f1923..b65c29e 100644 --- a/demuxerts.h +++ b/demuxerts.h @@ -21,8 +21,12 @@ #ifndef DEMUXERTS_H #define DEMUXERTS_H +#include "mutex.h" +#include + #include "demuxer.h" #include "defines.h" +#include "channel.h" #define TS_SIZE 188 #define TS_SIG 0x47 @@ -43,6 +47,15 @@ class DemuxerTS : public Demuxer int getAID() { return aID; } int getSubID() { return subID; } int put(UCHAR* buf, int len); + int PMTPID; //TODO HANS which of these do I Need: + void setFrameNum(ULONG frame); + void setPacketNum(ULONG npacket); + ULONG getFrameNumFromPTS(ULLONG pts); + ULONG getPacketNum(); + UINT stripAudio(UCHAR* buf, UINT len); + static bool scanForVideo(UCHAR* buf, UINT len); + Channel getChannelInfo() {return channelinfo;}; + private: int processTS(UCHAR* buf); @@ -58,8 +71,23 @@ class DemuxerTS : public Demuxer int atype; bool subActive; // Same for subtitles - UINT subLength; // Expected length of subtitle packet -bool vActive, aActive, tActive; // Whether video/audio is actively being captured + UINT subLength; // Expected length of subtitle packet + bool vActive, aActive, tActive; // Whether video/audio is actively being captured + + bool havechannelinfo; + Channel channelinfo; + + + //TODO HANS which of next do I need + ULONG frameNumber, packetNumber; + bool frameCounting, packetCounting; + typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry; + typedef std::deque PTSMap; + PTSMap pts_map; + Mutex pts_map_mutex; + void parseTSPacketDetails(PESPacket packet); + + }; #endif diff --git a/player.cc b/player.cc index 9400d0e..f68ae01 100644 --- a/player.cc +++ b/player.cc @@ -52,6 +52,7 @@ Player::Player(MessageQueue* tmessageQueue, void* tmessageReceiver, OSDReceiver* currentFrameNumber = 0; state = S_STOP; ifactor = 4; + is_pesrecording=true; subtitlesShowing = false; @@ -68,7 +69,7 @@ Player::~Player() if (initted) shutdown(); } -int Player::init() +int Player::init(bool isPesRecording) { if (initted) return 0; #ifndef WIN32 @@ -76,8 +77,11 @@ int Player::init() #else mutex=CreateMutex(NULL,FALSE,NULL); #endif - - demuxer = new DemuxerVDR(); + is_pesrecording=isPesRecording; + if (isPesRecording) + demuxer = new DemuxerVDR(); + else + demuxer = new DemuxerTS(); if (!demuxer) return 0; subtitles = new DVBSubtitles(osdReceiver); if (!subtitles) return 0; @@ -181,17 +185,29 @@ bool* Player::getDemuxerSubtitleChannels() int Player::getCurrentAudioChannel() { - return demuxer->getselAudioChannel(); + if (is_pesrecording) { + return demuxer->getselAudioChannel(); + } else { + return ((DemuxerTS*)demuxer)->getAID(); + } } int Player::getCurrentSubtitleChannel() { - return demuxer->getselSubtitleChannel(); + if (is_pesrecording) { + return demuxer->getselSubtitleChannel(); + } else { + return ((DemuxerTS*)demuxer)->getSubID(); + } } void Player::setSubtitleChannel(int newChannel) { - return demuxer->setDVBSubtitleStream(newChannel); + if (is_pesrecording) { + return demuxer->setDVBSubtitleStream(newChannel); + } else { + return ((DemuxerTS*)demuxer)->setSubID(newChannel); + } } int *Player::getTeletxtSubtitlePages() @@ -201,7 +217,13 @@ int *Player::getTeletxtSubtitlePages() void Player::setAudioChannel(int newChannel, int type) { - demuxer->setAudioStream(newChannel); + if (is_pesrecording) { + demuxer->setAudioStream(newChannel); + return; + } else { + ((DemuxerTS*)demuxer)->setAID(newChannel,type); + return; + } } bool Player::toggleSubtitles() @@ -233,6 +255,14 @@ void Player::turnSubtitlesOn(bool ison) { } +Channel Player::getDemuxerChannel() { + if (!is_pesrecording) { + return ((DemuxerTS*) demuxer)->getChannelInfo(); + } + return Channel(); //Should not happen! +} + + // ----------------------------------- Externally called events void Player::play() @@ -1149,6 +1179,7 @@ void Player::threadFeedScan() { // Fetch I-frames until we get one that can be displayed in good time // Repeat while clock0 + total_msec > clock2 + frameTimeOffset + baseFrameNumber = currentFrameNumber; do { diff --git a/player.h b/player.h index 3db0a11..b339e8f 100644 --- a/player.h +++ b/player.h @@ -50,6 +50,7 @@ class Log; class Demuxer; class OSDReceiver; class DVBSubtitles; +class Channel; class Player : public Thread_TYPE, public Callback { @@ -57,7 +58,7 @@ class Player : public Thread_TYPE, public Callback Player(MessageQueue* messageQueue, void* messageReceiver, OSDReceiver* osdReceiver); virtual ~Player(); - int init(); + int init(bool IsPesRecording); int shutdown(); void setStartFrame(ULONG frameNum); void setLengthBytes(ULLONG length); @@ -89,6 +90,8 @@ class Player : public Thread_TYPE, public Callback int *getTeletxtSubtitlePages(); int getCurrentAudioChannel(); int getCurrentSubtitleChannel(); + bool isPesRecording() {return is_pesrecording;}; + Channel getDemuxerChannel(); TeletextDecoderVBIEBU * getTeletextDecoder(){return teletext;}; @@ -153,6 +156,8 @@ class Player : public Thread_TYPE, public Callback bool startup; bool videoStartup; + bool is_pesrecording; + #ifndef WIN32 pthread_mutex_t mutex; #else diff --git a/playerradio.cc b/playerradio.cc index ddd15ba..cdb10e3 100644 --- a/playerradio.cc +++ b/playerradio.cc @@ -62,7 +62,7 @@ PlayerRadio::~PlayerRadio() if (initted) shutdown(); } -int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets) +int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets, bool isPesRecording) { if (initted) return 0; #ifndef WIN32 @@ -71,7 +71,10 @@ int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets) mutex=CreateMutex(NULL,FALSE,NULL); #endif - demuxer = new DemuxerVDR(); + if (isPesRecording) + demuxer = new DemuxerVDR(); + else + demuxer = new DemuxerTS(); if (!demuxer) return 0; if (!demuxer->init(this, audio, NULL, NULL, 0, 40000, 0)) diff --git a/playerradio.h b/playerradio.h index 3460a8f..dbfe1bb 100644 --- a/playerradio.h +++ b/playerradio.h @@ -50,7 +50,7 @@ class PlayerRadio : public Thread_TYPE, public Callback PlayerRadio(MessageQueue* messageQueue, void* messageReceiver); virtual ~PlayerRadio(); - int init(ULLONG lengthBytes, ULONG lengthPackets); + int init(ULLONG lengthBytes, ULONG lengthPackets, bool IsPesRecording); int shutdown(); void setStartBytes(ULLONG startBytes); diff --git a/recording.cc b/recording.cc index 9e8bdd3..c0e2f2a 100644 --- a/recording.cc +++ b/recording.cc @@ -24,6 +24,7 @@ #include "mark.h" #include "log.h" #include "demuxer.h" +#include "demuxerts.h" #include "command.h" Recording* Recording::recInfoFor = NULL; @@ -124,7 +125,7 @@ void Recording::loadMarks() bool Recording::isRadio() { ULONG lengthFrames = 0; - ULLONG lengthBytes = vdr->streamRecording(getFileName(), &lengthFrames); + ULLONG lengthBytes = vdr->streamRecording(getFileName(), &lengthFrames, &IsPesRecording); if (!lengthBytes || !lengthFrames) return false; UINT thisRead; @@ -137,7 +138,11 @@ bool Recording::isRadio() return false; } - bool hasVideo = Demuxer::scanForVideo(buffer, thisRead); + bool hasVideo = false; + if (IsPesRecording) + hasVideo = Demuxer::scanForVideo(buffer, thisRead); + else + hasVideo = DemuxerTS::scanForVideo(buffer, thisRead); free(buffer); diff --git a/recording.h b/recording.h index a79dc26..e114281 100644 --- a/recording.h +++ b/recording.h @@ -48,6 +48,7 @@ class Recording void dropRecInfo(); bool isRadio(); + bool IsPesRecording; void loadMarks(); int getPrevMark(int currentFrame); diff --git a/vdr.cc b/vdr.cc index 126b044..5bd4fdd 100644 --- a/vdr.cc +++ b/vdr.cc @@ -819,7 +819,7 @@ UCHAR* VDR::getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived) return toReturn; } -ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames) +ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames, bool* IsPesRecording) { VDR_RequestPacket vrp; if (!vrp.init(VDR_STREAMRECORDING, true, strlen(fileName) + 1)) return 0; @@ -830,11 +830,14 @@ ULLONG VDR::streamRecording(char* fileName, ULONG* totalFrames) ULLONG lengthBytes = vresp->extractULLONG(); ULONG lengthFrames = vresp->extractULONG(); + UCHAR isPesRecording = vresp->extractUCHAR(); delete vresp; - logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu", lengthBytes, lengthFrames); - *totalFrames = lengthFrames; + *IsPesRecording = (isPesRecording);//convert Uchar to bool + + logger->log("VDR", Log::DEBUG, "VDR said length is: %llu %lu, IsPesRecording %x", lengthBytes, lengthFrames, *IsPesRecording); + return lengthBytes; } @@ -895,7 +898,7 @@ bool VDR::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePositio delete vresp; -// logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength); + logger->log("VDR", Log::DEBUG, "VDR GNIF said %llu %lu %lu", *rfilePosition, *rframeNumber, *rframeLength); return true; } diff --git a/vdr.h b/vdr.h index 8e9313a..8bed05e 100644 --- a/vdr.h +++ b/vdr.h @@ -158,7 +158,7 @@ class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider RecInfo* getRecInfo(char* fileName); int deleteRecording(char* fileName); char* moveRecording(char* fileName, char* newPath); - ULLONG streamRecording(char* fileName, ULONG* lengthFrames); + ULLONG streamRecording(char* fileName, ULONG* lengthFrames, bool* IsPesRecording); ULLONG positionFromFrameNumber(ULONG frameNumber); ULONG frameNumberFromPosition(ULLONG position); bool getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength); diff --git a/videowin.cc b/videowin.cc index 7834751..1f1b635 100644 --- a/videowin.cc +++ b/videowin.cc @@ -1405,7 +1405,6 @@ void VideoWin::SetAudioVolume(long volume) void VideoWin::displayIFrame(const UCHAR* buffer, UINT length) { if (!iframemode) EnterIframePlayback(); - if (!isdsinited()) return ; #ifdef DO_VIDEO IMediaSample* ms=NULL; @@ -1433,8 +1432,10 @@ void VideoWin::displayIFrame(const UCHAR* buffer, UINT length) while (read_pos + 7 <= length) { pattern = ((pattern << 8) & 0xFFFFFFFF) | buffer[read_pos+3]; - if (pattern < 0x000001E0 || pattern > 0x000001EF) + if (pattern < 0x000001E0 || pattern > 0x000001EF) { read_pos++; + continue; + } else { headerstrip=buffer[read_pos+8]+9/*is this right*/; @@ -1443,7 +1444,8 @@ void VideoWin::displayIFrame(const UCHAR* buffer, UINT length) read_pos = length; else { - if ((write_pos+packet_length-headerstrip)>ms_length) { + if ( (headerstrip < packet_length) && + (write_pos+packet_length-headerstrip)>ms_length) { if (first) { ms->SetSyncPoint(TRUE); ms->SetDiscontinuity(TRUE); diff --git a/vradiorec.cc b/vradiorec.cc index 9077665..3308bb4 100644 --- a/vradiorec.cc +++ b/vradiorec.cc @@ -119,12 +119,14 @@ void VRadioRec::go() { Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName()); ULONG lengthFrames = 0; - ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames); + bool isPesRecording; + ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording); + myRec->IsPesRecording = isPesRecording; bool cantStart = false; if (!lengthBytes) cantStart = true; - else if (!player->init(lengthBytes, lengthFrames)) cantStart = true; + else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true; else { doBar(0); diff --git a/vvideorec.cc b/vvideorec.cc index e5c1bc0..eaea08b 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -39,6 +39,7 @@ #include "bitmap.h" #include "recinfo.h" #include "log.h" +#include "channel.h" VVideoRec::VVideoRec(Recording* rec) { @@ -49,12 +50,12 @@ VVideoRec::VVideoRec(Recording* rec) vas = NULL; vsummary = NULL; - player = new Player(Command::getInstance(), this, this); - player->init(); - videoMode = video->getMode(); myRec = rec; + player = new Player(Command::getInstance(), this, this); + player->init(myRec->IsPesRecording); + playing = false; startMargin = 0; @@ -165,7 +166,9 @@ void VVideoRec::go(bool resume) Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum); ULONG lengthFrames = 0; - ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames); + bool isPesRecording; + ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording); + myRec->IsPesRecording = isPesRecording; if (lengthBytes) { player->setLengthBytes(lengthBytes); @@ -629,33 +632,129 @@ void VVideoRec::toggleChopSides() void VVideoRec::doAudioSelector() { - bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels(); - bool* availableAc3AudioChannels = NULL; - bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels(); - int *availableTTxtpages = player->getTeletxtSubtitlePages(); - int currentAudioChannel = player->getCurrentAudioChannel(); - if (Audio::getInstance()->supportsAc3()) - { - availableAc3AudioChannels = player->getDemuxerAc3AudioChannels(); - } - int subtitleChannel=player->getCurrentSubtitleChannel(); - int subtitleType=0x10; - if (!(player)->isSubtitlesOn()) { - if ((player)->getTeletextDecoder()->getTeletxtView() && - (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() - ) { - subtitleChannel=(player)->getTeletextDecoder()->getPage(); - subtitleType=0x11; - - } else { - subtitleType=0xFF; //turnedOff - subtitleChannel=0; - } - } + int subtitleChannel=player->getCurrentSubtitleChannel(); + int subtitleType=0x10; + if (!(player)->isSubtitlesOn()) { + if ((player)->getTeletextDecoder()->getTeletxtView() && + (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() + ) { + subtitleChannel=(player)->getTeletextDecoder()->getPage(); + subtitleType=0x11; + + } else { + subtitleType=0xFF; //turnedOff + subtitleChannel=0; + } + } + if (player->isPesRecording()) { + bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels(); + bool* availableAc3AudioChannels = NULL; + bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels(); + int *availableTTxtpages = player->getTeletxtSubtitlePages(); + int currentAudioChannel = player->getCurrentAudioChannel(); + if (Audio::getInstance()->supportsAc3()) + { + availableAc3AudioChannels = player->getDemuxerAc3AudioChannels(); + } + + vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages, + subtitleChannel, subtitleType, myRec->recInfo); + } else { + // Draw the selector + Channel temp_channel=player->getDemuxerChannel(); + RecInfo *cur_info= myRec->recInfo; + unsigned char numchan_recinfo = cur_info->numComponents; + unsigned char numchan_subtitles_siz = temp_channel.numSPids; + int mp_audcounter = 0; + int ac3_counter = 0; + int dvb_subcounter = 1; + + unsigned char type; + char* lang; + char* description; + int i; + for (i = 0; i < numchan_recinfo; i++) + { + apid *ac=NULL; + type = cur_info->types[i]; + lang = cur_info->languages[i]; + description = cur_info->descriptions[i]; + + + if (cur_info->streams[i] == 2) { + switch (type) + { + case 1: //mpaudio mono + case 3: //mpaudio stereo + if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter]; + + mp_audcounter++; + break; + case 5: //ac3 + if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter]; + ac3_counter++; + break; + } + } else if (cur_info->streams[i] == 3){ + if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter]; + } else continue; //neither audio nor subtitle + if (ac) + { + if (description && (strlen(description) > 0)) + { + ac->name = new char[strlen(description) + 1]; + strcpy(ac->name, description); + + } else if (lang && strlen(lang) > 0) + { + ac->name = new char[strlen(lang) + 1]; + strcpy(ac->name, lang); + + } + } + } + for (i=0;iname==NULL) { + ac->name = new char[strlen(tr("unknown")) + 1]; + strcpy(ac->name, tr("unknown")); + } + } + for (i=0;iname==NULL) { + ac->name = new char[strlen(tr("unknown")) + 1]; + strcpy(ac->name, tr("unknown")); + } + } + for (i=0;iname==NULL) { + ac->name = new char[strlen(tr("unknown")) + 1]; + strcpy(ac->name, tr("unknown")); + } + } + + vas = new VAudioSelector(this,&temp_channel , (player)->getCurrentAudioChannel(), + subtitleType,subtitleChannel,player->getTeletxtSubtitlePages()); + for (i=0;iname; + ac->name=NULL; + } + for (i=0;iname; + ac->name=NULL; + } + for (i=0;iname; + ac->name=NULL; + } + } - vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages, - subtitleChannel, subtitleType, myRec->recInfo); vas->setBackgroundColour(barBlue); vas->setPosition(0, barRegion.y - 120); -- 2.39.2