*/
#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();
}
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()
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));
+ }
+ }
}
}
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);