allow cue points to be loaded incrementally

Change-Id: I6c10647c8885d9dcb0d6cb10dd2d6ba94a04ea38
This commit is contained in:
matthewjheaney 2010-10-07 19:07:48 -04:00
parent b607880184
commit 1d0c804fb9
2 changed files with 108 additions and 194 deletions

View File

@ -784,7 +784,6 @@ Segment::Segment(
m_pInfo(NULL),
m_pTracks(NULL),
m_pCues(NULL),
m_cues_off(-1),
m_clusters(NULL),
m_clusterCount(0),
m_clusterPreloadCount(0),
@ -998,16 +997,11 @@ long long Segment::ParseHeaders()
}
else if (id == 0x0C53BB6B) //Cues ID
{
#if 0
if (m_pCues == NULL)
{
m_pCues = new Cues(this, pos, size);
assert(m_pCues); //TODO
}
#else
if (m_cues_off < 0)
m_cues_off = idpos - m_start; //relative to segment start
#endif
}
else if (id == 0x014D9B74) //SeekHead ID
{
@ -1030,10 +1024,6 @@ long long Segment::ParseHeaders()
if (m_pTracks == NULL)
return E_FILE_FORMAT_INVALID;
//TODO: require Cues too?
//No, don't require it, but use its presence or abscense
//to determine whether seeking is allowed.
return 0; //success
}
@ -1247,16 +1237,11 @@ long Segment::LoadCluster()
if (id == 0x0C53BB6B) //Cues ID
{
#if 0
if (m_pCues == NULL)
{
m_pCues = new Cues(this, pos, size);
assert(m_pCues); //TODO
}
#else
if (m_cues_off < 0)
m_cues_off = idpos - m_start;
#endif
m_pos = pos + size; //consume payload
continue;
@ -1617,15 +1602,15 @@ void Segment::ParseSeekHead(long long start, long long size_)
}
void Segment::ParseCues()
void Segment::ParseCues(long long off)
{
if (m_pCues)
return;
//odbgstream os;
//os << "Segment::ParseCues (begin)" << endl;
if ((m_pCues != NULL) || (m_cues_off < 0))
return;
long long pos = m_start + m_cues_off;
long long pos = m_start + off;
const long long stop = m_start + m_size;
long len;
@ -1717,42 +1702,8 @@ void Segment::ParseSeekEntry(
const long long seekPos = m_start + seekOff;
assert(seekPos < (m_start + m_size));
#if 0
if (seekId == 0x0F43B675) //cluster id
{
if (pIndex == NULL)
++m_clusterCount;
else
{
assert(m_clusters);
assert(m_clusterCount > 0);
size_t& index = *pIndex;
assert(index < m_clusterCount);
Cluster*& pCluster = m_clusters[index];
pCluster = Cluster::Parse(this, index, seekOff);
assert(pCluster); //TODO
++index;
}
}
else if (seekId == 0x014D9B74) //SeekHead ID
{
ParseSecondarySeekHead(seekOff, pIndex);
}
#endif
if (seekId == 0x0C53BB6B) //Cues ID
{
#if 0
ParseCues(seekOff);
#else
if (m_cues_off < 0)
m_cues_off = seekOff;
#endif
}
}
@ -1760,14 +1711,18 @@ Cues::Cues(Segment* pSegment, long long start_, long long size_) :
m_pSegment(pSegment),
m_start(start_),
m_size(size_),
m_cue_points(NULL),
m_cue_points_count(0)
m_cue_points_size(0),
m_cue_points_count(0),
m_pos(start_)
{
IMkvReader* const pReader = m_pSegment->m_pReader;
const long long stop = m_start + m_size;
long long pos = m_start;
//odbgstream os;
//os << "Cues: ctor (begin)" << endl;
//First count the cue points
while (pos < stop)
@ -1788,50 +1743,19 @@ Cues::Cues(Segment* pSegment, long long start_, long long size_) :
assert((pos + size) <= stop);
if (id == 0x3B) //CuePoint ID
++m_cue_points_count;
++m_cue_points_size;
pos += size; //consume payload
assert(pos <= stop);
}
assert(m_cue_points_count > 0);
assert(m_cue_points_size > 0); //TODO
m_cue_points = new CuePoint[m_cue_points_count];
//os << "Cues::ctor: count=" << m_cue_points_size << endl;
//Now parse the cue points
m_cue_points = new CuePoint[m_cue_points_size];
CuePoint* pCP = m_cue_points;
pos = m_start;
while (pos < stop)
{
long len;
const long long id = ReadUInt(pReader, pos, len);
assert(id >= 0); //TODO
assert((pos + len) <= stop);
pos += len; //consume ID
const long long size = ReadUInt(pReader, pos, len);
assert(size >= 0);
assert((pos + len) <= stop);
pos += len; //consume Size field
assert((pos + size) <= stop);
if (id == 0x3B) //CuePoint ID
{
CuePoint& cp = *pCP++;
cp.Parse(pReader, pos, size);
}
pos += size; //consume payload
assert(pos <= stop);
}
assert(pos == stop);
assert(size_t(pCP - m_cue_points) == m_cue_points_count);
//os << "Cues: ctor (end)" << endl;
}
@ -1841,6 +1765,74 @@ Cues::~Cues()
}
const CuePoint* Cues::GetFirst() const
{
if ((m_cue_points == NULL) || (m_cue_points_count < 1))
return NULL;
CuePoint& cp = m_cue_points[0];
return &cp;
}
const CuePoint* Cues::GetLast() const
{
if ((m_cue_points == NULL) || (m_cue_points_count < 1))
return NULL;
const size_t idx = m_cue_points_count - 1;
CuePoint& cp = m_cue_points[idx];
return &cp;
}
size_t Cues::LoadCuePoint()
{
if (m_cue_points_count >= m_cue_points_size)
return 0;
IMkvReader* const pReader = m_pSegment->m_pReader;
const long long stop = m_start + m_size;
bool bDone = false;
while (!bDone && (m_pos < stop))
{
long len;
const long long id = ReadUInt(pReader, m_pos, len);
assert(id >= 0); //TODO
assert((m_pos + len) <= stop);
m_pos += len; //consume ID
const long long size = ReadUInt(pReader, m_pos, len);
assert(size >= 0);
assert((m_pos + len) <= stop);
m_pos += len; //consume Size field
assert((m_pos + size) <= stop);
if (id == 0x3B) //CuePoint ID
{
CuePoint& cp = m_cue_points[m_cue_points_count++];
cp.Parse(pReader, m_pos, size);
bDone = true;
}
m_pos += size; //consume payload
assert(m_pos <= stop);
}
const size_t result = m_cue_points_size - m_cue_points_count;
return result;
}
bool Cues::Find(
long long time_ns,
const Track* pTrack,
@ -2560,113 +2552,30 @@ bool Segment::SearchCues(
Cluster*& pCluster,
const BlockEntry*& pBlockEntry)
{
#if 0
if (m_pCues == NULL)
{
if (m_cues_off < 0)
return false;
ParseCues();
assert(m_pCues);
}
#else
if (m_pCues == NULL)
return false;
#endif
if (pTrack->GetType() != 1) //not video
return false; //TODO: for now, just handle video stream
#if 0
if ((m_clusters == NULL) || (m_clusterCount <= 0))
if (m_pCues == NULL)
return false;
const long last_idx = m_clusterCount - 1;
//odbgstream os;
//os << "SearchCues:: loading cue points; time[sec]="
// << (double(time_ns) / 1000000000)
// << endl;
Cluster* const pLastCluster = m_clusters[last_idx];
assert(pLastCluster);
assert(pLastCluster->m_index == last_idx);
assert(pLastCluster->m_pos);
const long long last_pos_ = pLastCluster->m_pos;
const long long last_pos = last_pos_ * ((last_pos_ < 0) ? -1 : 1);
last_pos;
const long long last_ns = pLastCluster->GetTime();
long long time_ns;
if (Unparsed() <= 0) //all clusters loaded
time_ns = time_ns_;
else if (time_ns_ < last_ns)
time_ns = time_ns_;
else
time_ns = last_ns;
const CuePoint* pCP;
const CuePoint::TrackPosition* pTP;
if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
return false; //weird
assert(pCP);
assert(pTP);
assert(pTP->m_track == pTrack->GetNumber());
assert(pTP->m_pos <= last_pos);
//We have the cue point and track position we want,
//so we now need to search for the cluster having
//the indicated position.
Cluster** const ii = m_clusters;
Cluster** i = ii;
Cluster* const pFirstCluster = *i;
assert(pFirstCluster);
const long long first_pos_ = pFirstCluster->m_pos;
const long long first_pos = first_pos_ * ((first_pos_ < 0) ? -1 : 1);
first_pos;
assert(pTP->m_pos >= first_pos);
Cluster** const jj = ii + m_clusterCount;
Cluster** j = jj;
assert(j > i);
for (;;)
while (m_pCues->LoadCuePoint())
{
//INVARIANT:
//[0, i) < pTP->m_pos
//[i, j) ?
//[j, jj) > pTP->m_pos
const CuePoint* const pCP = m_pCues->GetLast();
assert(pCP);
Cluster** const k = i + (j - i) / 2;
assert(k < jj);
const long long ns = pCP->GetTime(this);
pCluster = *k;
assert(pCluster);
const long long pos_ = pCluster->m_pos;
assert(pos_);
const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
if (pos < pTP->m_pos)
i = k + 1;
else if (pos > pTP->m_pos)
j = k;
else
{
pBlockEntry = pCluster->GetEntry(*pCP, *pTP);
assert(pBlockEntry);
return true;
}
assert(i < j);
if (ns >= time_ns)
break;
}
#else
//os << "SearchCues:: loading cue points done" << endl;
const CuePoint* pCP;
const CuePoint::TrackPosition* pTP;
@ -2734,7 +2643,6 @@ bool Segment::SearchCues(
assert(pBlockEntry);
return true;
#endif
}
@ -2750,7 +2658,7 @@ const SegmentInfo* Segment::GetInfo() const
}
const Cues* Segment::GetCues() const
Cues* Segment::GetCues() const
{
return m_pCues;
}

View File

@ -393,9 +393,15 @@ public:
const CuePoint*&,
const CuePoint::TrackPosition*&) const;
size_t LoadCuePoint();
const CuePoint* GetFirst() const;
const CuePoint* GetLast() const;
private:
CuePoint* m_cue_points;
size_t m_cue_points_count;
size_t m_cue_points_size;
long long m_pos;
};
@ -499,15 +505,14 @@ public:
Cluster*&,
const BlockEntry*&);
void ParseCues();
const Cues* GetCues() const;
Cues* GetCues() const;
private:
long long m_pos; //absolute file posn; what has been consumed so far
SegmentInfo* m_pInfo;
Tracks* m_pTracks;
Cues* m_pCues;
long long m_cues_off;
Cluster** m_clusters;
long m_clusterCount; //number of entries for which m_index >= 0
long m_clusterPreloadCount; //number of entries for which m_index < 0
@ -518,6 +523,7 @@ private:
void ParseSeekHead(long long pos, long long size);
void ParseSeekEntry(long long pos, long long size);
void ParseCues(long long);
bool SearchCues(
long long time_ns,