From ec7ed6e9b5bde153eabf81a57741939826898997 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 11 Jun 2006 18:33:14 +0000 Subject: [PATCH 01/16] Player now sets frame number to Demuxer --- player.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/player.cc b/player.cc index 3b76c3b..82c28f3 100644 --- a/player.cc +++ b/player.cc @@ -146,7 +146,7 @@ void Player::setLengthFrames(ULONG length) logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames); } -ULLONG Player::getEndTS() // used internally (jump to percent) +ULLONG Player::getEndTS() // FIXME delme - used only by bar clocks until current frame code is done { long long rendTS = endTS - startTS; if (rendTS < 0) rendTS += 8589934592ULL; @@ -270,6 +270,7 @@ int Player::playInt(bool* doUnlock) audio->reset(); video->reset(); demuxer->reset(); + demuxer->setFrameNum(0); if (!isRadio) demuxer->seek(); videoStartup = true; @@ -493,6 +494,7 @@ void Player::restartAt(ULLONG timecode) demuxer->flush(); if (!isRadio) demuxer->seek(); feedPosition = newPosition; + demuxer->setFrameNum(wantedFrameNumber); videoStartup = true; afeed.start(); vfeed.start(); @@ -523,6 +525,7 @@ void Player::restartAtFrame(ULONG newFrame) demuxer->flush(); if (!isRadio) demuxer->seek(); feedPosition = newPosition; + demuxer->setFrameNum(newFrame); videoStartup = true; afeed.start(); vfeed.start(); -- 2.39.5 From cbbf7675610653ccb8c752516c151c39d6075fe9 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Sun, 11 Jun 2006 19:55:08 +0000 Subject: [PATCH 02/16] Demuxer frame counting, second step --- demuxer.h | 1 + demuxervdr.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++++++--- demuxervdr.h | 6 +++++- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/demuxer.h b/demuxer.h index 188cb37..a30ad52 100644 --- a/demuxer.h +++ b/demuxer.h @@ -86,6 +86,7 @@ protected: virtual int put(UCHAR* buf, int len,ULLONG cur_pos) = 0; #endif virtual void setFrameNum(ULONG frame) {} + virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;} int getHorizontalSize() { return horizontal_size; } int getVerticalSize() { return vertical_size; } diff --git a/demuxervdr.cc b/demuxervdr.cc index ba9278e..9bdf7ba 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -34,6 +34,8 @@ #endif #define PTSMAP_MAXENTRIES 300 +#define PTSMAP_THRESHOLD 90000 // One second + // ISO standard demands at least one PTS every 0.7 seconds DemuxerVDR::DemuxerVDR() { @@ -118,6 +120,7 @@ void DemuxerVDR::setFrameNum(ULONG frame) { frameCounting = true; frameNumber = frame; + Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame); } #ifndef NEW_DEMUXER @@ -244,16 +247,59 @@ int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos) return ret; } +ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) +{ + ULONG ret; + pthread_mutex_lock(&pts_map_mutex); + PTSMap::const_iterator iter = pts_map.begin(); + bool onTarget = false; + while (iter != pts_map.end()) + { + bool inRange; + if (pts < PTSMAP_THRESHOLD) + inRange = (iter->pts <= pts || + iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD + pts); + else + inRange = (iter->pts <= pts && + iter->pts >= pts - PTSMAP_THRESHOLD); + if (onTarget) + { + if (!inRange) break; // We have hit the target + } + else + { + if (inRange) onTarget = true; // We are hot on the trail + } + ++iter; + } + --iter; + if (onTarget) ret = iter->frame; + pthread_mutex_unlock(&pts_map_mutex); + if (!onTarget) + return 0; + else + return ret; +} + void DemuxerVDR::PESPacketVDR::parseDetails() { + // TODO: Currently, we naïvely assume that a packet contains a new frame + // if and only if it contains a pts, and that no packet contains more + // than one new frame + DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance()); PESPacket::parseDetails(); - if (dx->frameCounting && pts != PTS_INVALID) + if (dx->frameCounting && pts != PTS_INVALID && + packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX) { PTSMapEntry me; me.pts = pts; me.frame = dx->frameNumber; - dx->PTSMap.push_back(me); - if (dx->PTSMap.size() == PTSMAP_MAXENTRIES) dx->PTSMap.pop_front(); + Log::getInstance()->log("Demuxer", Log::DEBUG, "Map %llu %u", me.pts, me.frame); + pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map.push_back(me); + if (dx->pts_map.size() == PTSMAP_MAXENTRIES) dx->pts_map.pop_front(); + pthread_mutex_unlock(&(dx->pts_map_mutex)); + ++(dx->frameNumber); } } diff --git a/demuxervdr.h b/demuxervdr.h index e8e186a..4194fe0 100644 --- a/demuxervdr.h +++ b/demuxervdr.h @@ -21,6 +21,7 @@ #ifndef DEMUXERVDR_H #define DEMUXERVDR_H +#include "pthread.h" #include #include "demuxer.h" #include "defines.h" @@ -44,6 +45,7 @@ class DemuxerVDR : public Demuxer int put(UCHAR* buf, int len,ULLONG cur_pos); #endif void setFrameNum(ULONG frame); + ULONG getFrameNumFromPTS(ULLONG pts); private: int state; @@ -54,7 +56,9 @@ class DemuxerVDR : public Demuxer ULONG frameNumber; bool frameCounting; typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry; - std::deque PTSMap; + typedef std::deque PTSMap; + PTSMap pts_map; + pthread_mutex_t pts_map_mutex; }; #endif -- 2.39.5 From 41d616a1fbe21b047619e68c690e878653a78330 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 11 Jun 2006 20:18:59 +0000 Subject: [PATCH 03/16] Major switch to frame number navigation --- player.cc | 41 ++++++++++++-------- player.h | 11 +++--- readme.win | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ video.cc | 6 +++ video.h | 1 + vvideorec.cc | 41 ++++++++------------ 6 files changed, 158 insertions(+), 47 deletions(-) create mode 100644 readme.win diff --git a/player.cc b/player.cc index 82c28f3..66a31d1 100644 --- a/player.cc +++ b/player.cc @@ -39,8 +39,8 @@ Player::Player(MessageQueue* messageQueue, bool tIsRecording, bool tIsRadio) feedPosition = 0; feedMode = MODE_NORMAL; lastRescan = 0; - startTS = 0; - endTS = 0; +// startTS = 0; +// endTS = 0; videoStartup = false; preBuffering = false; @@ -146,24 +146,31 @@ void Player::setLengthFrames(ULONG length) logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames); } +/* ULLONG Player::getEndTS() // FIXME delme - used only by bar clocks until current frame code is done { long long rendTS = endTS - startTS; if (rendTS < 0) rendTS += 8589934592ULL; return (ULLONG)rendTS; } +*/ +/* hmsf Player::getEndHMSF() { return video->framesToHMSF(lengthFrames); } +*/ -ULLONG Player::getPositionTS() // used internall (skip fw/bw) +ULONG Player::getLengthFrames() { - if (startup) return 0ULL; - long long currentTS = video->getCurrentTimestamp() - startTS; - if (currentTS < 0) currentTS += 8589934592ULL; - return (ULLONG)currentTS; + return lengthFrames; +} + +ULONG Player::getCurrentFrameNum() +{ + if (startup) return 0; + return demuxer->getFrameNumFromPTS(video->getCurrentTimestamp()); } // ----------------------------------- Externally called events @@ -433,21 +440,21 @@ void Player::toggleFastBackwardInt() void Player::skipForwardInt(int seconds) { logger->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); - restartAt(getPositionTS() + (seconds * 90000)); + restartAtFrame(getCurrentFrameNum() + (seconds * video->getFPS())); } void Player::skipBackwardInt(int seconds) { logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); - long long newTimeCode = getPositionTS() - (seconds * 90000); - if (newTimeCode < 0) newTimeCode = 0; - restartAt(newTimeCode); + long newFrameNum = getCurrentFrameNum() + (seconds * video->getFPS()); + if (newFrameNum < 0) newFrameNum = 0; + restartAt(newFrameNum); } void Player::jumpToPercentInt(int percent) { logger->log("Player", Log::DEBUG, "JUMP TO %i%%", percent); - ULONG newFrame = (ULONG)(((float)percent / 100) * lengthFrames); + ULONG newFrame = percent * lengthFrames / 100; restartAtFrame(newFrame); } @@ -538,6 +545,7 @@ void Player::restartAtFrame(ULONG newFrame) fbwd = false; } +/* void Player::setStartTS(UINT dataInBuffer) { #ifndef NEW_DEMUXER @@ -561,7 +569,9 @@ void Player::setStartTS(UINT dataInBuffer) startTS=0; #endif } +*/ +/* void Player::setEndTS() { logger->log("Player", Log::DEBUG, "Setting end TS"); @@ -578,6 +588,7 @@ void Player::setEndTS() #endif logger->log("Player", Log::DEBUG, "Set end TS"); } +*/ void Player::doConnectionLost() { @@ -664,7 +675,7 @@ void Player::threadMethod() if (!vdr->isConnected()) { doConnectionLost(); return; } logger->log("Player", Log::DEBUG, "Rescanned and reset length: %llu", lengthBytes); lastRescan = time(NULL); - setEndTS(); +// setEndTS(); } if (lengthBytes) // is playing a recording @@ -712,9 +723,9 @@ void Player::threadMethod() demuxer->setAudioStream(a_stream); logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream); - setStartTS(thisRead); +// setStartTS(thisRead); - if (isRecording) setEndTS(); +// if (isRecording) setEndTS(); startup = false; } diff --git a/player.h b/player.h index 96e599e..cf25d4e 100644 --- a/player.h +++ b/player.h @@ -64,9 +64,10 @@ class Player : public Thread_TYPE, public Callback bool isPaused() { return paused; } bool isFfwd() { return ffwd; } bool isFbwd() { return fbwd; } - ULLONG getPositionTS(); - ULLONG getEndTS(); - hmsf getEndHMSF(); + ULONG getCurrentFrameNum(); + ULONG getLengthFrames(); +// ULLONG getEndTS(); +// hmsf getEndHMSF(); void call(void*); // for callback interface @@ -89,7 +90,6 @@ class Player : public Thread_TYPE, public Callback void skipForwardInt(int seconds); void skipBackwardInt(int seconds); - void setStartTS(UINT dataInBuffer); void setEndTS(); void doConnectionLost(); void restartAt(ULLONG timeCode); @@ -118,8 +118,7 @@ class Player : public Thread_TYPE, public Callback void lock(); void unLock(); - ULLONG startTS; - ULLONG endTS; +// ULLONG endTS; ULLONG lengthBytes; ULONG lengthFrames; ULLONG feedPosition; diff --git a/readme.win b/readme.win new file mode 100644 index 0000000..d487b4c --- /dev/null +++ b/readme.win @@ -0,0 +1,105 @@ +Readme For Windows Port of Vomp-Client +====================================== + +This file contains notes regarding the Windows port of Vomp. +Please read it carefully. + +License and Homepage +==================== + +The source code of vomp client is released under the General Public License (GPL). +For further information consult the vomp homepage: +http://www.loggytronic.com +or vomp on SourceForge (including the source code on cvs): +http://sourceforge.net/projects/vomp + +Requirements +============ + +The vomp client on Windows requires: + +* Windows 2000 or later +* A DirectShow MPEG2 decoder, which supports Video Mixing Renderer 9 (VMR-9), + mostly included within DVD software player +* A network connection to the vompserver computer + +Compatibility List for MPEG2 Decoders +===================================== + +Compatible MPEG2 decoders: +* Cyberlink PowerDVD 6 + +Incompatible MPEG2 decoders: +* Cyperlink PowerDVD 4 + +This list will be extended, please report success or failure with your decoder +at the forum at http://www.loggytronic.com . + +Remote Control Buttons Reference +================================ + +This table shows the Hauppauge MediaMVP remote control buttons and their +corresponding Windows keyboard assignments: + +MediaMVP Button | Keyboard Shortcut +----------------*------------------ +VOLUMEUP | F10 +VOLUMEDOWN | F9 +CHANNELUP | "+", Ctrl+"+", Page down +CHANNELDOWN | Insert, Ctrl+Insert, Page up +0 | 0 +1 | 1 +2 | 2 +3 | 3 +4 | 4 +5 | 5 +6 | 6 +7 | 7 +8 | 8 +9 | 9 +POWER | Esc, Alt+F4 +GO | j +BACK | Backspace +MENU | m +RED | r +GREEN | g +YELLOW | y +BLUE | b +MUTE | F8 +RADIO | Not implemented +REVERSE | Not implemented (Can work on Remote Controls) +PLAY | Shift + P +FORWARD | Shift + F +RECORD | Ctrl + R +STOP | Ctrl + S +PAUSE | Ctrl + P +SKIPBACK | Ctrl + B +SKIPFORWARD | Ctrl + F +OK | Space, Return +FULL | Not implemented +TV | Not implemented +VIDEOS | Not implemented +MUSIC | Not implemented +PICTURES | Not implemented +GUIDE | Not implemented +UP | UP +DOWN | DOWN +LEFT | LEFT +RIGHT | RIGHT +PREVCHANNEL | Not implemented +STAR | * +HASH | Not implemented + +(Note: Remote Controls for Windows should work also for most buttons, +but this is an yet untested feature.) + +Usage +===== +Start the client executable and enjoy, you should not have to configure +anything if you met the requirements above. + +Firewall +======== +If vomp for Windows stops at "Locating server" or "Connecting to VDR", +please configure your firewall so that vomp for windows can communicate +with the vompserver on port 3024 (UDP and TCP). diff --git a/video.cc b/video.cc index d01bbf1..3cbb603 100644 --- a/video.cc +++ b/video.cc @@ -74,3 +74,9 @@ hmsf Video::framesToHMSF(ULONG frames) } return ret; } + +UINT Video::getFPS() +{ + if (format == NTSC) return 30; + else return 25; +} diff --git a/video.h b/video.h index 7f54b95..660e3e9 100644 --- a/video.h +++ b/video.h @@ -85,6 +85,7 @@ class Video: public DrainTarget UCHAR getTVsize() { return tvsize; } hmsf framesToHMSF(ULONG frames); + UINT getFPS(); // Video formats - AV_SET_VID_DISP_FMT const static UCHAR NTSC = 0; diff --git a/vvideorec.cc b/vvideorec.cc index 6c5b9e4..5c1db86 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -82,7 +82,7 @@ VVideoRec::VVideoRec(Recording* rec) VVideoRec::~VVideoRec() { if (playing) stopPlay(); - Video::getInstance()->setDefaultAspect(); + video->setDefaultAspect(); timers->cancelTimer(this, 1); timers->cancelTimer(this, 2); @@ -127,7 +127,7 @@ void VVideoRec::go(ULLONG startPosition) VInfo* vi = new VInfo(); vi->create(400, 150); - if (Video::getInstance()->getFormat() == Video::PAL) + if (video->getFormat() == Video::PAL) vi->setScreenPos(170, 200); else vi->setScreenPos(160, 150); @@ -379,30 +379,19 @@ void VVideoRec::drawBarClocks() rectangle(clocksRegion, barBlue); - ULONG currentTS = (player->getPositionTS() / 90000); - int chours = currentTS / 3600; - int cminutes = (currentTS - (chours * 3600)) / 60; - int cseconds = currentTS - (chours * 3600) - (cminutes * 60); + ULONG currentFrameNum = player->getCurrentFrameNum(); + ULONG lengthFrames = player->getLengthFrames(); - ULONG endTS = (player->getEndTS() / 90000); -// int ehours = endTS / 3600; -// int eminutes = (endTS - (ehours * 3600)) / 60; -// int eseconds = endTS - (ehours * 3600) - (eminutes * 60); - - hmsf endHMSF = player->getEndHMSF(); + hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum); + hmsf lengthHMSF = video->framesToHMSF(lengthFrames); char buffer[100]; - if ((currentTS > 95441) // it's at the 33bit rollover point where the calc doesn't work because of the 1s diff - // between demuxer values and video chip return values ... ? - || (!endTS) ) // No values yet - { - strcpy(buffer, "-:--:-- / -:--:--"); - } - else - { - SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", chours, cminutes, cseconds, endHMSF.hours, endHMSF.minutes, endHMSF.seconds); +// strcpy(buffer, "-:--:-- / -:--:--"); +// else +// { + SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds); logger->log("VVideoRec", Log::DEBUG, buffer); - } +// } drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT); @@ -411,9 +400,9 @@ void VVideoRec::drawBarClocks() rectangle(barRegion.x + 350, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT); rectangle(barRegion.x + 352, barRegion.y + 14, 306, 20, barBlue); - if ((currentTS > 95441) || (!endTS)) return; // No values yet +// if ((currentTS > 95441) || (!endTS)) return; // No values yet - double progress01 = (double)currentTS / (double)endTS; + double progress01 = (double)currentFrameNum / (double)lengthFrames; // total width of bar = 302 int progressWidth = (int)(302 * progress01); @@ -423,13 +412,13 @@ void VVideoRec::drawBarClocks() double pos01; int posPix; - pos01 = (double)startMargin / (double)endTS; + pos01 = ((double)startMargin * video->getFPS()) / lengthFrames; posPix = (int)(302 * pos01); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); - pos01 = (double)(endTS - endMargin) / (double)endTS; + pos01 = lengthFrames - (endMargin * video->getFPS()) / lengthFrames; posPix = (int)(302 * pos01); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); -- 2.39.5 From b9bfc681f477eae3e8b565fef86088f49c807eb5 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 11 Jun 2006 20:39:32 +0000 Subject: [PATCH 04/16] Fixes (1) for new frame number navigation --- player.cc | 4 ++-- vvideorec.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/player.cc b/player.cc index 66a31d1..628bbf5 100644 --- a/player.cc +++ b/player.cc @@ -446,9 +446,9 @@ void Player::skipForwardInt(int seconds) void Player::skipBackwardInt(int seconds) { logger->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); - long newFrameNum = getCurrentFrameNum() + (seconds * video->getFPS()); + long newFrameNum = getCurrentFrameNum() - (seconds * video->getFPS()); if (newFrameNum < 0) newFrameNum = 0; - restartAt(newFrameNum); + restartAtFrame(newFrameNum); } void Player::jumpToPercentInt(int percent) diff --git a/vvideorec.cc b/vvideorec.cc index 5c1db86..9580aba 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -412,13 +412,13 @@ void VVideoRec::drawBarClocks() double pos01; int posPix; - pos01 = ((double)startMargin * video->getFPS()) / lengthFrames; + pos01 = (startMargin * video->getFPS()) / (double)lengthFrames; posPix = (int)(302 * pos01); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); - pos01 = lengthFrames - (endMargin * video->getFPS()) / lengthFrames; + pos01 = (lengthFrames - (endMargin * video->getFPS())) / (double)lengthFrames; posPix = (int)(302 * pos01); rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); -- 2.39.5 From 0b391891d412ef6404c7deca85582f86a3a0007c Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 11 Jun 2006 21:09:06 +0000 Subject: [PATCH 05/16] Resume functionality switched to frame numbers --- defines.h | 4 ++-- player.cc | 15 ++++++++++++--- player.h | 4 ++-- vdr.cc | 4 ++-- vdr.h | 2 +- vvideorec.cc | 6 +++--- vvideorec.h | 2 +- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/defines.h b/defines.h index 2fc1292..e6e4003 100644 --- a/defines.h +++ b/defines.h @@ -47,7 +47,7 @@ void MILLISLEEP(ULONG a); #define VSNPRINTF _vsnprintf #define STRCASECMP _stricmp #define STRCASESTR StrStrI - #define STRTOULL _strtoui64 +/* #define STRTOULL _strtoui64 */ #define CLOSESOCKET closesocket #else @@ -59,7 +59,7 @@ void MILLISLEEP(ULONG a); #define VSNPRINTF vsnprintf #define STRCASECMP strcasecmp #define STRCASESTR strcasestr - #define STRTOULL strtoull + #define STRTOUL strtoul #define CLOSESOCKET close #endif diff --git a/player.cc b/player.cc index 628bbf5..88331ab 100644 --- a/player.cc +++ b/player.cc @@ -128,9 +128,17 @@ int Player::shutdown() return 1; } -void Player::setPosition(ULLONG position) +void Player::setStartFrame(ULONG startFrame) { - feedPosition = position; + startFrameNum = startFrame; + if (startFrameNum) + { + feedPosition = VDR::getInstance()->positionFromFrameNumber(startFrameNum); + } + else + { + feedPosition = 0; + } } void Player::setLengthBytes(ULLONG length) @@ -277,7 +285,8 @@ int Player::playInt(bool* doUnlock) audio->reset(); video->reset(); demuxer->reset(); - demuxer->setFrameNum(0); + if (startFrameNum > lengthFrames) startFrameNum = 0; + demuxer->setFrameNum(startFrameNum); if (!isRadio) demuxer->seek(); videoStartup = true; diff --git a/player.h b/player.h index cf25d4e..4d8a25e 100644 --- a/player.h +++ b/player.h @@ -48,7 +48,7 @@ class Player : public Thread_TYPE, public Callback int init(); int shutdown(); - void setPosition(ULLONG position); + void setStartFrame(ULONG frameNum); void setLengthBytes(ULLONG length); void setLengthFrames(ULONG length); @@ -118,7 +118,7 @@ class Player : public Thread_TYPE, public Callback void lock(); void unLock(); -// ULLONG endTS; + ULONG startFrameNum; ULLONG lengthBytes; ULONG lengthFrames; ULLONG feedPosition; diff --git a/vdr.cc b/vdr.cc index 36dd7da..5a8db29 100644 --- a/vdr.cc +++ b/vdr.cc @@ -886,14 +886,14 @@ EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration) return eventList; } -ULLONG VDR::getResumePoint(char* fileName) +ULONG VDR::getResumePoint(char* fileName) { if (!connected) return 0; char* resumeString = configLoad("ResumeData", fileName); if (!resumeString) return 0; - ULLONG toReturn = STRTOULL(resumeString, NULL, 10); + ULONG toReturn = STRTOUL(resumeString, NULL, 10); delete[] resumeString; return toReturn; } diff --git a/vdr.h b/vdr.h index f80b6e6..de5a97c 100644 --- a/vdr.h +++ b/vdr.h @@ -87,7 +87,7 @@ class VDR int connect(); void disconnect(); bool isConnected() { return connected; } - ULLONG getResumePoint(char* fileName); // uses configLoad + ULONG getResumePoint(char* fileName); // uses configLoad void setReceiveWindow(size_t size); diff --git a/vvideorec.cc b/vvideorec.cc index 9580aba..55cca71 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -93,9 +93,9 @@ void VVideoRec::draw() View::draw(); } -void VVideoRec::go(ULLONG startPosition) +void VVideoRec::go(ULONG startFrameNum) { - Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName()); + 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); if (lengthBytes) @@ -103,7 +103,7 @@ void VVideoRec::go(ULLONG startPosition) doBar(0); player->setLengthBytes(lengthBytes); player->setLengthFrames(lengthFrames); - player->setPosition(startPosition); + player->setStartFrame(startFrameNum); player->play(); playing = true; } diff --git a/vvideorec.h b/vvideorec.h index 482813b..6916e0c 100644 --- a/vvideorec.h +++ b/vvideorec.h @@ -44,7 +44,7 @@ class VVideoRec : public View, public TimerReceiver ~VVideoRec(); void draw(); int handleCommand(int command); - void go(ULLONG startPosition); + void go(ULONG startPosition); void timercall(int clientReference); -- 2.39.5 From d941362c13eceb888dc3ee843ddb5df7de82696b Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Sun, 11 Jun 2006 21:46:52 +0000 Subject: [PATCH 06/16] Fix to PTS/frame mapping in demuxer --- demuxervdr.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/demuxervdr.cc b/demuxervdr.cc index 9bdf7ba..526b300 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -255,20 +255,29 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) bool onTarget = false; while (iter != pts_map.end()) { - bool inRange; + bool inRange, inDoubleRange; if (pts < PTSMAP_THRESHOLD) inRange = (iter->pts <= pts || iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD + pts); else inRange = (iter->pts <= pts && iter->pts >= pts - PTSMAP_THRESHOLD); + + if (pts < PTSMAP_THRESHOLD*2) + inDoubleRange = (iter->pts <= pts || + iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD*2 + pts); + else + inDoubleRange = (iter->pts <= pts && + iter->pts >= pts - PTSMAP_THRESHOLD*2); + if (onTarget) { - if (!inRange) break; // We have hit the target + if (!inDoubleRange) break; // We have hit the target } else { - if (inRange) onTarget = true; // We are hot on the trail + if (inRange){ onTarget = true; // We are hot on the trail + Log::getInstance()->log("Demuxer", Log::DEBUG, "ON TARGET AT %d", iter->frame); } } ++iter; } @@ -276,9 +285,15 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) if (onTarget) ret = iter->frame; pthread_mutex_unlock(&pts_map_mutex); if (!onTarget) + { + Log::getInstance()->log("Demuxer", Log::DEBUG, "FAILED TO FIND FRAME NUMBER for %llu", pts); return 0; + } else + { + Log::getInstance()->log("Demuxer", Log::DEBUG, "FOUND FRAME NUMBER %d for %llu", ret, pts); return ret; + } } void DemuxerVDR::PESPacketVDR::parseDetails() -- 2.39.5 From 73d334ca01aa478260bc258977f23656fe30fa19 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 13 Jun 2006 23:14:02 +0000 Subject: [PATCH 07/16] Keep compiler happy --- demuxervdr.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demuxervdr.cc b/demuxervdr.cc index 526b300..a969954 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -282,7 +282,6 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) ++iter; } --iter; - if (onTarget) ret = iter->frame; pthread_mutex_unlock(&pts_map_mutex); if (!onTarget) { @@ -291,17 +290,18 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) } else { + ret = iter->frame; Log::getInstance()->log("Demuxer", Log::DEBUG, "FOUND FRAME NUMBER %d for %llu", ret, pts); return ret; } } - + void DemuxerVDR::PESPacketVDR::parseDetails() { // TODO: Currently, we naïvely assume that a packet contains a new frame // if and only if it contains a pts, and that no packet contains more // than one new frame - + DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance()); PESPacket::parseDetails(); if (dx->frameCounting && pts != PTS_INVALID && -- 2.39.5 From 382c3d3656a74a469501468895a178988fddc4ed Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 14 Jun 2006 21:39:47 +0000 Subject: [PATCH 08/16] *** empty log message *** --- player.cc | 9 +- player.h | 2 +- surface.cc | 1 - surface.h | 1 - surfacewin.cc | 321 +++++++++++++++++++++++++------------------------- surfacewin.h | 3 +- 6 files changed, 169 insertions(+), 168 deletions(-) diff --git a/player.cc b/player.cc index 88331ab..ad51549 100644 --- a/player.cc +++ b/player.cc @@ -285,8 +285,11 @@ int Player::playInt(bool* doUnlock) audio->reset(); video->reset(); demuxer->reset(); - if (startFrameNum > lengthFrames) startFrameNum = 0; - demuxer->setFrameNum(startFrameNum); + if (isRecording) + { + if (startFrameNum > lengthFrames) startFrameNum = 0; + demuxer->setFrameNum(startFrameNum); + } if (!isRadio) demuxer->seek(); videoStartup = true; @@ -491,6 +494,7 @@ void Player::unLock() #endif } +/* void Player::restartAt(ULLONG timecode) { if (paused) togglePauseInt(); @@ -522,6 +526,7 @@ void Player::restartAt(ULLONG timecode) audio->doMuting(); fbwd = false; } +*/ void Player::restartAtFrame(ULONG newFrame) { diff --git a/player.h b/player.h index 4d8a25e..92d3efa 100644 --- a/player.h +++ b/player.h @@ -92,7 +92,7 @@ class Player : public Thread_TYPE, public Callback void setEndTS(); void doConnectionLost(); - void restartAt(ULLONG timeCode); +// void restartAt(ULLONG timeCode); void restartAtFrame(ULONG newFrame); MessageQueue* commandMessageQueue; diff --git a/surface.cc b/surface.cc index 04c1d5a..8a4c42b 100644 --- a/surface.cc +++ b/surface.cc @@ -1,6 +1,5 @@ /* Copyright 2004-2005 Chris Tallon - Portions copyright 2004 Jon Gettler This file is part of VOMP. diff --git a/surface.h b/surface.h index 66fb5fe..557f630 100644 --- a/surface.h +++ b/surface.h @@ -1,6 +1,5 @@ /* Copyright 2004-2005 Chris Tallon - Portions copyright 2004 Jon Gettler This file is part of VOMP. diff --git a/surfacewin.cc b/surfacewin.cc index 8cc3fbb..0cb251e 100644 --- a/surfacewin.cc +++ b/surfacewin.cc @@ -1,6 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon - Portions copyright 2004 Jon Gettler + Copyright 2006 Marten Richter This file is part of VOMP. @@ -26,54 +25,54 @@ SurfaceWin::SurfaceWin(int id) : Surface(id) { - d3dtexture=NULL; - d3dsurface=NULL; - sheight=swidth=0; - event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); + d3dtexture=NULL; + d3dsurface=NULL; + sheight=swidth=0; + event = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL); } SurfaceWin::~SurfaceWin() { - if (d3dsurface) d3dsurface->Release(); - if (d3dtexture) d3dtexture->Release(); - CloseHandle(event); + if (d3dsurface) d3dsurface->Release(); + if (d3dtexture) d3dtexture->Release(); + CloseHandle(event); } int SurfaceWin::create(UINT width, UINT height) { - LPDIRECT3DDEVICE9 d3ddev=((OsdWin*)(Osd::getInstance()))->getD3dDev(); - while (true) { - if (screen==this) { - if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8, - // Does every adapter with alpha blending support this? - D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) { - MILLISLEEP(50);//wait maybe next time it will work - continue; - } - if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) { - d3dtexture->Release(); - d3dtexture=NULL; - MILLISLEEP(50); - continue; - } - } else { - HRESULT hres; - if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8, - D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) { - MILLISLEEP(50);//wait maybe next time it will work - continue; - } - - } - sheight=height; - swidth=width; - /* If someone does high performance Animations on the OSD, we have to change the types - of surface in order to address these performance issues, if we have only very few updates - per second this would be fast enough !*/ - break; - } - SetEvent(event); - return 1; + LPDIRECT3DDEVICE9 d3ddev=((OsdWin*)(Osd::getInstance()))->getD3dDev(); + while (true) { + if (screen==this) { + if (d3ddev->CreateTexture(1024,1024,0,0,D3DFMT_A8R8G8B8, + // Does every adapter with alpha blending support this? + D3DPOOL_DEFAULT,&d3dtexture ,NULL)!=D3D_OK) { + MILLISLEEP(50);//wait maybe next time it will work + continue; + } + if (d3dtexture->GetSurfaceLevel(0,&d3dsurface)!=D3D_OK) { + d3dtexture->Release(); + d3dtexture=NULL; + MILLISLEEP(50); + continue; + } + } else { + HRESULT hres; + if (hres=d3ddev->CreateOffscreenPlainSurface(width,height,D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM,&d3dsurface,NULL)!=D3D_OK) { + MILLISLEEP(50);//wait maybe next time it will work + continue; + } + + } + sheight=height; + swidth=width; + /* If someone does high performance Animations on the OSD, we have to change the types + of surface in order to address these performance issues, if we have only very few updates + per second this would be fast enough !*/ + break; + } + SetEvent(event); + return 1; } void SurfaceWin::display() @@ -85,44 +84,44 @@ int SurfaceWin::fillblt(int x, int y, int width, int height, unsigned int c) WaitForSingleObject(event,INFINITE); //since this might be called before surface //allocation we will wait in this case, hopefully without deadlocks OsdWin* osd=((OsdWin*)(Osd::getInstance())); - + if (!d3dsurface) { - return 0; //why does this happen + return 0; //why does this happen } LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); - + if (screen==this) { - //This should not happen! - return 0; + //This should not happen! + return 0; } else { - osd->BeginPainting(); - D3DLOCKED_RECT lockrect; - int cx,cy,cwidth,cheight; - cx=min(max(x,0),swidth); - cy=min(max(y,0),sheight); - cwidth=min(width,swidth-x); - cheight=min(height,sheight-y); - RECT rect={cx,cy,cwidth,cheight}; - - if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { - return 0; - } - unsigned int line; - unsigned int column; - for (line=0;lineUnlockRect()!=D3D_OK) { - osd->EndPainting(); - return 0; - } - osd->EndPainting(); + osd->BeginPainting(); + D3DLOCKED_RECT lockrect; + int cx,cy,cwidth,cheight; + cx=min(max(x,0),swidth); + cy=min(max(y,0),sheight); + cwidth=min(width,swidth-x); + cheight=min(height,sheight-y); + RECT rect={cx,cy,cwidth,cheight}; + + if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { + return 0; + } + unsigned int line; + unsigned int column; + for (line=0;lineUnlockRect()!=D3D_OK) { + osd->EndPainting(); + return 0; + } + osd->EndPainting(); } return 0; @@ -134,65 +133,65 @@ void SurfaceWin::drawPixel(int x, int y, unsigned int c) WaitForSingleObject(event,INFINITE); //since this might be called before surface //allocation we will wait in this case, hopefully without deadlocks if (!d3dsurface) { - return; //why does this happen + return; //why does this happen } OsdWin* osd=((OsdWin*)(Osd::getInstance())); LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); if (x>swidth || y>sheight) return; //do not draw outside the surface if (screen==this) { - //This should not happen! - return ; + //This should not happen! + return ; } else { - osd->BeginPainting(); - D3DLOCKED_RECT lockrect; - RECT rect={x,y,x+1,y+1}; - if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { - osd->EndPainting(); - return ; - } - unsigned int*row=(unsigned int*)(((char*)lockrect.pBits)); - row[0]=c; - if (d3dsurface->UnlockRect()!=D3D_OK) { - osd->EndPainting(); - return ; - } - osd->EndPainting(); + osd->BeginPainting(); + D3DLOCKED_RECT lockrect; + RECT rect={x,y,x+1,y+1}; + if (d3dsurface->LockRect(&lockrect,&rect,D3DLOCK_DISCARD)!=D3D_OK) { + osd->EndPainting(); + return ; + } + unsigned int*row=(unsigned int*)(((char*)lockrect.pBits)); + row[0]=c; + if (d3dsurface->UnlockRect()!=D3D_OK) { + osd->EndPainting(); + return ; + } + osd->EndPainting(); } } void SurfaceWin::drawHorzLine(int x1, int x2, int y, unsigned int c) { - fillblt(x1, y, x2-x1, 1, c); + fillblt(x1, y, x2-x1, 1, c); } void SurfaceWin::drawVertLine(int x, int y1, int y2, unsigned int c) { - fillblt(x, y1, 1, y2-y1, c); + fillblt(x, y1, 1, y2-y1, c); } int SurfaceWin::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME { - WaitForSingleObject(event,INFINITE); //since this might be called before surface + WaitForSingleObject(event,INFINITE); //since this might be called before surface //allocation we will wait in this case, hopefully without deadlocks - if (!d3dsurface) { - return 0; //why does this happen - } - OsdWin* osd=((OsdWin*)(Osd::getInstance())); - LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); + if (!d3dsurface) { + return 0; //why does this happen + } + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + LPDIRECT3DDEVICE9 d3ddev=osd->getD3dDev(); LPDIRECT3DSURFACE9 screensurface=((SurfaceWin*)screen)->getD3dsurface(); - if (!screensurface) return 0; - RECT sourcerect={sx,sy,sx+w,sy+h}; - POINT destpoint={dx,dy}; - osd->BeginPainting(); - if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) { - Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!"); - osd->EndPainting(); - return 0; - } - osd->EndPainting(); - return 0; + if (!screensurface) return 0; + RECT sourcerect={sx,sy,sx+w,sy+h}; + POINT destpoint={dx,dy}; + osd->BeginPainting(); + if (d3ddev->UpdateSurface(d3dsurface,&sourcerect,screensurface,&destpoint)!=D3D_OK) { + Log::getInstance()->log("Surface", Log::DEBUG, "Could not update to Screen!"); + osd->EndPainting(); + return 0; + } + osd->EndPainting(); + return 0; } int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy) @@ -203,68 +202,68 @@ int SurfaceWin::blt(int fd, unsigned long shandle, int sx, int sy, int width, in void SurfaceWin::screenShot(char* fileName) { - //Isn't this for debugging only, so I won't implement it yet + //Isn't this for debugging only, so I won't implement it yet } void SurfaceWin::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b) { - //Isn't this for debugging only, so I won't implement it yet + //Isn't this for debugging only, so I won't implement it yet } void SurfaceWin::ReleaseSurface() { - ResetEvent(event); - LPDIRECT3DSURFACE9 temp_surf=d3dsurface; - LPDIRECT3DTEXTURE9 temp_text=d3dtexture; - d3dsurface=NULL; - d3dtexture=NULL; - sheight=swidth=0; - if (temp_surf) temp_surf->Release(); - if (temp_text) temp_text->Release(); + ResetEvent(event); + LPDIRECT3DSURFACE9 temp_surf=d3dsurface; + LPDIRECT3DTEXTURE9 temp_text=d3dtexture; + d3dsurface=NULL; + d3dtexture=NULL; + sheight=swidth=0; + if (temp_surf) temp_surf->Release(); + if (temp_text) temp_text->Release(); } void SurfaceWin::drawJpeg(char *fileName,DWORD x, DWORD y,DWORD *width, DWORD *height){ - WaitForSingleObject(event,INFINITE); //since this might be called before surface + WaitForSingleObject(event,INFINITE); //since this might be called before surface //allocation we will wait in this case, hopefully without deadlocks - if (!d3dsurface) { - return ; //why does this happen - } - OsdWin* osd=((OsdWin*)(Osd::getInstance())); - - - D3DXIMAGE_INFO image_inf; - osd->BeginPainting(); -// D3DXGetImageInfoFromFile(fileName,&image_inf); - D3DXGetImageInfoFromResource(NULL,fileName,&image_inf); - RECT dest_rec={x,y,x+image_inf.Width, - y+image_inf.Height}; -/* if (D3DXLoadSurfaceFromFile( - d3dsurface, - NULL, - &dest_rec, - fileName, - NULL, - D3DX_FILTER_NONE, - 0, - &image_inf)!=D3D_OK) { - Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!"); - - }*/ - if (D3DXLoadSurfaceFromResource( - d3dsurface, - NULL, - &dest_rec, - NULL, - fileName, - NULL, - D3DX_FILTER_NONE, - 0, - &image_inf)!=D3D_OK) { - Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!"); - - } - osd->EndPainting(); - *width=image_inf.Width; - *height=image_inf.Height; - + if (!d3dsurface) { + return ; //why does this happen + } + OsdWin* osd=((OsdWin*)(Osd::getInstance())); + + + D3DXIMAGE_INFO image_inf; + osd->BeginPainting(); +// D3DXGetImageInfoFromFile(fileName,&image_inf); + D3DXGetImageInfoFromResource(NULL,fileName,&image_inf); + RECT dest_rec={x,y,x+image_inf.Width, + y+image_inf.Height}; +/* if (D3DXLoadSurfaceFromFile( + d3dsurface, + NULL, + &dest_rec, + fileName, + NULL, + D3DX_FILTER_NONE, + 0, + &image_inf)!=D3D_OK) { + Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!"); + + }*/ + if (D3DXLoadSurfaceFromResource( + d3dsurface, + NULL, + &dest_rec, + NULL, + fileName, + NULL, + D3DX_FILTER_NONE, + 0, + &image_inf)!=D3D_OK) { + Log::getInstance()->log("Surface", Log::DEBUG, "Could not open jpeg!"); + + } + osd->EndPainting(); + *width=image_inf.Width; + *height=image_inf.Height; + } diff --git a/surfacewin.h b/surfacewin.h index 104aec6..6409103 100644 --- a/surfacewin.h +++ b/surfacewin.h @@ -1,6 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon - Portions copyright 2004 Jon Gettler + Copyright 2006 Marten Richter This file is part of VOMP. -- 2.39.5 From 8ddd8fbfad1fc7d74600c77b4c5486449e927b22 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Wed, 14 Jun 2006 23:17:29 +0000 Subject: [PATCH 09/16] Clock on recplayer bar. code deletions from player --- player.cc | 95 ---------------------------------------------------- player.h | 3 -- vvideorec.cc | 35 +++++++++++++------ 3 files changed, 25 insertions(+), 108 deletions(-) diff --git a/player.cc b/player.cc index ad51549..c68eca1 100644 --- a/player.cc +++ b/player.cc @@ -154,22 +154,6 @@ void Player::setLengthFrames(ULONG length) logger->log("Player", Log::DEBUG, "Player has received length frames of %lu", lengthFrames); } -/* -ULLONG Player::getEndTS() // FIXME delme - used only by bar clocks until current frame code is done -{ - long long rendTS = endTS - startTS; - if (rendTS < 0) rendTS += 8589934592ULL; - return (ULLONG)rendTS; -} -*/ - -/* -hmsf Player::getEndHMSF() -{ - return video->framesToHMSF(lengthFrames); -} -*/ - ULONG Player::getLengthFrames() { return lengthFrames; @@ -494,40 +478,6 @@ void Player::unLock() #endif } -/* -void Player::restartAt(ULLONG timecode) -{ - if (paused) togglePauseInt(); - if (ffwd) toggleFastForwardInt(); - - ULONG wantedFrameNumber = video->timecodeToFrameNumber(timecode); - ULLONG newPosition = VDR::getInstance()->positionFromFrameNumber(wantedFrameNumber); - if (!VDR::getInstance()->isConnected()) { doConnectionLost(); return; } - logger->log("Player", Log::DEBUG, "wantedframe %i feedpos %llu goto %llu", wantedFrameNumber, feedPosition, newPosition); - - vfeed.stop(); - afeed.stop(); - threadStop(); - video->stop(); - video->reset(); - audio->reset(); - demuxer->flush(); - if (!isRadio) demuxer->seek(); - feedPosition = newPosition; - demuxer->setFrameNum(wantedFrameNumber); - videoStartup = true; - afeed.start(); - vfeed.start(); - threadStart(); - audio->play(); - video->sync(); - audio->sync(); - audio->systemMuteOff(); - audio->doMuting(); - fbwd = false; -} -*/ - void Player::restartAtFrame(ULONG newFrame) { if (paused) togglePauseInt(); @@ -559,51 +509,6 @@ void Player::restartAtFrame(ULONG newFrame) fbwd = false; } -/* -void Player::setStartTS(UINT dataInBuffer) -{ -#ifndef NEW_DEMUXER - if (isRecording && feedPosition) // (feedPosition != 0) - { - // FIXME find out how much data need to get to find a TS - // Need to get the actual start of the recording - - UINT thisRead; - UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead); - if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; } - if (!tempBuffer) return; - if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &startTS); - free(tempBuffer); - } - else - { - demuxer->findVideoPTS(threadBuffer, dataInBuffer, &startTS); - } -#else - startTS=0; -#endif -} -*/ - -/* -void Player::setEndTS() -{ - logger->log("Player", Log::DEBUG, "Setting end TS"); -#ifndef NEW_DEMUXER - UINT thisRead; - UCHAR* tempBuffer = VDR::getInstance()->getBlock((lengthBytes - 100000), 100000, &thisRead); - if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; } - if (!tempBuffer) return; - if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &endTS); - free(tempBuffer); - #else //The replacement code relias completely on VDRs timecode and not the pts - endTS=video->frameNumberToTimecode( - VDR::getInstance()->frameNumberFromPosition((lengthBytes - 100000))); - #endif - logger->log("Player", Log::DEBUG, "Set end TS"); -} -*/ - void Player::doConnectionLost() { Message* m = new Message(); diff --git a/player.h b/player.h index 92d3efa..59826bb 100644 --- a/player.h +++ b/player.h @@ -66,8 +66,6 @@ class Player : public Thread_TYPE, public Callback bool isFbwd() { return fbwd; } ULONG getCurrentFrameNum(); ULONG getLengthFrames(); -// ULLONG getEndTS(); -// hmsf getEndHMSF(); void call(void*); // for callback interface @@ -92,7 +90,6 @@ class Player : public Thread_TYPE, public Callback void setEndTS(); void doConnectionLost(); -// void restartAt(ULLONG timeCode); void restartAtFrame(ULONG newFrame); MessageQueue* commandMessageQueue; diff --git a/vvideorec.cc b/vvideorec.cc index 55cca71..6dd80cd 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -69,7 +69,7 @@ VVideoRec::VVideoRec(Recording* rec) barRegion.w = video->getScreenWidth(); barRegion.h = 66; - clocksRegion.x = barRegion.x + 160; + clocksRegion.x = barRegion.x + 140; clocksRegion.y = barRegion.y + 12; clocksRegion.w = 170; clocksRegion.h = surface->getFontHeight(); @@ -395,18 +395,33 @@ void VVideoRec::drawBarClocks() drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT); - // Draw progress bar - rectangle(barRegion.x + 350, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT); - rectangle(barRegion.x + 352, barRegion.y + 14, 306, 20, barBlue); + // Draw clock + // Blank the area first + rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue); + char timeString[20]; + time_t t; + time(&t); + struct tm* tms = localtime(&t); + strftime(timeString, 19, "%H:%M", tms); + drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT); + + + + + + + // Draw progress bar + int progBarXbase = barRegion.x + 300; -// if ((currentTS > 95441) || (!endTS)) return; // No values yet + rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue); double progress01 = (double)currentFrameNum / (double)lengthFrames; // total width of bar = 302 int progressWidth = (int)(302 * progress01); - rectangle(barRegion.x + 354, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT); + rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT); // Now calc position for start margin blips double pos01; @@ -415,14 +430,14 @@ void VVideoRec::drawBarClocks() pos01 = (startMargin * video->getFPS()) / (double)lengthFrames; posPix = (int)(302 * pos01); - rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); - rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); pos01 = (lengthFrames - (endMargin * video->getFPS())) / (double)lengthFrames; posPix = (int)(302 * pos01); - rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); - rectangle(barRegion.x + 352 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); } void VVideoRec::removeBar() -- 2.39.5 From b6c6e95fd76802fcd4f1ff2eea8d9b1ef6b41011 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Thu, 15 Jun 2006 00:34:14 +0000 Subject: [PATCH 10/16] New PTS-to-frame mapping method in demuxer --- demuxer.cc | 2 + demuxer.h | 3 +- demuxervdr.cc | 140 +++++++++++++++++++++++++++++++++----------------- demuxervdr.h | 1 + vvideorec.cc | 11 ++-- 5 files changed, 101 insertions(+), 56 deletions(-) diff --git a/demuxer.cc b/demuxer.cc index b29b398..e2426d5 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -169,6 +169,7 @@ void Demuxer::PESPacket::init(UCHAR type) data[4] = data[5] = 0; packetType = type; pts = PTS_INVALID; + seq_header = false; } int Demuxer::PESPacket::write(UCHAR *buf, int len) @@ -280,6 +281,7 @@ void Demuxer::PESPacket::parseDetails() UINT pattern = *(UINT*)(data+pos); if (pattern == DEMUXER_SEQ_HEAD) { + seq_header = true; pos += 4; if (pos+6 >= size) return; dx->horizontal_size = ((int)data[pos] << 4) | ((int)data[pos+1] >> 4); diff --git a/demuxer.h b/demuxer.h index a30ad52..25b4b35 100644 --- a/demuxer.h +++ b/demuxer.h @@ -57,6 +57,7 @@ protected: bool closed; UCHAR packetType; ULLONG pts; + bool seq_header; UINT submitted; virtual void parseDetails(); @@ -69,7 +70,7 @@ protected: virtual ~Demuxer(); static Demuxer* getInstance(); int init(Callback* callback, DrainTarget* audio, DrainTarget* video); - void reset(); + virtual void reset(); virtual void flush(); void flushAudio(); void seek(); diff --git a/demuxervdr.cc b/demuxervdr.cc index a969954..b22513e 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -19,6 +19,7 @@ */ #include "demuxervdr.h" +#include "video.h" #ifndef WIN32 #include #else @@ -33,20 +34,46 @@ #define DEMUXER_SEQ_HEAD 0xB3010000 #endif -#define PTSMAP_MAXENTRIES 300 -#define PTSMAP_THRESHOLD 90000 // One second - // ISO standard demands at least one PTS every 0.7 seconds +#define PTS_JUMP_MARGIN 10000 +#define PTS_ERASE_MARGIN 900000 // Erase PTS record if we get within 10 seconds +#define PTS_ALLOWANCE 90000 +//#define PTS_UPDATE_FRAMES 2048 +//#define PTS_EXPIRE_FRAMES 2500 + +// 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; +} DemuxerVDR::DemuxerVDR() { frameCounting = false; } +void DemuxerVDR::reset() +{ + frameCounting = false; + pts_map.clear(); + Demuxer::reset(); +} + void DemuxerVDR::flush() { state = 0; submitting = false; - frameCounting = false; Demuxer::flush(); } @@ -249,51 +276,48 @@ int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos) ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) { - ULONG ret; + ULLONG difference = (1LL<<33); + ULONG ref_frame = 0; + int total = 0, actual = 0; pthread_mutex_lock(&pts_map_mutex); - PTSMap::const_iterator iter = pts_map.begin(); - bool onTarget = false; + PTSMap::iterator iter = pts_map.begin(); while (iter != pts_map.end()) { - bool inRange, inDoubleRange; - if (pts < PTSMAP_THRESHOLD) - inRange = (iter->pts <= pts || - iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD + pts); - else - inRange = (iter->pts <= pts && - iter->pts >= pts - PTSMAP_THRESHOLD); - - if (pts < PTSMAP_THRESHOLD*2) - inDoubleRange = (iter->pts <= pts || - iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD*2 + pts); - else - inDoubleRange = (iter->pts <= pts && - iter->pts >= pts - PTSMAP_THRESHOLD*2); - - if (onTarget) + ++total; + if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE) { - if (!inDoubleRange) break; // We have hit the target + difference = 0; + ref_frame = iter->frame; + actual = total; + break; } - else + ULLONG newdiff = PTSDifference(pts, iter->pts); + if (newdiff < difference) { - if (inRange){ onTarget = true; // We are hot on the trail - Log::getInstance()->log("Demuxer", Log::DEBUG, "ON TARGET AT %d", iter->frame); } + difference = newdiff; + ref_frame = iter->frame; + actual = total; } ++iter; } - --iter; - pthread_mutex_unlock(&pts_map_mutex); - if (!onTarget) - { - Log::getInstance()->log("Demuxer", Log::DEBUG, "FAILED TO FIND FRAME NUMBER for %llu", pts); - return 0; + 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()); } + pthread_mutex_unlock(&pts_map_mutex); + if (total > 1 && actual == 1) +Log::getInstance()->log("Demuxer", Log::DEBUG, "DELETED REFERENCES"); + if (actual > 1) +Log::getInstance()->log("Demuxer", Log::DEBUG, "STILL USING OLD REF"); + +//ULONG ret = ref_frame + difference * Video::getInstance()->getFPS() / 90000; +//Log::getInstance()->log("Demuxer", Log::DEBUG, "%llu: FOUND %d from %d, diff %llu", pts, ret, ref_frame, difference); + + if (difference == (1LL<<33)) + return 0; // We cannot make sense of the pts else - { - ret = iter->frame; - Log::getInstance()->log("Demuxer", Log::DEBUG, "FOUND FRAME NUMBER %d for %llu", ret, pts); - return ret; - } + return ref_frame + difference * Video::getInstance()->getFPS() / 90000; } void DemuxerVDR::PESPacketVDR::parseDetails() @@ -307,14 +331,36 @@ void DemuxerVDR::PESPacketVDR::parseDetails() if (dx->frameCounting && pts != PTS_INVALID && packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX) { - PTSMapEntry me; - me.pts = pts; - me.frame = dx->frameNumber; - Log::getInstance()->log("Demuxer", Log::DEBUG, "Map %llu %u", me.pts, me.frame); - pthread_mutex_lock(&(dx->pts_map_mutex)); - dx->pts_map.push_back(me); - if (dx->pts_map.size() == PTSMAP_MAXENTRIES) dx->pts_map.pop_front(); - pthread_mutex_unlock(&(dx->pts_map_mutex)); - ++(dx->frameNumber); + ULONG frame_num = (dx->frameNumber)++; + if (seq_header) + { + PTSMapEntry me; + pthread_mutex_lock(&(dx->pts_map_mutex)); + if (dx->pts_map.empty()) + { + me.pts = pts; + me.frame = frame_num; + pthread_mutex_unlock(&(dx->pts_map_mutex)); +Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame); + pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map.push_front(me); + } + me = dx->pts_map.front(); + pthread_mutex_unlock(&(dx->pts_map_mutex)); + + 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, pts) > PTS_JUMP_MARGIN) // PTS jump! + { +Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", pts, frame_num); + me.pts = pts; + me.frame = frame_num; + pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map.push_front(me); + pthread_mutex_unlock(&(dx->pts_map_mutex)); + } + } } } diff --git a/demuxervdr.h b/demuxervdr.h index 4194fe0..d1412e0 100644 --- a/demuxervdr.h +++ b/demuxervdr.h @@ -36,6 +36,7 @@ class DemuxerVDR : public Demuxer public: DemuxerVDR(); + void reset(); void flush(); int scan(UCHAR* buf, int len); int findVideoPTS(UCHAR* buf, int len, ULLONG* dest); diff --git a/vvideorec.cc b/vvideorec.cc index 6dd80cd..7362674 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -417,24 +417,19 @@ void VVideoRec::drawBarClocks() rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue); - double progress01 = (double)currentFrameNum / (double)lengthFrames; - // total width of bar = 302 - int progressWidth = (int)(302 * progress01); + int progressWidth = 302 * currentFrameNum / lengthFrames; rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT); // Now calc position for start margin blips - double pos01; int posPix; - pos01 = (startMargin * video->getFPS()) / (double)lengthFrames; - posPix = (int)(302 * pos01); + posPix = 302 * startMargin * video->getFPS() / lengthFrames; rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); - pos01 = (lengthFrames - (endMargin * video->getFPS())) / (double)lengthFrames; - posPix = (int)(302 * pos01); + posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames; rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); -- 2.39.5 From 147ceb76b764f20ac530f7ee99206150d8c9e31b Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 15 Jun 2006 23:09:32 +0000 Subject: [PATCH 11/16] Fix overdrawing progress bar at startup --- vvideorec.cc | 57 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/vvideorec.cc b/vvideorec.cc index 7362674..4b7b271 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -377,6 +377,18 @@ void VVideoRec::drawBarClocks() Log* logger = Log::getInstance(); logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks"); + // Draw RTC + // Blank the area first + rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue); + char timeString[20]; + time_t t; + time(&t); + struct tm* tms = localtime(&t); + strftime(timeString, 19, "%H:%M", tms); + drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT); + + // Draw clocks + rectangle(clocksRegion, barBlue); ULONG currentFrameNum = player->getCurrentFrameNum(); @@ -386,26 +398,19 @@ void VVideoRec::drawBarClocks() hmsf lengthHMSF = video->framesToHMSF(lengthFrames); char buffer[100]; -// strcpy(buffer, "-:--:-- / -:--:--"); -// else -// { + if (currentFrameNum >= lengthFrames) + { + strcpy(buffer, "-:--:-- / -:--:--"); + } + else + { SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds); logger->log("VVideoRec", Log::DEBUG, buffer); -// } + } drawText(buffer, clocksRegion.x, clocksRegion.y, Colour::LIGHTTEXT); - // Draw clock - // Blank the area first - rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue); - char timeString[20]; - time_t t; - time(&t); - struct tm* tms = localtime(&t); - strftime(timeString, 19, "%H:%M", tms); - drawText(timeString, barRegion.x + 624, barRegion.y + 12, Colour::LIGHTTEXT); - @@ -417,22 +422,26 @@ void VVideoRec::drawBarClocks() rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, Colour::LIGHTTEXT); rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue); - int progressWidth = 302 * currentFrameNum / lengthFrames; + if (currentFrameNum < lengthFrames) + { + + int progressWidth = 302 * currentFrameNum / lengthFrames; - rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT); + rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, Colour::SELECTHIGHLIGHT); - // Now calc position for start margin blips - int posPix; + // Now calc position for start margin blips + int posPix; - posPix = 302 * startMargin * video->getFPS() / lengthFrames; + posPix = 302 * startMargin * video->getFPS() / lengthFrames; - rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); - rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); - posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames; + posPix = 302 * (lengthFrames - endMargin * video->getFPS()) / lengthFrames; - rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); - rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, Colour::LIGHTTEXT); + rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, Colour::LIGHTTEXT); + } } void VVideoRec::removeBar() -- 2.39.5 From a06afe8c2d4f4d54f9a1c8154c96ed75a1ca9c87 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Thu, 15 Jun 2006 23:46:11 +0000 Subject: [PATCH 12/16] Fixes for deadlocks when no stream available --- player.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/player.cc b/player.cc index c68eca1..13b7576 100644 --- a/player.cc +++ b/player.cc @@ -179,6 +179,7 @@ int Player::play() void Player::stop() { lock(); + logger->log("Player", Log::DEBUG, "Stop called lock"); stopInt(); unLock(); } @@ -319,7 +320,7 @@ void Player::stopInt() vfeed.stop(); afeed.stop(); - threadStop(); + if (threadIsActive()) threadStop(); video->stop(); video->blank(); audio->stop(); @@ -626,8 +627,8 @@ void Player::threadMethod() threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead); #ifdef NEW_DEMUXER - currentposition=feedPosition; - #endif + currentposition=feedPosition; +#endif if (!vdr->isConnected()) { doConnectionLost(); @@ -722,6 +723,13 @@ void Player::threadMethod() // end of recording logger->log("Player", Log::DEBUG, "Recording playback ends"); + if (videoStartup) // oh woe. there never was a stream, I was conned! + { + videoStartup = false; + unLock(); + MILLISLEEP(500); // I think this will solve a race + } + threadCheckExit(); Message* m = new Message(); // Must be done after this thread finishes, and must break into master mutex -- 2.39.5 From 82b96d86d51ef44bad27322b87a24e9d5f3829da Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Wed, 21 Jun 2006 20:53:25 +0000 Subject: [PATCH 13/16] Count frames properly in VDR demuxer --- demuxer.cc | 19 +++++++++++++++++-- demuxer.h | 1 + demuxervdr.cc | 18 +++--------------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/demuxer.cc b/demuxer.cc index e2426d5..0b6f2cd 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -33,6 +33,8 @@ #define DEMUXER_SEQ_HEAD 0xB3010000 #endif +#define DEMUXER_PIC_HEAD 0x00000101 + #define SEEK_THRESHOLD 150000 // About 1.5 seconds const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 }; @@ -237,7 +239,7 @@ void Demuxer::PESPacket::parseDetails() if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX) { // Extract audio PTS if it exists - if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present + if ( size >= 14 && (data[7] & 0x80) ) // PTS_DTS_flags indicate PTS { dx->audio_pts = pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) | ( (ULLONG)(data[10]) << 22 ) | @@ -265,7 +267,7 @@ void Demuxer::PESPacket::parseDetails() else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX) { // Extract video PTS if it exists - if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present + if ( size >= 14 && (data[7] & 0x80) ) // PTS_DTS_flags indicate PTS { dx->video_pts = pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) | ( (ULLONG)(data[10]) << 22 ) | @@ -310,3 +312,16 @@ void Demuxer::PESPacket::parseDetails() } } } + +UINT Demuxer::PESPacket::findPictureHeader() +{ + if (size < 12) return 0; + UINT pattern = *(UINT*)(data+8); + UINT pos = 11; + while (pattern != DEMUXER_PIC_HEAD) + { + if (++pos >= size) return 0; + pattern = (pattern << 8) | data[pos]; + } + return pos-3; +} diff --git a/demuxer.h b/demuxer.h index 25b4b35..6447f0c 100644 --- a/demuxer.h +++ b/demuxer.h @@ -60,6 +60,7 @@ protected: bool seq_header; UINT submitted; virtual void parseDetails(); + UINT findPictureHeader(); static const ULLONG PTS_INVALID; }; diff --git a/demuxervdr.cc b/demuxervdr.cc index b22513e..cb0a4fd 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -28,17 +28,8 @@ #define __BYTE_ORDER __LITTLE_ENDIAN #endif -#if __BYTE_ORDER == __BIG_ENDIAN -#define DEMUXER_SEQ_HEAD 0x000001B3 -#else -#define DEMUXER_SEQ_HEAD 0xB3010000 -#endif - #define PTS_JUMP_MARGIN 10000 -#define PTS_ERASE_MARGIN 900000 // Erase PTS record if we get within 10 seconds #define PTS_ALLOWANCE 90000 -//#define PTS_UPDATE_FRAMES 2048 -//#define PTS_EXPIRE_FRAMES 2500 // TODO: PTS class to handle wrapping arithmetic & comparisons? static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2) @@ -322,17 +313,14 @@ Log::getInstance()->log("Demuxer", Log::DEBUG, "STILL USING OLD REF"); void DemuxerVDR::PESPacketVDR::parseDetails() { - // TODO: Currently, we naïvely assume that a packet contains a new frame - // if and only if it contains a pts, and that no packet contains more - // than one new frame - DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance()); PESPacket::parseDetails(); - if (dx->frameCounting && pts != PTS_INVALID && + + if (dx->frameCounting && findPictureHeader() && packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX) { ULONG frame_num = (dx->frameNumber)++; - if (seq_header) + if (seq_header && pts != PTS_INVALID) { PTSMapEntry me; pthread_mutex_lock(&(dx->pts_map_mutex)); -- 2.39.5 From 945240d136e6986bc0f7c1061d422acfbdf8a569 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Fri, 23 Jun 2006 23:23:38 +0000 Subject: [PATCH 14/16] MVP/Windows convergence --- defines.h | 1 + demuxer.cc | 13 +------------ demuxer.h | 8 -------- demuxervdr.cc | 46 +++++++++------------------------------------- demuxervdr.h | 8 ++------ objects.mk | 26 ++++++++++++++------------ player.cc | 12 +----------- stream.cc | 3 +-- stream.h | 5 ----- videowin.cc | 11 ++++++----- videowin.h | 2 +- 11 files changed, 36 insertions(+), 99 deletions(-) diff --git a/defines.h b/defines.h index e6e4003..d3c1f0d 100644 --- a/defines.h +++ b/defines.h @@ -48,6 +48,7 @@ void MILLISLEEP(ULONG a); #define STRCASECMP _stricmp #define STRCASESTR StrStrI /* #define STRTOULL _strtoui64 */ + #define STRTOUL strtoul #define CLOSESOCKET closesocket #else diff --git a/demuxer.cc b/demuxer.cc index 0b6f2cd..8e97ec6 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -185,11 +185,8 @@ int Demuxer::PESPacket::write(UCHAR *buf, int len) data[5] = (length & 0xFF); return 1; } -#ifndef NEW_DEMUXER + int Demuxer::PESPacket::submit() -#else -int Demuxer::PESPacket::submit(ULLONG cur_pos) -#endif { if (submitted >= size) return 0; if (!closed) parseDetails(); @@ -201,11 +198,7 @@ int Demuxer::PESPacket::submit(ULLONG cur_pos) { if (dx->video_current == -1) dx->video_current = packetType; if (dx->video_current == packetType && !dx->vid_seeking) -#ifndef NEW_DEMUXER sent = dx->videostream.put(data+submitted, size-submitted); -#else - sent = dx->videostream.put(data+submitted, size-submitted,cur_pos); -#endif else sent = size-submitted; } @@ -213,11 +206,7 @@ int Demuxer::PESPacket::submit(ULLONG cur_pos) { if (dx->audio_current == -1) dx->audio_current = packetType; if (dx->audio_current == packetType && !dx->aud_seeking) -#ifndef NEW_DEMUXER sent = dx->audiostream.put(data+submitted, size-submitted); -#else - sent = dx->audiostream.put(data+submitted, size-submitted,cur_pos); -#endif else sent = size-submitted; } diff --git a/demuxer.h b/demuxer.h index 6447f0c..7e0f88d 100644 --- a/demuxer.h +++ b/demuxer.h @@ -46,11 +46,7 @@ protected: PESPacket(); void init(UCHAR type); int write(UCHAR* buf, int len); -#ifndef NEW_DEMUXER int submit(); -#else - int submit(ULLONG cur_pos); -#endif protected: UCHAR data[0x10000]; UINT length, size; @@ -82,11 +78,7 @@ protected: virtual int scan(UCHAR* buf, int len) = 0; virtual int findVideoPTS(UCHAR* buf, int len, ULLONG* dest) = 0; -#ifndef NEW_DEMUXER virtual int put(UCHAR* buf, int len) = 0; -#else - virtual int put(UCHAR* buf, int len,ULLONG cur_pos) = 0; -#endif virtual void setFrameNum(ULONG frame) {} virtual ULONG getFrameNumFromPTS(ULLONG pts) {return 0;} diff --git a/demuxervdr.cc b/demuxervdr.cc index cb0a4fd..9444b5b 100644 --- a/demuxervdr.cc +++ b/demuxervdr.cc @@ -141,25 +141,12 @@ void DemuxerVDR::setFrameNum(ULONG frame) Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame); } -#ifndef NEW_DEMUXER int DemuxerVDR::put(UCHAR* buf, int len) -#else -int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos) -#endif { int ret = 0; // return number of bytes consumed - -#ifdef NEW_DEMUXER - ULLONG current_position = cur_pos; -#endif - if (submitting) { -#ifndef NEW_DEMUXER if (packet.submit() == 0) // Still full! -#else - if (packet.submit(current_position) == 0) // Still full! -#endif return ret; else submitting = false; @@ -172,11 +159,7 @@ int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos) packet.write(buf, state); buf += state; len -= state; ret += state; state = 0; -#ifndef NEW_DEMUXER - if (packet.submit() == 0) // Stream is full -#else - if (packet.submit(current_position) == 0) // Stream is full -#endif + if (packet.submit() == 0) // Stream is full { submitting = true; return ret; @@ -229,25 +212,14 @@ int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos) break; } -#ifdef NEW_DEMUXER - current_position++; -#endif - if (state == -6) // Packet header complete { if (len >= packetLength) // The entire packet is available. { packet.write(buf, packetLength); buf += packetLength; len -= packetLength; ret += packetLength; -#ifdef NEW_DEMUXER - current_position+=(ULLONG)packetLength; -#endif state = 0; -#ifndef NEW_DEMUXER if (packet.submit() == 0) // Stream is full -#else - if (packet.submit(current_position) == 0) // Stream is full -#endif { submitting = true; return ret; @@ -270,7 +242,7 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) ULLONG difference = (1LL<<33); ULONG ref_frame = 0; int total = 0, actual = 0; - pthread_mutex_lock(&pts_map_mutex); + pts_map_mutex.Lock(); PTSMap::iterator iter = pts_map.begin(); while (iter != pts_map.end()) { @@ -296,7 +268,7 @@ ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts) iter = pts_map.begin(); iter++; pts_map.erase(iter, pts_map.end()); } - pthread_mutex_unlock(&pts_map_mutex); + pts_map_mutex.Unlock(); if (total > 1 && actual == 1) Log::getInstance()->log("Demuxer", Log::DEBUG, "DELETED REFERENCES"); if (actual > 1) @@ -323,18 +295,18 @@ void DemuxerVDR::PESPacketVDR::parseDetails() if (seq_header && pts != PTS_INVALID) { PTSMapEntry me; - pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Lock(); if (dx->pts_map.empty()) { me.pts = pts; me.frame = frame_num; - pthread_mutex_unlock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Unlock(); Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame); - pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Lock(); dx->pts_map.push_front(me); } me = dx->pts_map.front(); - pthread_mutex_unlock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Unlock(); UINT fps = Video::getInstance()->getFPS(); ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps; @@ -345,9 +317,9 @@ Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", pts, frame_num); me.pts = pts; me.frame = frame_num; - pthread_mutex_lock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Lock(); dx->pts_map.push_front(me); - pthread_mutex_unlock(&(dx->pts_map_mutex)); + dx->pts_map_mutex.Unlock(); } } } diff --git a/demuxervdr.h b/demuxervdr.h index d1412e0..65b0e8e 100644 --- a/demuxervdr.h +++ b/demuxervdr.h @@ -21,7 +21,7 @@ #ifndef DEMUXERVDR_H #define DEMUXERVDR_H -#include "pthread.h" +#include "mutex.h" #include #include "demuxer.h" #include "defines.h" @@ -40,11 +40,7 @@ class DemuxerVDR : public Demuxer void flush(); int scan(UCHAR* buf, int len); int findVideoPTS(UCHAR* buf, int len, ULLONG* dest); -#ifndef NEW_DEMUXER int put(UCHAR* buf, int len); -#else - int put(UCHAR* buf, int len,ULLONG cur_pos); -#endif void setFrameNum(ULONG frame); ULONG getFrameNumFromPTS(ULLONG pts); @@ -59,7 +55,7 @@ class DemuxerVDR : public Demuxer typedef struct { ULLONG pts; ULONG frame; } PTSMapEntry; typedef std::deque PTSMap; PTSMap pts_map; - pthread_mutex_t pts_map_mutex; + Mutex pts_map_mutex; }; #endif diff --git a/objects.mk b/objects.mk index b51cde8..1fd2051 100644 --- a/objects.mk +++ b/objects.mk @@ -1,13 +1,15 @@ -OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o \ - message.o messagequeue.o \ - vdr.o recman.o recording.o channel.o rectimer.o event.o directory.o \ - player.o vfeed.o afeed.o \ - demuxer.o demuxervdr.o stream.o draintarget.o \ - viewman.o box.o region.o colour.o view.o \ - vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o \ - vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o vquestion.o \ - vchannellist.o vwelcome.o vvideolive.o vvideorec.o vepgsettimer.o \ - vchannelselect.o vserverselect.o vconnect.o voptions.o vepg.o vrecmove.o \ - widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o woptionbox.o wtextbox.o \ - fonts/helvB24.o fonts/helvB18.o \ +OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o \ + message.o messagequeue.o \ + vdr.o recman.o recording.o channel.o rectimer.o event.o directory.o\ + player.o vfeed.o afeed.o \ + demuxer.o demuxervdr.o stream.o draintarget.o \ + viewman.o box.o region.o colour.o view.o \ + vinfo.o vquestion.o vwallpaper.o vrecordinglist.o vlivebanner.o \ + vmute.o vvolume.o voptions.o \ + vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o \ + vchannellist.o vwelcome.o vvideolive.o vvideorec.o vepgsettimer.o \ + vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o \ + widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o \ + woptionbox.o wtextbox.o \ + fonts/helvB24.o fonts/helvB18.o \ remote.o led.o mtd.o video.o audio.o osd.o surface.o diff --git a/player.cc b/player.cc index 13b7576..bdacba5 100644 --- a/player.cc +++ b/player.cc @@ -573,9 +573,6 @@ void Player::threadMethod() UINT writeLength; UINT thisWrite; UINT preBufferTotal = 0; -#ifdef NEW_DEMUXER - ULLONG currentposition; -#endif VDR* vdr = VDR::getInstance(); @@ -626,9 +623,7 @@ void Player::threadMethod() } threadBuffer = vdr->getBlock(feedPosition, askFor, &thisRead); -#ifdef NEW_DEMUXER - currentposition=feedPosition; -#endif + if (!vdr->isConnected()) { doConnectionLost(); @@ -693,12 +688,7 @@ void Player::threadMethod() while(writeLength < thisRead) { -#ifndef NEW_DEMUXER thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength); -#else - thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength, - currentposition+(ULLONG)writeLength); -#endif writeLength += thisWrite; // logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite); diff --git a/stream.cc b/stream.cc index 68232ab..6a4531e 100644 --- a/stream.cc +++ b/stream.cc @@ -119,7 +119,7 @@ int Stream::put(UCHAR* inbuf, int len) return ret; } #else -int Stream::put(UCHAR* inbuf, int len,ULLONG curpos) +int Stream::put(UCHAR* inbuf, int len) { int ret = 0; int tail = bufferTail; @@ -130,7 +130,6 @@ int Stream::put(UCHAR* inbuf, int len,ULLONG curpos) MediaPacket newPacket; newPacket.length=len; newPacket.pos_buffer=0; - newPacket.recording_byte_pos=curpos; newPacket.synched=false; newPacket.disconti=false; newPacket.pts=0; diff --git a/stream.h b/stream.h index 6d33cf0..507855b 100644 --- a/stream.h +++ b/stream.h @@ -42,12 +42,7 @@ class Stream int init(DrainTarget* tdt, int bufsize); void shutdown(); void flush(); -#ifndef NEW_DEMUXER int put(UCHAR* inbuf, int len); -#else - int put(UCHAR* inbuf, int len,ULLONG curpos); -#endif - int drain(); private: diff --git a/videowin.cc b/videowin.cc index 487c019..d029886 100644 --- a/videowin.cc +++ b/videowin.cc @@ -48,8 +48,8 @@ VideoWin::VideoWin() startoffset=0; lastrefaudiotime=0; lastrefvideotime=0; - lastreftimeBYTE=0; lastreftimeRT=0; + lastreftimePTS=0; firstsynched=false; cur_audio_media_sample=NULL; cur_video_media_sample=NULL; @@ -377,8 +377,9 @@ ULLONG VideoWin::getCurrentTimestamp() startoffset=sourcefilter->getStartOffset(); ncr_time-=startoffset; ncr_time-=lastreftimeRT; - ULLONG result=frameNumberToTimecode( - VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE)); + /* ULLONG result=frameNumberToTimecode( + VDR::getInstance()->frameNumberFromPosition(lastreftimeBYTE));*/ + ULLONG result=lastreftimePTS; result+=(ULLONG)(ncr_time/10000LL*90LL); return result; @@ -536,7 +537,7 @@ UINT VideoWin::DeliverMediaSample(MediaPacket packet, else ms->SetPreroll(FALSE); /*Timecode handling*/ lastreftimeRT=reftime1; - lastreftimeBYTE=packet.recording_byte_pos; + lastreftimePTS=packet.pts; }else { ms->SetSyncPoint(FALSE); @@ -689,8 +690,8 @@ void VideoWin::ResetTimeOffsets() { startoffset=0; lastrefaudiotime=0; lastrefvideotime=0; - lastreftimeBYTE=0; lastreftimeRT=0; + lastreftimePTS=0; } diff --git a/videowin.h b/videowin.h index c6b6db8..5176d6a 100644 --- a/videowin.h +++ b/videowin.h @@ -128,7 +128,7 @@ private: bool videoon; UCHAR pseudotvsize; REFERENCE_TIME lastreftimeRT; - ULLONG lastreftimeBYTE; + ULLONG lastreftimePTS; unsigned int videoposx; unsigned int videoposy; #ifdef DS_DEBUG -- 2.39.5 From 10077a4216345a4578a18a3840f6ec93d814cf63 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Fri, 23 Jun 2006 23:55:10 +0000 Subject: [PATCH 15/16] MVP/Windows convergence --- mutex.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ mutex.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 mutex.cc create mode 100644 mutex.h diff --git a/mutex.cc b/mutex.cc new file mode 100644 index 0000000..1017180 --- /dev/null +++ b/mutex.cc @@ -0,0 +1,51 @@ +/* + Copyright 2004-2005 Chris Tallon + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "mutex.h" + +Mutex::Mutex() { +#ifndef WIN32 + pthread_mutex_init(&my_mutex, NULL); +#else + my_mutex=CreateMutex(NULL,FALSE,NULL); +#endif +} + +Mutex::~Mutex() { +#ifdef WIN32 + CloseHandle(my_mutex); +#endif +} + +void Mutex::Lock() { +#ifndef WIN32 + pthread_mutex_lock(&my_mutex); +#else + WaitForSingleObject(my_mutex, INFINITE ); +#endif +} + +void Mutex::Unlock() { +#ifndef WIN32 + pthread_mutex_unlock(&my_mutex); +#else + ReleaseMutex(my_mutex); +#endif +} + diff --git a/mutex.h b/mutex.h new file mode 100644 index 0000000..d989da8 --- /dev/null +++ b/mutex.h @@ -0,0 +1,47 @@ +/* + Copyright 2004-2005 Chris Tallon + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MUTEX_H +#define MUTEX_H + +#ifndef WIN32 +#include +#else +#include +#include +#endif + + + +class Mutex +{ +public: + Mutex(); + ~Mutex(); + void Lock(); + void Unlock(); +protected: +#ifndef WIN32 + pthread_mutex_t my_mutex; +#else + HANDLE my_mutex; +#endif +}; +#endif -- 2.39.5 From 698a189619d15ba5df8333501a083923e614365a Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Sat, 24 Jun 2006 12:23:20 +0000 Subject: [PATCH 16/16] MVP/Windows convergence: Stream; DrainTarget --- afeed.cc | 2 +- audio.h | 4 - audiomvp.cc | 21 ++--- audiomvp.h | 12 +-- audiowin.cc | 19 +++- audiowin.h | 7 +- defines.h | 4 - demuxer.cc | 4 +- demuxer.h | 4 +- draintarget.h | 67 ++++++++------ player.cc | 2 + stream.cc | 242 ++++++++++++-------------------------------------- stream.h | 15 ++-- vfeed.cc | 2 +- video.h | 4 - videomvp.cc | 40 +++++---- videomvp.h | 18 ++-- videowin.cc | 19 +++- videowin.h | 7 +- 19 files changed, 205 insertions(+), 288 deletions(-) diff --git a/afeed.cc b/afeed.cc index 7bc8fbf..5f86445 100644 --- a/afeed.cc +++ b/afeed.cc @@ -60,7 +60,7 @@ void AFeed::stop() void AFeed::threadMethod() { - int alen; + bool alen; while(1) { diff --git a/audio.h b/audio.h index a240121..0baaeb2 100644 --- a/audio.h +++ b/audio.h @@ -58,10 +58,6 @@ class Audio : public DrainTarget virtual int mute()=0; virtual int unMute()=0; -#ifndef NEW_DEMUXER - virtual int write(UCHAR* buffer, ULONG length)=0; -#endif - int volumeUp(); int volumeDown(); int getVolume(); diff --git a/audiomvp.cc b/audiomvp.cc index f7a4ab4..3ef84e1 100644 --- a/audiomvp.cc +++ b/audiomvp.cc @@ -228,23 +228,20 @@ int AudioMVP::test() } #endif - -#ifdef NEW_DEMUXER - -UINT AudioMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos) +void AudioMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) { - return 0; + packet = mplist.front(); } -void AudioMVP::ResetTimeOffsets() +UINT AudioMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos) { + int written = ::write(fdAudio, buffer + packet.pos_buffer + *samplepos, + packet.length - *samplepos); + if (written == (int)(packet.length - *samplepos)) {*samplepos = 0; return 1;} + if (written > 0) *samplepos += written; + return 0; } -#else - -int AudioMVP::write(UCHAR* buffer, ULONG length) +void AudioMVP::ResetTimeOffsets() { - return ::write(fdAudio, buffer, length); } - -#endif diff --git a/audiomvp.h b/audiomvp.h index 0178514..52c3b53 100644 --- a/audiomvp.h +++ b/audiomvp.h @@ -55,14 +55,11 @@ class AudioMVP : public Audio int mute(); int unMute(); -#ifdef NEW_DEMUXER - //Writing Data to Audiodevice -- unused in MVP code so far - virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + //Writing Data to Audiodevice + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); + virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; virtual void ResetTimeOffsets(); -#else - int write(UCHAR* buffer, ULONG length); -#endif #ifdef DEV int test(); @@ -72,6 +69,9 @@ class AudioMVP : public Audio int initAllParams(); UCHAR streamType; int fdAudio; + + MediaPacket packet; + UINT packetpos; }; #endif diff --git a/audiowin.cc b/audiowin.cc index 189731b..097247f 100644 --- a/audiowin.cc +++ b/audiowin.cc @@ -145,8 +145,23 @@ int AudioWin::unMute() return 1; } -UINT AudioWin::DeliverMediaSample(MediaPacket packet, - UCHAR* buffer, +void AudioWin::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) +{ + mediapacket = mplist.front(); +} + +UINT AudioWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) +{ + DeliverMediaPacket(mediapacket, buffer, samplepos); + if (*samplepos == mediapacket.length) { + *samplepos = 0; + return 1; + } + else return 0; +} + +UINT AudioWin::DeliverMediaPacket(MediaPacket packet, + const UCHAR* buffer, UINT *samplepos) { /*First Check, if we have an audio sample*/ diff --git a/audiowin.h b/audiowin.h index 52690b5..b297519 100644 --- a/audiowin.h +++ b/audiowin.h @@ -49,7 +49,12 @@ class AudioWin : public Audio int write(char *buf, int len); // Writing Data to Audiodevice - virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); + virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); + UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos); + private: + MediaPacket mediapacket; + public: virtual long long SetStartOffset(long long curreftime, bool *rsync); virtual void ResetTimeOffsets(); diff --git a/defines.h b/defines.h index d3c1f0d..a1a7d7d 100644 --- a/defines.h +++ b/defines.h @@ -21,10 +21,6 @@ #ifndef DEFINES_H #define DEFINES_H -//#define NEW_DEMUXER //Switch for the new demuxer code -//At the beginning the changed code will be switchable -//in order to apply the changes also to the mvp code - typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned int UINT; diff --git a/demuxer.cc b/demuxer.cc index 8e97ec6..90db814 100644 --- a/demuxer.cc +++ b/demuxer.cc @@ -145,12 +145,12 @@ void Demuxer::setAspectRatio(enum AspectRatio ar) arcnt = 0; } -int Demuxer::writeAudio() +bool Demuxer::writeAudio() { return audiostream.drain(); } -int Demuxer::writeVideo() +bool Demuxer::writeVideo() { return videostream.drain(); } diff --git a/demuxer.h b/demuxer.h index 7e0f88d..c4c9392 100644 --- a/demuxer.h +++ b/demuxer.h @@ -73,8 +73,8 @@ protected: void seek(); void setVideoStream(int id); void setAudioStream(int id); - int writeAudio(); - int writeVideo(); + bool writeAudio(); + bool writeVideo(); virtual int scan(UCHAR* buf, int len) = 0; virtual int findVideoPTS(UCHAR* buf, int len, ULLONG* dest) = 0; diff --git a/draintarget.h b/draintarget.h index 380979b..74d5862 100644 --- a/draintarget.h +++ b/draintarget.h @@ -24,55 +24,66 @@ #include "defines.h" #include - -#ifdef NEW_DEMUXER - struct MediaPacket { - ULLONG recording_byte_pos; //position in recording - ULLONG pts; ULONG pos_buffer; //position in stream buffer ULONG length; //length of the packet - //The last to are only needed on windows, for memory reasons they can be excluded in mvp + // The fields below are not needed by the MVP +#ifdef WIN32 + ULLONG recording_byte_pos; //position in recording + ULLONG pts; long long presentation_time;/* in 100 ns units*/ bool synched; bool disconti; +#endif }; using namespace std; - typedef list MediaPacketList; -#endif - class DrainTarget { public: DrainTarget(); virtual ~DrainTarget(); -#ifdef NEW_DEMUXER - - virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos)=0; - - /* This function behaviour should be: - Try to deliver the Data from packet.pos_buffer+samplepos to packet.pos_buffer+packet.length, - with considering the bufferwraparound according to buffersize. - Then increasing samplepos, so that on the next call delivering can proceed. So if writebytes are - writen samplepos=samplepos+writebytes! - If samplepos>=packet.length is returned, the next packet can be used for the next call.*/ - virtual long long SetStartOffset(long long curreftime, bool *rsync)=0; virtual void ResetTimeOffsets()=0; -#else - virtual int write(UCHAR* buffer, ULONG length)=0; -#endif - +// The following two functions are used by the Stream +// to deliver media packets to the front end (DrainTarget). +// +// First, the Stream calls PrepareMediaSample, which gives the front end +// read-only access to the Stream's MediaPacketList. PrepareMediaSample should +// examine the list to determine how much it wishes to consume, and +// should copy any data it requires from the MediaPacket objects into +// local storage. +// This function call takes place under a mutex lock to ensure integrity +// of the list structure. It should be fast and must not contain any +// cancellation points, such as I/O calls for logging. +// +// Second, the Stream releases the mutex and calls DeliverMediaSample. +// This function delivers data from the Stream buffer to the presentation +// device and returns information to the Stream regarding how many MediaPackets +// were consumed. Any data copied from the MediaPackets objects during +// PrepareMediaSample is guaranteed by the Stream still to be valid +// during the following DeliverMediaSample call. + + // samplepos is equal to the number of bytes from the first MediaPacket + // in the list that have already been consumed in a previous call. + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos)=0; + + // The Stream guarantees that the value of *samplepos passed to + // DeliverMediaSample will be equal to the value of samplepos passed to + // PrepareMediaSample in the previous call. + // This function should consume data from the buffer according to the + // decisions made in PrepareMediaSample. Its return value and *samplepos + // tell the Stream how much data it consumed. + // If DeliverMediaSample returns X, the Stream will remove packets 0 to X-1 + // (inclusive) from the list before the next call. + // DeliverMediaSample must also set *samplepos equal to the number of bytes + // processed from packet X (usually zero). + virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos)=0; }; - - - #endif - diff --git a/player.cc b/player.cc index bdacba5..7477586 100644 --- a/player.cc +++ b/player.cc @@ -293,6 +293,8 @@ int Player::playInt(bool* doUnlock) else // do prebuffering { logger->log("Player", Log::DEBUG, "Prebuffering..."); +// afeed.start(); +// vfeed.start(); preBuffering = true; } diff --git a/stream.cc b/stream.cc index 6a4531e..21b847a 100644 --- a/stream.cc +++ b/stream.cc @@ -1,5 +1,5 @@ /* - Copyright 2005 Mark Calderbank + Copyright 2005-2006 Mark Calderbank This file is part of VOMP. @@ -19,14 +19,13 @@ */ #include "stream.h" +#include "log.h" Stream::Stream() { initted = 0; - draintarget=NULL; -#ifdef NEW_DEMUXER - cur_packet_pos=0; -#endif + draintarget = NULL; + cur_packet_pos = 0; } Stream::~Stream() @@ -36,16 +35,14 @@ Stream::~Stream() void Stream::shutdown() { - if (initted) { - free(outbuf); -#ifdef NEW_DEMUXER + if (initted) + { + free(outbuf); #ifdef WIN32 - CloseHandle(mutex); -#endif + CloseHandle(mutex); #endif } initted = 0; - } int Stream::init(DrainTarget* tdt, int bufsize) @@ -54,82 +51,31 @@ int Stream::init(DrainTarget* tdt, int bufsize) if (!outbuf) return 0; draintarget = tdt; bufferSize = bufsize; - bufferHead = 0; - bufferTail = 0; - bufferMark = -1; initted = 1; -#ifdef NEW_DEMUXER #ifndef WIN32 pthread_mutex_init(&mutex, NULL); #else mutex=CreateMutex(NULL,FALSE,NULL); -#endif #endif return 1; } void Stream::flush() { -#ifdef NEW_DEMUXER lock(); mediapackets.clear(); unLock(); if (draintarget) draintarget->ResetTimeOffsets(); -#endif - bufferHead = 0; - bufferTail = 0; - bufferMark = -1; } -#ifndef NEW_DEMUXER -int Stream::put(UCHAR* inbuf, int len) +int Stream::put(const UCHAR* inbuf, int len) { int ret = 0; - int tail = bufferTail; - int head = bufferHead; - if (tail == 0) tail = bufferSize; - - if (head < tail) - { - // The free space is in one continuous chunk. - if (len < tail - head) - { - memcpy(outbuf + head, inbuf, len); - bufferHead += len; - ret = len; - } - } - else if (len <= bufferSize - head) - { - // There is enough space above the Head. - memcpy(outbuf + head, inbuf, len); - if (head + len == bufferSize) - bufferHead = 0; - else - bufferHead += len; - ret = len; - } - else if (len < tail) - { - bufferMark = head; - memcpy(outbuf, inbuf, len); - bufferHead = len; - ret = len; - } - return ret; -} -#else -int Stream::put(UCHAR* inbuf, int len) -{ - int ret = 0; - int tail = bufferTail; - int head = bufferHead; - if (tail == 0) tail = bufferSize; - if (!draintarget) return 0; MediaPacket newPacket; - newPacket.length=len; - newPacket.pos_buffer=0; + newPacket.length = len; + newPacket.pos_buffer = 0; +#ifdef WIN32 newPacket.synched=false; newPacket.disconti=false; newPacket.pts=0; @@ -146,142 +92,66 @@ int Stream::put(UCHAR* inbuf, int len) newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL); newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti); } +#endif - if (head < tail) + lock(); + int front, back; + if (mediapackets.empty()) { - // The free space is in one continuous chunk. - if (len < tail - head) - { - memcpy(outbuf + head, inbuf, len); - bufferHead += len; - ret = len; - newPacket.pos_buffer=head; - lock(); - mediapackets.push_front(newPacket); - unLock(); - } + back = 0; front = bufferSize; } - else if (len <= bufferSize - head) + else { - // There is enough space above the Head. - memcpy(outbuf + head, inbuf, len); - if (head + len == bufferSize) - bufferHead = 0; - else - bufferHead += len; - - newPacket.pos_buffer=head; - lock(); - mediapackets.push_front(newPacket); - unLock(); + front = mediapackets.front().pos_buffer; + back = mediapackets.back().pos_buffer + mediapackets.back().length; + if (back == bufferSize) back = 0; + } + unLock(); + if (back <= front) + { + // The free space (if any) is in one continuous chunk. + if (len <= front - back) ret = len; // Is there enough of it? + } + else if (len <= bufferSize - back) + { + // There is enough space at the end of the buffer ret = len; } - else if (len < tail) + else if (len <= front) { - bufferMark = head; - memcpy(outbuf, inbuf, len); - bufferHead = len; + // There is enough space at the start of the buffer + back = 0; ret = len; - newPacket.pos_buffer=0; - lock(); - mediapackets.push_front(newPacket); - unLock(); } - return ret; -} -#endif - -#ifndef NEW_DEMUXER - -int Stream::drain() -{ - int ret = 0; - int head = bufferHead; - int tail = bufferTail; - int mark = bufferMark; - int written; - if (mark == -1 && tail > head) mark = bufferSize; - - if (mark >= 0) + if (ret) // Nonzero if we managed to find room for the packet { - // Drain up to the marker. -#ifndef WIN32 - written = draintarget->write(outbuf + tail, (mark - tail)); -#else - written=mark-tail; - MILLISLEEP(1); -#endif - if (written < 0) return ret; - ret += written; - if (written == (mark - tail)) - { - bufferMark = -1; - bufferTail = tail = 0; - } - else - { - bufferTail += written; - return ret; - } + memcpy(outbuf + back, inbuf, len); + newPacket.pos_buffer = back; + lock(); + mediapackets.push_back(newPacket); + unLock(); } - - if (tail == head) return ret; // Empty -#ifndef WIN32 - written = draintarget->write(outbuf + tail, (head - tail)); -#else - written=(head - tail); - MILLISLEEP(1); -#endif - if (written < 0) return ret; - ret += written; - bufferTail = tail + written; return ret; } -#else - -int Stream::drain() +bool Stream::drain() { - int ret = 0; - int written=1; -// draintarget=dt; // this is now set in init, is this ok? - - - - if (mediapackets.empty()) { - return 0; - } - // using mediapackets, may be this is slower but it is more flexible - // while (!mediapackets.empty() && written) { - - int head = bufferHead; - int tail = bufferTail; - int mark = bufferMark; - if (mark == -1 && tail > head) mark = bufferSize; + bool ret = false; lock(); - MediaPacket cur_mp=mediapackets.back(); - unLock(); - written=0; - written=draintarget->DeliverMediaSample(cur_mp,outbuf,&cur_packet_pos); - - ret+=written; - - if (cur_packet_pos==cur_mp.length) { - cur_packet_pos=0; - lock(); - mediapackets.pop_back(); - unLock(); - if ((((ULONG)tail)+cur_mp.length) < ((ULONG)mark)) { - bufferTail=tail+cur_mp.length; - } else { - bufferTail=0; - bufferMark=-1; - } - + UINT listlength = mediapackets.size(); + if (listlength != 0) + { + draintarget->PrepareMediaSample(mediapackets, cur_packet_pos); + unLock(); + UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos); + lock(); + if (consumed != 0) ret = true; + if (consumed > listlength) consumed = listlength; + while (consumed--) mediapackets.pop_front(); } - + unLock(); return ret; } @@ -289,7 +159,7 @@ void Stream::lock() { #ifndef WIN32 pthread_mutex_lock(&mutex); - logger->log("Player", Log::DEBUG, "LOCKED"); + //logger->log("Player", Log::DEBUG, "LOCKED"); #else WaitForSingleObject(mutex, INFINITE ); @@ -299,11 +169,9 @@ void Stream::lock() void Stream::unLock() { #ifndef WIN32 - logger->log("Player", Log::DEBUG, "UNLOCKING"); + //logger->log("Player", Log::DEBUG, "UNLOCKING"); pthread_mutex_unlock(&mutex); #else ReleaseMutex(mutex); #endif } - -#endif diff --git a/stream.h b/stream.h index 507855b..d963330 100644 --- a/stream.h +++ b/stream.h @@ -21,6 +21,10 @@ #ifndef STREAM_H #define STREAM_H +#ifndef WIN32 +#include +#endif + #include #ifndef WIN32 #include @@ -32,8 +36,6 @@ #include "defines.h" #include "draintarget.h" - - class Stream { public: @@ -42,11 +44,10 @@ class Stream int init(DrainTarget* tdt, int bufsize); void shutdown(); void flush(); - int put(UCHAR* inbuf, int len); - int drain(); + int put(const UCHAR* inbuf, int len); + bool drain(); private: -#ifdef NEW_DEMUXER MediaPacketList mediapackets; UINT cur_packet_pos; #ifndef WIN32 @@ -56,15 +57,11 @@ class Stream #endif void lock(); void unLock(); -#endif DrainTarget* draintarget; int initted; UCHAR* outbuf; int bufferSize; - volatile int bufferHead; - volatile int bufferTail; - volatile int bufferMark; }; #endif diff --git a/vfeed.cc b/vfeed.cc index 4fd4657..0255b98 100644 --- a/vfeed.cc +++ b/vfeed.cc @@ -53,7 +53,7 @@ void VFeed::release() void VFeed::threadMethod() { - int vlen; + bool vlen; threadWaitForSignal(); // Don't feed video until audio has started diff --git a/video.h b/video.h index 660e3e9..026aee2 100644 --- a/video.h +++ b/video.h @@ -65,10 +65,6 @@ class Video: public DrainTarget virtual ULONG timecodeToFrameNumber(ULLONG timecode)=0; virtual ULLONG getCurrentTimestamp()=0; -#ifndef NEW_DEMUXER - virtual int write(UCHAR* buffer, ULONG length)=0; -#endif - virtual void turnVideoOn(){}; virtual void turnVideoOff(){}; virtual ULLONG frameNumberToTimecode(ULONG timecode) { return 0; }; diff --git a/videomvp.cc b/videomvp.cc index 43e84a7..279a134 100644 --- a/videomvp.cc +++ b/videomvp.cc @@ -366,25 +366,35 @@ int VideoMVP::test2() } #endif - - -#ifdef NEW_DEMUXER - -UINT VideoMVP::DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos) -{ - return 0; +void VideoMVP::PrepareMediaSample(const MediaPacketList& mplist,UINT samplepos) +{ + MediaPacketList::const_iterator iter = mplist.begin(); + deliver_start = iter->pos_buffer + samplepos; + mediapacket_len[0] = deliver_length = iter->length; + deliver_count = 1; + while (++iter != mplist.end() && + iter->pos_buffer == deliver_start + deliver_length) + { + deliver_length += iter->length; + mediapacket_len[deliver_count] = iter->length; + ++deliver_count; + if (deliver_length >= WRITE_LENGTH || + deliver_count == WRITE_PACKETS) break; + } } -void VideoMVP::ResetTimeOffsets() +UINT VideoMVP::DeliverMediaSample(const UCHAR* buffer, UINT* samplepos) { + int written = ::write(fdVideo, buffer + deliver_start, deliver_length); + if (written == (int)deliver_length) { *samplepos = 0; return deliver_count;} + if (written <= 0) return 0; + // Handle a partial write. Is this possible? Should we bother? + UINT i = 0; + while ((written -= mediapacket_len[i]) >= 0) i++; + *samplepos = mediapacket_len[i] + written; + return i; } -#else - -int VideoMVP::write(UCHAR* buffer, ULONG length) +void VideoMVP::ResetTimeOffsets() { - return ::write(fdVideo, buffer, length); } - -#endif - diff --git a/videomvp.h b/videomvp.h index 3f626d2..b8db9c6 100644 --- a/videomvp.h +++ b/videomvp.h @@ -36,6 +36,9 @@ #include "video.h" #include "stb.h" +#define WRITE_LENGTH (32*1024) // Consume up to 32K at a time from Stream +#define WRITE_PACKETS 16 // But no more than 16 packets + class VideoMVP : public Video { public: @@ -68,14 +71,12 @@ class VideoMVP : public Video ULONG timecodeToFrameNumber(ULLONG timecode); ULLONG getCurrentTimestamp(); -#ifdef NEW_DEMUXER - //Writing Data to Videodevice - virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); - virtual long long SetStartOffset(long long curreftime, bool *rsync) { return 0; }; + // Writing Data to Videodevice + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); + virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT* samplepos); + virtual long long SetStartOffset(long long curreftime, bool *rsync) + { return 0; }; virtual void ResetTimeOffsets(); -#else - int write(UCHAR* buffer, ULONG length); -#endif #ifdef DEV int test(); @@ -85,6 +86,9 @@ class VideoMVP : public Video private: int checkSCART(); void setLetterboxBorder(char* border); + + UINT deliver_start, deliver_length, deliver_count; + UINT mediapacket_len[WRITE_PACKETS]; }; #endif diff --git a/videowin.cc b/videowin.cc index d029886..35ddff6 100644 --- a/videowin.cc +++ b/videowin.cc @@ -453,9 +453,24 @@ void VideoWin::CleanupDS() } +void VideoWin::PrepareMediaSample(const MediaPacketList& mplist, + UINT samplepos) +{ + mediapacket = mplist.front(); +} + +UINT VideoWin::DeliverMediaSample(const UCHAR* buffer, UINT *samplepos) +{ + DeliverMediaPacket(mediapacket, buffer, samplepos); + if (*samplepos == mediapacket.length) { + *samplepos = 0; + return 1; + } + else return 0; +} -UINT VideoWin::DeliverMediaSample(MediaPacket packet, - UCHAR* buffer, +UINT VideoWin::DeliverMediaPacket(MediaPacket packet, + const UCHAR* buffer, UINT *samplepos) { /*First Check, if we have an audio sample*/ diff --git a/videowin.h b/videowin.h index 5176d6a..23f558f 100644 --- a/videowin.h +++ b/videowin.h @@ -73,7 +73,12 @@ class VideoWin : public Video ULLONG getCurrentTimestamp(); //Writing Data to Videodevice - virtual UINT DeliverMediaSample(MediaPacket packet, UCHAR* buffer, UINT *samplepos); + virtual void PrepareMediaSample(const MediaPacketList&, UINT samplepos); + virtual UINT DeliverMediaSample(const UCHAR* buffer, UINT *samplepos); + UINT DeliverMediaPacket(MediaPacket packet, const UCHAR* buffer, UINT *samplepos); + private: + MediaPacket mediapacket; + public: int getCurrentAudioMediaSample(IMediaSample** ms); int DeliverAudioMediaSample(); -- 2.39.5