]> git.vomp.tv Git - vompclient.git/commitdiff
New PTS-to-frame mapping method in demuxer
authorMark Calderbank <mark@vomp.tv>
Thu, 15 Jun 2006 00:34:14 +0000 (00:34 +0000)
committerMark Calderbank <mark@vomp.tv>
Thu, 15 Jun 2006 00:34:14 +0000 (00:34 +0000)
demuxer.cc
demuxer.h
demuxervdr.cc
demuxervdr.h
vvideorec.cc

index b29b3989debc7a4bde3be42a1b468d7b612e0802..e2426d52a1e10c9eab0984e53496c4d37f2fafa5 100644 (file)
@@ -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);
index a30ad52f751ff2c27c3cb2214290b19c5bc6e0e1..25b4b35b2118435ecb2a0adfd6498a9b60c29d92 100644 (file)
--- 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();
index a969954db010ad7032f0edd7f252d8c4df078939..b22513e9438f4c7f1dc432922a0d4a7aba5e77ab 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "demuxervdr.h"
+#include "video.h"
 #ifndef WIN32
 #include <endian.h>
 #else
 #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));
+      }
+    }
   }
 }
index 4194fe06db811ec0ff7cb77042630897cf65395d..d1412e06847e8466b34a9444fc080477655802db 100644 (file)
@@ -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);
index 6dd80cdce7d69238be40c5736aa9380bb4ac0521..73626742e3835adb60e673328e30fa5ee4ec8b32 100644 (file)
@@ -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);