From b6c6e95fd76802fcd4f1ff2eea8d9b1ef6b41011 Mon Sep 17 00:00:00 2001 From: Mark Calderbank Date: Thu, 15 Jun 2006 00:34:14 +0000 Subject: [PATCH] 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.2