JD2022-TU1/main/extern/libwebm/custom/mkvparser/cues.cpp

244 lines
5.6 KiB
C++

#include "cues.hpp"
#include "segment.hpp"
#include "ebmlreadhelpers.hpp"
#include "mkvprofiler.hpp"
#include <stddef.h>
#include <assert.h>
#include <algorithm>
namespace mkvparser
{
Cues::Cues(Segment* pSegment, const EBMLElement& elemInfo)
: m_pSegment(pSegment)
, m_elemInfo(elemInfo)
, m_pos(m_elemInfo.GetPayloadPos())
{
const size_t initialCuePointsSize = 2048;
m_cue_points.reserve(initialCuePointsSize);
}
Cues::~Cues()
{
CuePointVect_t::iterator first = m_cue_points.begin();
CuePointVect_t::iterator last = m_cue_points.end();
for( ; first != last; ++first)
{
CuePoint* const pCP = *first;
assert(pCP);
delete pCP;
}
}
long Cues::GetCount() const
{
return static_cast<long>(m_cue_points.size());
}
bool Cues::DoneParsing() const
{
return (m_pos >= m_elemInfo.GetEndPos());
}
bool Cues::LoadCuePoint()
{
PROFILER_SCOPED_EVENT("webm::Cues::LoadCuePoint");
//odbgstream os;
//os << "Cues::LoadCuePoint" << endl;
const long long stop = m_elemInfo.GetEndPos();
if (m_pos >= stop)
return false; //nothing else to do
IMkvReader* const pReader = m_pSegment->GetReader();
while (m_pos < stop)
{
EBMLElement elemInfo;
long long result = elemInfo.Parse(pReader, m_pos);
assert (result == 0);
if (elemInfo.GetID() != 0x3B) //CuePoint ID
{
m_pos += elemInfo.GetSize(); //consume payload
assert(m_pos <= stop);
continue;
}
const long idx = static_cast<long>(m_cue_points.size());
CuePoint* const pCP = new CuePoint(idx, m_pos);
assert(pCP);
assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == m_pos));
pCP->Load(pReader);
m_cue_points.push_back(pCP);
m_pos += elemInfo.GetSize(); //consume payload
assert(m_pos <= stop);
return true; //yes, we loaded a cue point
}
//return (m_pos < stop);
return false; //no, we did not load a cue point
}
namespace
{
struct CuePointTimeLT
{
CuePointTimeLT(long long time_ns, const Segment* segment)
: m_time_ns(time_ns), m_segment(segment) {}
// one of the entries can be 0 (see usage in Cues::Find)
bool operator()(const CuePoint* left, const CuePoint* right) const
{
if(left)
{
const long long t = left->GetTime(m_segment);
return t < m_time_ns;
}
if (right)
{
const long long t = right->GetTime(m_segment);
return t < m_time_ns;
}
return false;
}
long long m_time_ns;
const Segment* m_segment;
};
}
bool Cues::Find(
long long time_ns,
const Track* pTrack,
const CuePoint*& pCP,
const CuePoint::TrackPosition*& pTP) const
{
assert(time_ns >= 0);
assert(pTrack);
if (m_cue_points.empty())
return false;
// in this lower_bound call, do not use the value (set to 0), the value to compare is set in CuePointTimeLT()
CuePointVect_t:: const_iterator it = std::lower_bound(m_cue_points.begin(),
m_cue_points.end(),
static_cast<const CuePoint*>(0),
CuePointTimeLT(time_ns, m_pSegment));
if (it == m_cue_points.end())
{
--it; // result is one before end
}
else
{
const CuePoint* cp = *it;
assert(cp);
const long long t = cp->GetTime(m_pSegment);
// lower_bound returns the first element which is not less than time_ns
if (t > time_ns)
{
if(it != m_cue_points.begin())
--it; // the result is one before
else
return false; // no cue point before time_ns
}
}
pCP = *it;
assert(pCP);
assert(pCP->GetTime(m_pSegment) <= time_ns);
//TODO: here and elsewhere, it's probably not correct to search
//for the cue point with this time, and then search for a matching
//track. In principle, the matching track could be on some earlier
//cue point, and with our current algorithm, we'd miss it. To make
//this bullet-proof, we'd need to create a secondary structure,
//with a list of cue points that apply to a track, and then search
//that track-based structure for a matching cue point.
pTP = pCP->Find(pTrack);
return (pTP != NULL);
}
const CuePoint* Cues::GetFirst() const
{
if (m_cue_points.empty())
return NULL;
CuePoint* const pCP = m_cue_points.front();
assert(pCP);
assert(pCP->GetTimeCode() >= 0);
return pCP;
}
const CuePoint* Cues::GetLast() const
{
if (m_cue_points.empty())
return NULL;
CuePoint* const pCP = m_cue_points.back();
assert(pCP);
assert(pCP->GetTimeCode() >= 0);
return pCP;
}
const CuePoint* Cues::GetNext(const CuePoint* pCurr) const
{
if (pCurr == NULL)
return NULL;
assert(pCurr->GetTimeCode() >= 0);
assert(m_cue_points.size() >= 1);
long index = pCurr->m_index;
assert(index < static_cast<long>(m_cue_points.size()));
assert(m_cue_points[index] == pCurr);
++index;
if (index >= static_cast<long>(m_cue_points.size()))
return NULL;
CuePoint* const pNext = m_cue_points[index];
assert(pNext);
assert(pNext->GetTimeCode() >= 0);
return pNext;
}
const BlockEntry* Cues::GetBlock(
const CuePoint* pCP,
const CuePoint::TrackPosition* pTP) const
{
if (pCP == NULL)
return NULL;
if (pTP == NULL)
return NULL;
return m_pSegment->GetBlock(*pCP, *pTP);
}
} // namespace mkvparser