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

400 lines
9.8 KiB
C++

#include "tracks.hpp"
#include "imkvreader.hpp"
#include "segment.hpp"
#include "ebmlreadhelpers.hpp"
#include "videotrack.hpp"
#include "audiotrack.hpp"
#include "mkvprofiler.hpp"
#include <stddef.h>
#include <assert.h>
namespace mkvparser
{
Tracks::Tracks(Segment* pSegment, const EBMLElement& elemInfo)
: m_pSegment(pSegment)
, m_elemInfo(elemInfo)
{
}
Tracks::~Tracks()
{
TrackVect_t::iterator first = m_trackEntries.begin();
TrackVect_t::iterator last = m_trackEntries.end();
for (; first != last; ++first)
{
delete (*first);
}
}
long Tracks::Parse()
{
PROFILER_SCOPED_EVENT("webm::Tracks::Parse");
assert(m_trackEntries.empty());
const long long stop = m_elemInfo.GetEndPos();
IMkvReader* const pReader = m_pSegment->GetReader();
long long pos = m_elemInfo.GetPayloadPos();
while (pos < stop)
{
EBMLElement elemInfo;
long long result = elemInfo.Parse(pReader, pos);
if (result != 0)
return static_cast<long>(result);
if (elemInfo.GetPayloadSize() != 0)
{
assert(elemInfo.GetEndPos() <= stop);
if (elemInfo.GetID() == 0x2E) //TrackEntry ID
{
Track* pTrack = NULL;
const long status = ParseTrackEntry(elemInfo, pTrack);
if (status)
return status;
if (pTrack)
m_trackEntries.push_back(pTrack);
}
}
pos += elemInfo.GetSize();
assert(pos <= stop);
}
assert(pos == stop);
return 0; //success
}
long Tracks::ParseTrackEntry(const EBMLElement& elemInfo, Track*& pResult) const
{
PROFILER_SCOPED_EVENT("webm::Tracks::ParseTrackEntry");
if (pResult)
return -1;
IMkvReader* const pReader = m_pSegment->GetReader();
long long pos = elemInfo.GetPayloadPos();
const long long track_stop = elemInfo.GetEndPos();
Track::Info info;
info.type = 0;
info.number = 0;
info.uid = 0;
Track::Settings v;
v.start = -1;
v.size = -1;
Track::Settings a;
a.start = -1;
a.size = -1;
Track::Settings e; //content_encodings_settings;
e.start = -1;
e.size = -1;
long long lacing = 1; //default is true
while (pos < track_stop)
{
EBMLElement trackElemInfo;
long long result = trackElemInfo.Parse(pReader, pos);
if (result != 0)
return static_cast<long>(result);
const long long start = trackElemInfo.GetPayloadPos();
const long long size = trackElemInfo.GetPayloadSize();
if (size < 0)
return E_FILE_FORMAT_INVALID;
long long id = trackElemInfo.GetID();
if (id == 0x60) // VideoSettings ID
{
v.start = start;
v.size = size;
}
else if (id == 0x61) // AudioSettings ID
{
a.start = start;
a.size = size;
}
else if (id == 0x2D80) // ContentEncodings ID
{
e.start = start;
e.size = size;
}
else if (id == 0x33C5) //Track UID
{
if (size > 8)
return E_FILE_FORMAT_INVALID;
info.uid = 0;
long long pos_ = start;
const long long pos_end = start + size;
while (pos_ != pos_end)
{
unsigned char b;
const int status = pReader->Read(pos_, 1, &b);
if (status)
return status;
info.uid <<= 8;
info.uid |= b;
++pos_;
}
}
else if (id == 0x57) //Track Number
{
const long long num = UnserializeUInt(pReader, start, size);
if ((num <= 0) || (num > 127))
return E_FILE_FORMAT_INVALID;
info.number = static_cast<long>(num);
}
else if (id == 0x03) //Track Type
{
const long long type = UnserializeUInt(pReader, start, size);
if ((type <= 0) || (type > 254))
return E_FILE_FORMAT_INVALID;
info.type = static_cast<long>(type);
}
else if (id == 0x136E) //Track Name
{
const long status = UnserializeString(
pReader,
start,
size,
info.nameAsUTF8);
if (status)
return status;
}
else if (id == 0x06) //CodecID
{
const long status = UnserializeString(
pReader,
start,
size,
info.codecId);
if (status)
return status;
}
else if (id == 0x1C) //lacing
{
lacing = UnserializeUInt(pReader, start, size);
if ((lacing < 0) || (lacing > 1))
return E_FILE_FORMAT_INVALID;
}
else if (id == 0x23A2) //Codec Private
{
info.codecPrivate.clear();
const size_t buflen = static_cast<size_t>(size);
if (buflen)
{
info.codecPrivate.reserve(buflen);
if (info.codecPrivate.capacity() < buflen)
return -1;
info.codecPrivate.resize(buflen);
const int status = pReader->Read(start, buflen, &info.codecPrivate[0]);
if (status)
{
return status;
}
}
}
else if (id == 0x058688) //Codec Name
{
const long status = UnserializeString(
pReader,
start,
size,
info.codecNameAsUTF8);
if (status)
return status;
}
pos += trackElemInfo.GetSize(); //consume payload
assert(pos <= track_stop);
}
assert(pos == track_stop);
if (info.number <= 0) //not specified
return E_FILE_FORMAT_INVALID;
if (GetTrackByNumber(info.number))
return E_FILE_FORMAT_INVALID;
if (info.type <= 0) //not specified
return E_FILE_FORMAT_INVALID;
info.lacing = (lacing > 0) ? true : false;
if (info.type == Track::kVideo)
{
if (v.start < 0)
return E_FILE_FORMAT_INVALID;
if (a.start >= 0)
return E_FILE_FORMAT_INVALID;
info.settings = v;
VideoTrack* pTrack = NULL;
const long status = VideoTrack::Parse(m_pSegment,
info,
elemInfo.GetPos(),
elemInfo.GetSize(),
pTrack);
if (status)
return status;
pResult = pTrack;
assert(pResult);
if (e.start >= 0)
pResult->ParseContentEncodingsEntry(e.start, e.size);
}
else if (info.type == Track::kAudio)
{
if (a.start < 0)
return E_FILE_FORMAT_INVALID;
if (v.start >= 0)
return E_FILE_FORMAT_INVALID;
info.settings = a;
AudioTrack* pTrack = NULL;
const long status = AudioTrack::Parse(m_pSegment,
info,
elemInfo.GetPos(),
elemInfo.GetSize(),
pTrack);
if (status)
return status;
pResult = pTrack;
assert(pResult);
if (e.start >= 0)
pResult->ParseContentEncodingsEntry(e.start, e.size);
}
else
{
// neither video nor audio - probably metadata
if (a.start >= 0)
return E_FILE_FORMAT_INVALID;
if (v.start >= 0)
return E_FILE_FORMAT_INVALID;
if (e.start >= 0)
return E_FILE_FORMAT_INVALID;
info.settings.start = -1;
info.settings.size = 0;
Track* pTrack = NULL;
const long status = Track::Create(m_pSegment,
info,
elemInfo.GetPos(),
elemInfo.GetSize(),
pTrack);
if (status)
return status;
pResult = pTrack;
assert(pResult);
}
return 0; //success
}
const Track* Tracks::GetTrackByNumber(long tn) const
{
PROFILER_SCOPED_EVENT("webm::Tracks::GetTrackByNumber");
if (tn < 0)
return NULL;
TrackVect_t::const_iterator first = m_trackEntries.begin();
TrackVect_t::const_iterator last = m_trackEntries.end();
for (; first != last; ++first)
{
Track* const pTrack = *first;
if (pTrack == NULL)
continue;
if (tn == pTrack->GetNumber())
return pTrack;
}
return NULL; //not found
}
const Track* Tracks::GetTrackByIndex(unsigned long idx) const
{
if (idx >= m_trackEntries.size())
return NULL;
return m_trackEntries[idx];
}
const Track* Tracks::GetTrackByType(Track::Type type) const
{
TrackVect_t::const_iterator first = m_trackEntries.begin();
TrackVect_t::const_iterator last = m_trackEntries.end();
for (; first != last; ++first)
{
Track* const pTrack = *first;
if (pTrack == NULL)
continue;
if (type == pTrack->GetType())
return pTrack;
}
return NULL; //not found
}
} // namespace mkvparser