From 2d990ae3e894927b01cb0390b88bd549e4427099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Mei=C3=9Fner?= Date: Tue, 28 Oct 2014 19:53:57 +0100 Subject: [PATCH] Rewrite TrackMgr Also: Do not start the video again if it is already playing. Update files from libwebm --- .../pfMoviePlayer/plMoviePlayer.cpp | 163 +- .../pfMoviePlayer/webm/mkvparser.cpp | 10427 +++++++--------- .../pfMoviePlayer/webm/mkvparser.hpp | 1569 ++- .../pfMoviePlayer/webm/mkvreader.cpp | 148 +- .../pfMoviePlayer/webm/mkvreader.hpp | 50 +- 5 files changed, 5611 insertions(+), 6746 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp b/Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp index 73d0d5ff..a1871e57 100644 --- a/Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp +++ b/Sources/Plasma/FeatureLib/pfMoviePlayer/plMoviePlayer.cpp @@ -120,81 +120,48 @@ public: class TrackMgr { - const mkvparser::BlockEntry* blk_entry; - bool valid; - - bool PeekNextBlockEntry(const std::unique_ptr& segment) - { - // Assume that if blk_entry == nullptr, we need to start from the beginning - // Load the current cluster - const mkvparser::Cluster* cluster; - if (blk_entry) - cluster = blk_entry->GetCluster(); - else - cluster = segment->GetFirst(); - - // As long as we have clusters, they contain blocks that we have to process - while (cluster && !cluster->EOS()) { - // If we have no block yet, get the first one, otherwise the next one - if (!blk_entry) - { - SAFE_OP(cluster->GetFirst(blk_entry), "get first block"); - } - else - { - SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block"); - } - - // Are there any blocks left? - while (blk_entry && !blk_entry->EOS()) { - // Is this the next block we want for our track? Awesome, we're done! - if (blk_entry->GetBlock()->GetTrackNumber() == number) - return true; - SAFE_OP(cluster->GetNext(blk_entry, blk_entry), "get next block"); - } - - // No blocks left, go to next cluster - blk_entry = nullptr; - cluster = segment->GetNext(cluster); - } - - // That's it, nothing left... - return false; - } +protected: + const mkvparser::Track* fTrack; + const mkvparser::BlockEntry* fCurrentBlock; + int32_t fStatus; public: - int32_t number; + TrackMgr(const mkvparser::Track* track) : fTrack(track), fCurrentBlock(nullptr), fStatus(0) { } - TrackMgr(int32_t num) : blk_entry(nullptr), valid(true), number(num) { } + const mkvparser::Track* GetTrack() { return fTrack; } - bool GetFrames(plMoviePlayer* p, int64_t movieTime, std::vector& frames) + bool GetFrames(mkvparser::MkvReader* reader, int64_t movieTime, std::vector& frames) { - if (!valid) - return false; + // If we have no block yet, grab the first one + if (!fCurrentBlock) + fStatus = fTrack->GetFirst(fCurrentBlock); - const mkvparser::BlockEntry* prev = blk_entry; - while (valid = PeekNextBlockEntry(p->fSegment)) + // Continue through the blocks until our current movie time + while (fCurrentBlock && fStatus == 0) { - const mkvparser::Block* blk = blk_entry->GetBlock(); - if (blk->GetTime(blk_entry->GetCluster()) <= movieTime) + const mkvparser::Block* block = fCurrentBlock->GetBlock(); + int64_t time = block->GetTime(fCurrentBlock->GetCluster()) - fTrack->GetCodecDelay(); + if (time <= movieTime * 1000000) // Block time is nano seconds { - frames.reserve(frames.size() + blk->GetFrameCount()); - for (int32_t i = 0; i < blk->GetFrameCount(); ++i) + // We want to play this block, add it to the frames buffer + frames.reserve(frames.size() + block->GetFrameCount()); + for (int32_t i = 0; i < block->GetFrameCount(); i++) { - const mkvparser::Block::Frame data = blk->GetFrame(i); + const mkvparser::Block::Frame data = block->GetFrame(i); uint8_t* buf = new uint8_t[data.len]; - data.Read(p->fReader, buf); + data.Read(reader, buf); frames.push_back(std::make_tuple(std::unique_ptr(buf), static_cast(data.len))); } + fStatus = fTrack->GetNext(fCurrentBlock, fCurrentBlock); } else { - blk_entry = prev; + // We've got all frames that have to play... come back for more later! return true; } - prev = blk_entry; } - return true; + + return false; // No more blocks... We're done! } }; @@ -270,13 +237,13 @@ bool plMoviePlayer::IOpenMovie() case mkvparser::Track::kAudio: { if (!fAudioTrack) - fAudioTrack.reset(new TrackMgr(track->GetNumber())); + fAudioTrack.reset(new TrackMgr(track)); break; } case mkvparser::Track::kVideo: { if (!fVideoTrack) - fVideoTrack.reset(new TrackMgr(track->GetNumber())); + fVideoTrack.reset(new TrackMgr(track)); break; } } @@ -325,7 +292,7 @@ void plMoviePlayer::IProcessVideoFrame(const std::vector& frames) void plMoviePlayer::IProcessAudioFrame(const std::vector& frames) { #ifdef VIDEO_AVAILABLE - const unsigned char* data = nullptr; + const uint8_t* data = nullptr; int32_t size = 0; for (auto it = frames.begin(); it != frames.end(); ++it) { @@ -334,7 +301,7 @@ void plMoviePlayer::IProcessAudioFrame(const std::vector& frames) size = std::get<1>(*it); static const int frameSize = 5760; //max packet duration at 48kHz - const mkvparser::AudioTrack* audio = static_cast(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number)); + const mkvparser::AudioTrack* audio = static_cast(fAudioTrack->GetTrack()); int16_t* pcm = new int16_t[frameSize * audio->GetChannels() * sizeof(int16_t)]; int samples = opus_decode(fOpusDecoder, data, size, pcm, frameSize, 0); if (samples < 0) @@ -346,6 +313,9 @@ void plMoviePlayer::IProcessAudioFrame(const std::vector& frames) bool plMoviePlayer::Start() { + if (fPlaying) + return false; + #ifdef VIDEO_AVAILABLE if (!IOpenMovie()) return false; @@ -359,7 +329,7 @@ bool plMoviePlayer::Start() // Need to figure out scaling based on pipe size. plPlateManager& plateMgr = plPlateManager::Instance(); - const mkvparser::VideoTrack* video = static_cast(fSegment->GetTracks()->GetTrackByNumber(fVideoTrack->number)); + const mkvparser::VideoTrack* video = static_cast(fVideoTrack->GetTrack()); float width = (static_cast(video->GetWidth()) / static_cast(plateMgr.GetPipeWidth())) * fScale.fX; float height = (static_cast(video->GetHeight()) / static_cast(plateMgr.GetPipeHeight())) * fScale.fY; @@ -368,7 +338,7 @@ bool plMoviePlayer::Start() fTexture = fPlate->CreateMaterial(static_cast(video->GetWidth()), static_cast(video->GetHeight()), nullptr); //initialize opus - const mkvparser::AudioTrack* audio = static_cast(fSegment->GetTracks()->GetTrackByNumber(fAudioTrack->number)); + const mkvparser::AudioTrack* audio = static_cast(fAudioTrack->GetTrack()); plWAVHeader header; header.fFormatTag = plWAVHeader::kPCMFormatTag; header.fNumChannels = audio->GetChannels(); @@ -392,45 +362,44 @@ bool plMoviePlayer::Start() bool plMoviePlayer::NextFrame() { - if (fPlaying) - { -#ifdef VIDEO_AVAILABLE - // Get our current timecode - int64_t movieTime = 0; - if (fStartTime == 0) - fStartTime = static_cast(hsTimer::GetMilliSeconds()); - else - movieTime = GetMovieTime(); - - std::vector audio; - std::vector video; - uint8_t tracksWithData = 0; - if (fAudioTrack) - { - if (fAudioTrack->GetFrames(this, movieTime, audio)) - tracksWithData++; - } - if (fVideoTrack) - { - if (fVideoTrack->GetFrames(this, movieTime, video)) - tracksWithData++; - } - if (!tracksWithData) - { - Stop(); - return false; - } + if (!fPlaying) + return false; - // Show our mess - IProcessVideoFrame(video); - IProcessAudioFrame(audio); +#ifdef VIDEO_AVAILABLE + // Get our current timecode + int64_t movieTime = 0; + if (fStartTime == 0) + fStartTime = static_cast(hsTimer::GetMilliSeconds()); + else + movieTime = GetMovieTime(); - return true; -#else + std::vector audio; + std::vector video; + uint8_t tracksWithData = 0; + if (fAudioTrack) + { + if (fAudioTrack->GetFrames(fReader, movieTime, audio)) + tracksWithData++; + } + if (fVideoTrack) + { + if (fVideoTrack->GetFrames(fReader, movieTime, video)) + tracksWithData++; + } + if (!tracksWithData) + { + Stop(); return false; -#endif // VIDEO_AVAILABLE } + + // Show our mess + IProcessVideoFrame(video); + IProcessAudioFrame(audio); + + return true; +#else return false; +#endif // VIDEO_AVAILABLE } bool plMoviePlayer::Stop() diff --git a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp index ee1756d3..6ccaa8f8 100644 --- a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp +++ b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.cpp @@ -12,1376 +12,1206 @@ #include #include -mkvparser::IMkvReader::~IMkvReader() -{ -} +#ifdef _MSC_VER +// Disable MSVC warnings that suggest making code non-portable. +#pragma warning(disable : 4996) +#endif -void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) -{ - major = 1; - minor = 0; - build = 0; - revision = 26; +mkvparser::IMkvReader::~IMkvReader() {} + +void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) { + major = 1; + minor = 0; + build = 0; + revision = 29; } -long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) -{ - assert(pReader); - assert(pos >= 0); +long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) { + assert(pReader); + assert(pos >= 0); - int status; + int status; -//#ifdef _DEBUG -// long long total, available; -// status = pReader->Length(&total, &available); -// assert(status >= 0); -// assert((total < 0) || (available <= total)); -// assert(pos < available); -// assert((available - pos) >= 1); //assume here max u-int len is 8 -//#endif + //#ifdef _DEBUG + // long long total, available; + // status = pReader->Length(&total, &available); + // assert(status >= 0); + // assert((total < 0) || (available <= total)); + // assert(pos < available); + // assert((available - pos) >= 1); //assume here max u-int len is 8 + //#endif - len = 1; + len = 1; - unsigned char b; + unsigned char b; - status = pReader->Read(pos, 1, &b); + status = pReader->Read(pos, 1, &b); - if (status < 0) //error or underflow - return status; + if (status < 0) // error or underflow + return status; - if (status > 0) //interpreted as "underflow" - return E_BUFFER_NOT_FULL; + if (status > 0) // interpreted as "underflow" + return E_BUFFER_NOT_FULL; - if (b == 0) //we can't handle u-int values larger than 8 bytes - return E_FILE_FORMAT_INVALID; + if (b == 0) // we can't handle u-int values larger than 8 bytes + return E_FILE_FORMAT_INVALID; - unsigned char m = 0x80; + unsigned char m = 0x80; - while (!(b & m)) - { - m >>= 1; - ++len; - } + while (!(b & m)) { + m >>= 1; + ++len; + } -//#ifdef _DEBUG -// assert((available - pos) >= len); -//#endif + //#ifdef _DEBUG + // assert((available - pos) >= len); + //#endif - long long result = b & (~m); - ++pos; + long long result = b & (~m); + ++pos; - for (int i = 1; i < len; ++i) - { - status = pReader->Read(pos, 1, &b); + for (int i = 1; i < len; ++i) { + status = pReader->Read(pos, 1, &b); - if (status < 0) - { - len = 1; - return status; - } + if (status < 0) { + len = 1; + return status; + } - if (status > 0) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if (status > 0) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result <<= 8; - result |= b; + result <<= 8; + result |= b; - ++pos; - } + ++pos; + } - return result; + return result; } -long long mkvparser::GetUIntLength( - IMkvReader* pReader, - long long pos, - long& len) -{ - assert(pReader); - assert(pos >= 0); +long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos, + long& len) { + assert(pReader); + assert(pos >= 0); - long long total, available; + long long total, available; - int status = pReader->Length(&total, &available); - assert(status >= 0); - assert((total < 0) || (available <= total)); + int status = pReader->Length(&total, &available); + assert(status >= 0); + assert((total < 0) || (available <= total)); - len = 1; + len = 1; - if (pos >= available) - return pos; //too few bytes available + if (pos >= available) + return pos; // too few bytes available - unsigned char b; + unsigned char b; - status = pReader->Read(pos, 1, &b); + status = pReader->Read(pos, 1, &b); - if (status < 0) - return status; + if (status < 0) + return status; - assert(status == 0); + assert(status == 0); - if (b == 0) //we can't handle u-int values larger than 8 bytes - return E_FILE_FORMAT_INVALID; + if (b == 0) // we can't handle u-int values larger than 8 bytes + return E_FILE_FORMAT_INVALID; - unsigned char m = 0x80; + unsigned char m = 0x80; - while (!(b & m)) - { - m >>= 1; - ++len; - } + while (!(b & m)) { + m >>= 1; + ++len; + } - return 0; //success + return 0; // success } +// TODO(vigneshv): This function assumes that unsigned values never have their +// high bit set. +long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos, + long long size) { + assert(pReader); + assert(pos >= 0); -long long mkvparser::UnserializeUInt( - IMkvReader* pReader, - long long pos, - long long size) -{ - assert(pReader); - assert(pos >= 0); - - if ((size <= 0) || (size > 8)) - return E_FILE_FORMAT_INVALID; + if ((size <= 0) || (size > 8)) + return E_FILE_FORMAT_INVALID; - long long result = 0; + long long result = 0; - for (long long i = 0; i < size; ++i) - { - unsigned char b; + for (long long i = 0; i < size; ++i) { + unsigned char b; - const long status = pReader->Read(pos, 1, &b); + const long status = pReader->Read(pos, 1, &b); - if (status < 0) - return status; + if (status < 0) + return status; - result <<= 8; - result |= b; + result <<= 8; + result |= b; - ++pos; - } + ++pos; + } - return result; + return result; } +long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos, + long long size_, double& result) { + assert(pReader); + assert(pos >= 0); -long mkvparser::UnserializeFloat( - IMkvReader* pReader, - long long pos, - long long size_, - double& result) -{ - assert(pReader); - assert(pos >= 0); - - if ((size_ != 4) && (size_ != 8)) - return E_FILE_FORMAT_INVALID; - - const long size = static_cast(size_); + if ((size_ != 4) && (size_ != 8)) + return E_FILE_FORMAT_INVALID; - unsigned char buf[8]; + const long size = static_cast(size_); - const int status = pReader->Read(pos, size, buf); + unsigned char buf[8]; - if (status < 0) //error - return status; + const int status = pReader->Read(pos, size, buf); - if (size == 4) - { - union - { - float f; - unsigned long ff; - }; + if (status < 0) // error + return status; - ff = 0; + if (size == 4) { + union { + float f; + unsigned long ff; + }; - for (int i = 0;;) - { - ff |= buf[i]; + ff = 0; - if (++i >= 4) - break; + for (int i = 0;;) { + ff |= buf[i]; - ff <<= 8; - } + if (++i >= 4) + break; - result = f; + ff <<= 8; } - else - { - assert(size == 8); - union - { - double d; - unsigned long long dd; - }; + result = f; + } else { + assert(size == 8); - dd = 0; + union { + double d; + unsigned long long dd; + }; - for (int i = 0;;) - { - dd |= buf[i]; + dd = 0; - if (++i >= 8) - break; + for (int i = 0;;) { + dd |= buf[i]; - dd <<= 8; - } + if (++i >= 8) + break; - result = d; + dd <<= 8; } - return 0; -} + result = d; + } + return 0; +} -long mkvparser::UnserializeInt( - IMkvReader* pReader, - long long pos, - long size, - long long& result) -{ - assert(pReader); - assert(pos >= 0); - assert(size > 0); - assert(size <= 8); +long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, long size, + long long& result) { + assert(pReader); + assert(pos >= 0); + assert(size > 0); + assert(size <= 8); - { - signed char b; + { + signed char b; - const long status = pReader->Read(pos, 1, (unsigned char*)&b); + const long status = pReader->Read(pos, 1, (unsigned char*)&b); - if (status < 0) - return status; + if (status < 0) + return status; - result = b; + result = b; - ++pos; - } + ++pos; + } - for (long i = 1; i < size; ++i) - { - unsigned char b; + for (long i = 1; i < size; ++i) { + unsigned char b; - const long status = pReader->Read(pos, 1, &b); + const long status = pReader->Read(pos, 1, &b); - if (status < 0) - return status; + if (status < 0) + return status; - result <<= 8; - result |= b; + result <<= 8; + result |= b; - ++pos; - } + ++pos; + } - return 0; //success + return 0; // success } +long mkvparser::UnserializeString(IMkvReader* pReader, long long pos, + long long size_, char*& str) { + delete[] str; + str = NULL; -long mkvparser::UnserializeString( - IMkvReader* pReader, - long long pos, - long long size_, - char*& str) -{ - delete[] str; - str = NULL; - - if (size_ >= LONG_MAX) //we need (size+1) chars - return E_FILE_FORMAT_INVALID; + if (size_ >= LONG_MAX) // we need (size+1) chars + return E_FILE_FORMAT_INVALID; - const long size = static_cast(size_); + const long size = static_cast(size_); - str = new (std::nothrow) char[size+1]; + str = new (std::nothrow) char[size + 1]; - if (str == NULL) - return -1; + if (str == NULL) + return -1; - unsigned char* const buf = reinterpret_cast(str); + unsigned char* const buf = reinterpret_cast(str); - const long status = pReader->Read(pos, size, buf); + const long status = pReader->Read(pos, size, buf); - if (status) - { - delete[] str; - str = NULL; + if (status) { + delete[] str; + str = NULL; - return status; - } + return status; + } - str[size] = '\0'; + str[size] = '\0'; - return 0; //success + return 0; // success } +long mkvparser::ParseElementHeader(IMkvReader* pReader, long long& pos, + long long stop, long long& id, + long long& size) { + if ((stop >= 0) && (pos >= stop)) + return E_FILE_FORMAT_INVALID; -long mkvparser::ParseElementHeader( - IMkvReader* pReader, - long long& pos, - long long stop, - long long& id, - long long& size) -{ - if ((stop >= 0) && (pos >= stop)) - return E_FILE_FORMAT_INVALID; - - long len; + long len; - id = ReadUInt(pReader, pos, len); + id = ReadUInt(pReader, pos, len); - if (id < 0) - return E_FILE_FORMAT_INVALID; + if (id < 0) + return E_FILE_FORMAT_INVALID; - pos += len; //consume id + pos += len; // consume id - if ((stop >= 0) && (pos >= stop)) - return E_FILE_FORMAT_INVALID; + if ((stop >= 0) && (pos >= stop)) + return E_FILE_FORMAT_INVALID; - size = ReadUInt(pReader, pos, len); + size = ReadUInt(pReader, pos, len); - if (size < 0) - return E_FILE_FORMAT_INVALID; + if (size < 0) + return E_FILE_FORMAT_INVALID; - pos += len; //consume length of size + pos += len; // consume length of size - //pos now designates payload + // pos now designates payload - if ((stop >= 0) && ((pos + size) > stop)) - return E_FILE_FORMAT_INVALID; + if ((stop >= 0) && ((pos + size) > stop)) + return E_FILE_FORMAT_INVALID; - return 0; //success + return 0; // success } +bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_, + long long& val) { + assert(pReader); + assert(pos >= 0); -bool mkvparser::Match( - IMkvReader* pReader, - long long& pos, - unsigned long id_, - long long& val) -{ - assert(pReader); - assert(pos >= 0); - - long long total, available; + long long total, available; - const long status = pReader->Length(&total, &available); - assert(status >= 0); - assert((total < 0) || (available <= total)); + const long status = pReader->Length(&total, &available); + assert(status >= 0); + assert((total < 0) || (available <= total)); + if (status < 0) + return false; - long len; + long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); - assert(len > 0); - assert(len <= 8); - assert((pos + len) <= available); + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); + assert(len > 0); + assert(len <= 8); + assert((pos + len) <= available); - if ((unsigned long)id != id_) - return false; + if ((unsigned long)id != id_) + return false; - pos += len; //consume id + pos += len; // consume id - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); - assert(size <= 8); - assert(len > 0); - assert(len <= 8); - assert((pos + len) <= available); + const long long size = ReadUInt(pReader, pos, len); + assert(size >= 0); + assert(size <= 8); + assert(len > 0); + assert(len <= 8); + assert((pos + len) <= available); - pos += len; //consume length of size of payload + pos += len; // consume length of size of payload - val = UnserializeUInt(pReader, pos, size); - assert(val >= 0); + val = UnserializeUInt(pReader, pos, size); + assert(val >= 0); - pos += size; //consume size of payload + pos += size; // consume size of payload - return true; + return true; } -bool mkvparser::Match( - IMkvReader* pReader, - long long& pos, - unsigned long id_, - unsigned char*& buf, - size_t& buflen) -{ - assert(pReader); - assert(pos >= 0); +bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_, + unsigned char*& buf, size_t& buflen) { + assert(pReader); + assert(pos >= 0); - long long total, available; + long long total, available; - long status = pReader->Length(&total, &available); - assert(status >= 0); - assert((total < 0) || (available <= total)); + long status = pReader->Length(&total, &available); + assert(status >= 0); + assert((total < 0) || (available <= total)); + if (status < 0) + return false; - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); - assert(len > 0); - assert(len <= 8); - assert((pos + len) <= available); + long len; + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); + assert(len > 0); + assert(len <= 8); + assert((pos + len) <= available); - if ((unsigned long)id != id_) - return false; + if ((unsigned long)id != id_) + return false; - pos += len; //consume id + pos += len; // consume id - const long long size_ = ReadUInt(pReader, pos, len); - assert(size_ >= 0); - assert(len > 0); - assert(len <= 8); - assert((pos + len) <= available); + const long long size_ = ReadUInt(pReader, pos, len); + assert(size_ >= 0); + assert(len > 0); + assert(len <= 8); + assert((pos + len) <= available); - pos += len; //consume length of size of payload - assert((pos + size_) <= available); + pos += len; // consume length of size of payload + assert((pos + size_) <= available); - const long buflen_ = static_cast(size_); + const long buflen_ = static_cast(size_); - buf = new (std::nothrow) unsigned char[buflen_]; - assert(buf); //TODO + buf = new (std::nothrow) unsigned char[buflen_]; + assert(buf); // TODO - status = pReader->Read(pos, buflen_, buf); - assert(status == 0); //TODO + status = pReader->Read(pos, buflen_, buf); + assert(status == 0); // TODO - buflen = buflen_; + buflen = buflen_; - pos += size_; //consume size of payload - return true; + pos += size_; // consume size of payload + return true; } +namespace mkvparser { -namespace mkvparser -{ - -EBMLHeader::EBMLHeader() : - m_docType(NULL) -{ - Init(); -} +EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); } -EBMLHeader::~EBMLHeader() -{ - delete[] m_docType; -} +EBMLHeader::~EBMLHeader() { delete[] m_docType; } -void EBMLHeader::Init() -{ - m_version = 1; - m_readVersion = 1; - m_maxIdLength = 4; - m_maxSizeLength = 8; +void EBMLHeader::Init() { + m_version = 1; + m_readVersion = 1; + m_maxIdLength = 4; + m_maxSizeLength = 8; - if (m_docType) - { - delete[] m_docType; - m_docType = NULL; - } + if (m_docType) { + delete[] m_docType; + m_docType = NULL; + } - m_docTypeVersion = 1; - m_docTypeReadVersion = 1; + m_docTypeVersion = 1; + m_docTypeReadVersion = 1; } -long long EBMLHeader::Parse( - IMkvReader* pReader, - long long& pos) -{ - assert(pReader); - - long long total, available; +long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) { + assert(pReader); - long status = pReader->Length(&total, &available); + long long total, available; - if (status < 0) //error - return status; + long status = pReader->Length(&total, &available); - pos = 0; - long long end = (available >= 1024) ? 1024 : available; + if (status < 0) // error + return status; - for (;;) - { - unsigned char b = 0; + pos = 0; + long long end = (available >= 1024) ? 1024 : available; - while (pos < end) - { - status = pReader->Read(pos, 1, &b); + for (;;) { + unsigned char b = 0; - if (status < 0) //error - return status; + while (pos < end) { + status = pReader->Read(pos, 1, &b); - if (b == 0x1A) - break; + if (status < 0) // error + return status; - ++pos; - } + if (b == 0x1A) + break; - if (b != 0x1A) - { - if (pos >= 1024) - return E_FILE_FORMAT_INVALID; //don't bother looking anymore + ++pos; + } - if ((total >= 0) && ((total - available) < 5)) - return E_FILE_FORMAT_INVALID; + if (b != 0x1A) { + if (pos >= 1024) + return E_FILE_FORMAT_INVALID; // don't bother looking anymore - return available + 5; //5 = 4-byte ID + 1st byte of size - } + if ((total >= 0) && ((total - available) < 5)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && ((total - pos) < 5)) - return E_FILE_FORMAT_INVALID; + return available + 5; // 5 = 4-byte ID + 1st byte of size + } - if ((available - pos) < 5) - return pos + 5; //try again later + if ((total >= 0) && ((total - pos) < 5)) + return E_FILE_FORMAT_INVALID; - long len; + if ((available - pos) < 5) + return pos + 5; // try again later - const long long result = ReadUInt(pReader, pos, len); + long len; - if (result < 0) //error - return result; + const long long result = ReadUInt(pReader, pos, len); - if (result == 0x0A45DFA3) //EBML Header ID - { - pos += len; //consume ID - break; - } + if (result < 0) // error + return result; - ++pos; //throw away just the 0x1A byte, and try again + if (result == 0x0A45DFA3) { // EBML Header ID + pos += len; // consume ID + break; } - //pos designates start of size field + ++pos; // throw away just the 0x1A byte, and try again + } - //get length of size field + // pos designates start of size field - long len; - long long result = GetUIntLength(pReader, pos, len); + // get length of size field - if (result < 0) //error - return result; + long len; + long long result = GetUIntLength(pReader, pos, len); - if (result > 0) //need more data - return result; + if (result < 0) // error + return result; - assert(len > 0); - assert(len <= 8); + if (result > 0) // need more data + return result; - if ((total >= 0) && ((total - pos) < len)) - return E_FILE_FORMAT_INVALID; + assert(len > 0); + assert(len <= 8); - if ((available - pos) < len) - return pos + len; //try again later + if ((total >= 0) && ((total - pos) < len)) + return E_FILE_FORMAT_INVALID; - //get the EBML header size + if ((available - pos) < len) + return pos + len; // try again later - result = ReadUInt(pReader, pos, len); + // get the EBML header size - if (result < 0) //error - return result; + result = ReadUInt(pReader, pos, len); - pos += len; //consume size field + if (result < 0) // error + return result; - //pos now designates start of payload + pos += len; // consume size field - if ((total >= 0) && ((total - pos) < result)) - return E_FILE_FORMAT_INVALID; + // pos now designates start of payload - if ((available - pos) < result) - return pos + result; + if ((total >= 0) && ((total - pos) < result)) + return E_FILE_FORMAT_INVALID; - end = pos + result; + if ((available - pos) < result) + return pos + result; - Init(); + end = pos + result; - while (pos < end) - { - long long id, size; + Init(); - status = ParseElementHeader( - pReader, - pos, - end, - id, - size); + while (pos < end) { + long long id, size; - if (status < 0) //error - return status; + status = ParseElementHeader(pReader, pos, end, id, size); - if (size == 0) //weird - return E_FILE_FORMAT_INVALID; + if (status < 0) // error + return status; - if (id == 0x0286) //version - { - m_version = UnserializeUInt(pReader, pos, size); + if (size == 0) // weird + return E_FILE_FORMAT_INVALID; - if (m_version <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x02F7) //read version - { - m_readVersion = UnserializeUInt(pReader, pos, size); + if (id == 0x0286) { // version + m_version = UnserializeUInt(pReader, pos, size); - if (m_readVersion <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x02F2) //max id length - { - m_maxIdLength = UnserializeUInt(pReader, pos, size); + if (m_version <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x02F7) { // read version + m_readVersion = UnserializeUInt(pReader, pos, size); - if (m_maxIdLength <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x02F3) //max size length - { - m_maxSizeLength = UnserializeUInt(pReader, pos, size); + if (m_readVersion <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x02F2) { // max id length + m_maxIdLength = UnserializeUInt(pReader, pos, size); - if (m_maxSizeLength <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x0282) //doctype - { - if (m_docType) - return E_FILE_FORMAT_INVALID; + if (m_maxIdLength <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x02F3) { // max size length + m_maxSizeLength = UnserializeUInt(pReader, pos, size); - status = UnserializeString(pReader, pos, size, m_docType); + if (m_maxSizeLength <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x0282) { // doctype + if (m_docType) + return E_FILE_FORMAT_INVALID; - if (status) //error - return status; - } - else if (id == 0x0287) //doctype version - { - m_docTypeVersion = UnserializeUInt(pReader, pos, size); + status = UnserializeString(pReader, pos, size, m_docType); - if (m_docTypeVersion <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x0285) //doctype read version - { - m_docTypeReadVersion = UnserializeUInt(pReader, pos, size); + if (status) // error + return status; + } else if (id == 0x0287) { // doctype version + m_docTypeVersion = UnserializeUInt(pReader, pos, size); - if (m_docTypeReadVersion <= 0) - return E_FILE_FORMAT_INVALID; - } + if (m_docTypeVersion <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x0285) { // doctype read version + m_docTypeReadVersion = UnserializeUInt(pReader, pos, size); - pos += size; + if (m_docTypeReadVersion <= 0) + return E_FILE_FORMAT_INVALID; } - assert(pos == end); - return 0; + pos += size; + } + + assert(pos == end); + return 0; } +Segment::Segment(IMkvReader* pReader, long long elem_start, + // long long elem_size, + long long start, long long size) + : m_pReader(pReader), + m_element_start(elem_start), + // m_element_size(elem_size), + m_start(start), + m_size(size), + m_pos(start), + m_pUnknownSize(0), + m_pSeekHead(NULL), + m_pInfo(NULL), + m_pTracks(NULL), + m_pCues(NULL), + m_pChapters(NULL), + m_clusters(NULL), + m_clusterCount(0), + m_clusterPreloadCount(0), + m_clusterSize(0) {} + +Segment::~Segment() { + const long count = m_clusterCount + m_clusterPreloadCount; + + Cluster** i = m_clusters; + Cluster** j = m_clusters + count; + + while (i != j) { + Cluster* const p = *i++; + assert(p); + + delete p; + } + + delete[] m_clusters; -Segment::Segment( - IMkvReader* pReader, - long long elem_start, - //long long elem_size, - long long start, - long long size) : - m_pReader(pReader), - m_element_start(elem_start), - //m_element_size(elem_size), - m_start(start), - m_size(size), - m_pos(start), - m_pUnknownSize(0), - m_pSeekHead(NULL), - m_pInfo(NULL), - m_pTracks(NULL), - m_pCues(NULL), - m_pChapters(NULL), - m_clusters(NULL), - m_clusterCount(0), - m_clusterPreloadCount(0), - m_clusterSize(0) -{ + delete m_pTracks; + delete m_pInfo; + delete m_pCues; + delete m_pChapters; + delete m_pSeekHead; } +long long Segment::CreateInstance(IMkvReader* pReader, long long pos, + Segment*& pSegment) { + assert(pReader); + assert(pos >= 0); -Segment::~Segment() -{ - const long count = m_clusterCount + m_clusterPreloadCount; - - Cluster** i = m_clusters; - Cluster** j = m_clusters + count; + pSegment = NULL; - while (i != j) - { - Cluster* const p = *i++; - assert(p); + long long total, available; - delete p; - } + const long status = pReader->Length(&total, &available); - delete[] m_clusters; + if (status < 0) // error + return status; - delete m_pTracks; - delete m_pInfo; - delete m_pCues; - delete m_pChapters; - delete m_pSeekHead; -} + if (available < 0) + return -1; + if ((total >= 0) && (available > total)) + return -1; -long long Segment::CreateInstance( - IMkvReader* pReader, - long long pos, - Segment*& pSegment) -{ - assert(pReader); - assert(pos >= 0); + // I would assume that in practice this loop would execute + // exactly once, but we allow for other elements (e.g. Void) + // to immediately follow the EBML header. This is fine for + // the source filter case (since the entire file is available), + // but in the splitter case over a network we should probably + // just give up early. We could for example decide only to + // execute this loop a maximum of, say, 10 times. + // TODO: + // There is an implied "give up early" by only parsing up + // to the available limit. We do do that, but only if the + // total file size is unknown. We could decide to always + // use what's available as our limit (irrespective of whether + // we happen to know the total file length). This would have + // as its sense "parse this much of the file before giving up", + // which a slightly different sense from "try to parse up to + // 10 EMBL elements before giving up". + + for (;;) { + if ((total >= 0) && (pos >= total)) + return E_FILE_FORMAT_INVALID; - pSegment = NULL; + // Read ID + long len; + long long result = GetUIntLength(pReader, pos, len); - long long total, available; + if (result) // error, or too few available bytes + return result; - const long status = pReader->Length(&total, &available); + if ((total >= 0) && ((pos + len) > total)) + return E_FILE_FORMAT_INVALID; - if (status < 0) //error - return status; + if ((pos + len) > available) + return pos + len; - if (available < 0) - return -1; - - if ((total >= 0) && (available > total)) - return -1; - - //I would assume that in practice this loop would execute - //exactly once, but we allow for other elements (e.g. Void) - //to immediately follow the EBML header. This is fine for - //the source filter case (since the entire file is available), - //but in the splitter case over a network we should probably - //just give up early. We could for example decide only to - //execute this loop a maximum of, say, 10 times. - //TODO: - //There is an implied "give up early" by only parsing up - //to the available limit. We do do that, but only if the - //total file size is unknown. We could decide to always - //use what's available as our limit (irrespective of whether - //we happen to know the total file length). This would have - //as its sense "parse this much of the file before giving up", - //which a slightly different sense from "try to parse up to - //10 EMBL elements before giving up". - - for (;;) - { - if ((total >= 0) && (pos >= total)) - return E_FILE_FORMAT_INVALID; - - //Read ID - long len; - long long result = GetUIntLength(pReader, pos, len); - - if (result) //error, or too few available bytes - return result; - - if ((total >= 0) && ((pos + len) > total)) - return E_FILE_FORMAT_INVALID; - - if ((pos + len) > available) - return pos + len; - - const long long idpos = pos; - const long long id = ReadUInt(pReader, pos, len); + const long long idpos = pos; + const long long id = ReadUInt(pReader, pos, len); - if (id < 0) //error - return id; + if (id < 0) // error + return id; - pos += len; //consume ID + pos += len; // consume ID - //Read Size + // Read Size - result = GetUIntLength(pReader, pos, len); + result = GetUIntLength(pReader, pos, len); - if (result) //error, or too few available bytes - return result; + if (result) // error, or too few available bytes + return result; - if ((total >= 0) && ((pos + len) > total)) - return E_FILE_FORMAT_INVALID; + if ((total >= 0) && ((pos + len) > total)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > available) - return pos + len; + if ((pos + len) > available) + return pos + len; - long long size = ReadUInt(pReader, pos, len); + long long size = ReadUInt(pReader, pos, len); - if (size < 0) //error - return size; + if (size < 0) // error + return size; - pos += len; //consume length of size of element + pos += len; // consume length of size of element - //Pos now points to start of payload + // Pos now points to start of payload - //Handle "unknown size" for live streaming of webm files. - const long long unknown_size = (1LL << (7 * len)) - 1; + // Handle "unknown size" for live streaming of webm files. + const long long unknown_size = (1LL << (7 * len)) - 1; - if (id == 0x08538067) //Segment ID - { - if (size == unknown_size) - size = -1; + if (id == 0x08538067) { // Segment ID + if (size == unknown_size) + size = -1; - else if (total < 0) - size = -1; + else if (total < 0) + size = -1; - else if ((pos + size) > total) - size = -1; + else if ((pos + size) > total) + size = -1; - pSegment = new (std::nothrow) Segment( - pReader, - idpos, - //elem_size - pos, - size); + pSegment = new (std::nothrow) Segment(pReader, idpos, + // elem_size + pos, size); - if (pSegment == 0) - return -1; //generic error + if (pSegment == 0) + return -1; // generic error - return 0; //success - } + return 0; // success + } - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && ((pos + size) > total)) - return E_FILE_FORMAT_INVALID; + if ((total >= 0) && ((pos + size) > total)) + return E_FILE_FORMAT_INVALID; - if ((pos + size) > available) - return pos + size; + if ((pos + size) > available) + return pos + size; - pos += size; //consume payload - } + pos += size; // consume payload + } } +long long Segment::ParseHeaders() { + // Outermost (level 0) segment object has been constructed, + // and pos designates start of payload. We need to find the + // inner (level 1) elements. + long long total, available; -long long Segment::ParseHeaders() -{ - //Outermost (level 0) segment object has been constructed, - //and pos designates start of payload. We need to find the - //inner (level 1) elements. - long long total, available; - - const int status = m_pReader->Length(&total, &available); + const int status = m_pReader->Length(&total, &available); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - assert((total < 0) || (available <= total)); + assert((total < 0) || (available <= total)); - const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; - assert((segment_stop < 0) || (total < 0) || (segment_stop <= total)); - assert((segment_stop < 0) || (m_pos <= segment_stop)); + const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; + assert((segment_stop < 0) || (total < 0) || (segment_stop <= total)); + assert((segment_stop < 0) || (m_pos <= segment_stop)); - for (;;) - { - if ((total >= 0) && (m_pos >= total)) - break; + for (;;) { + if ((total >= 0) && (m_pos >= total)) + break; - if ((segment_stop >= 0) && (m_pos >= segment_stop)) - break; + if ((segment_stop >= 0) && (m_pos >= segment_stop)) + break; - long long pos = m_pos; - const long long element_start = pos; + long long pos = m_pos; + const long long element_start = pos; - if ((pos + 1) > available) - return (pos + 1); + if ((pos + 1) > available) + return (pos + 1); - long len; - long long result = GetUIntLength(m_pReader, pos, len); + long len; + long long result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return result; + if (result < 0) // error + return result; - if (result > 0) //underflow (weird) - return (pos + 1); + if (result > 0) // underflow (weird) + return (pos + 1); - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > available) - return pos + len; + if ((pos + len) > available) + return pos + len; - const long long idpos = pos; - const long long id = ReadUInt(m_pReader, idpos, len); + const long long idpos = pos; + const long long id = ReadUInt(m_pReader, idpos, len); - if (id < 0) //error - return id; + if (id < 0) // error + return id; - if (id == 0x0F43B675) //Cluster ID - break; + if (id == 0x0F43B675) // Cluster ID + break; - pos += len; //consume ID + pos += len; // consume ID - if ((pos + 1) > available) - return (pos + 1); + if ((pos + 1) > available) + return (pos + 1); - //Read Size - result = GetUIntLength(m_pReader, pos, len); + // Read Size + result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return result; + if (result < 0) // error + return result; - if (result > 0) //underflow (weird) - return (pos + 1); + if (result > 0) // underflow (weird) + return (pos + 1); - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > available) - return pos + len; + if ((pos + len) > available) + return pos + len; - const long long size = ReadUInt(m_pReader, pos, len); + const long long size = ReadUInt(m_pReader, pos, len); - if (size < 0) //error - return size; + if (size < 0) // error + return size; - pos += len; //consume length of size of element + pos += len; // consume length of size of element - const long long element_size = size + pos - element_start; + const long long element_size = size + pos - element_start; - //Pos now points to start of payload + // Pos now points to start of payload - if ((segment_stop >= 0) && ((pos + size) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + size) > segment_stop)) + return E_FILE_FORMAT_INVALID; - //We read EBML elements either in total or nothing at all. + // We read EBML elements either in total or nothing at all. - if ((pos + size) > available) - return pos + size; + if ((pos + size) > available) + return pos + size; - if (id == 0x0549A966) //Segment Info ID - { - if (m_pInfo) - return E_FILE_FORMAT_INVALID; + if (id == 0x0549A966) { // Segment Info ID + if (m_pInfo) + return E_FILE_FORMAT_INVALID; - m_pInfo = new (std::nothrow) SegmentInfo( - this, - pos, - size, - element_start, - element_size); + m_pInfo = new (std::nothrow) + SegmentInfo(this, pos, size, element_start, element_size); - if (m_pInfo == NULL) - return -1; + if (m_pInfo == NULL) + return -1; - const long status = m_pInfo->Parse(); + const long status = m_pInfo->Parse(); - if (status) - return status; - } - else if (id == 0x0654AE6B) //Tracks ID - { - if (m_pTracks) - return E_FILE_FORMAT_INVALID; + if (status) + return status; + } else if (id == 0x0654AE6B) { // Tracks ID + if (m_pTracks) + return E_FILE_FORMAT_INVALID; - m_pTracks = new (std::nothrow) Tracks(this, - pos, - size, - element_start, - element_size); + m_pTracks = new (std::nothrow) + Tracks(this, pos, size, element_start, element_size); - if (m_pTracks == NULL) - return -1; + if (m_pTracks == NULL) + return -1; - const long status = m_pTracks->Parse(); + const long status = m_pTracks->Parse(); - if (status) - return status; - } - else if (id == 0x0C53BB6B) //Cues ID - { - if (m_pCues == NULL) - { - m_pCues = new (std::nothrow) Cues( - this, - pos, - size, - element_start, - element_size); - - if (m_pCues == NULL) - return -1; - } - } - else if (id == 0x014D9B74) //SeekHead ID - { - if (m_pSeekHead == NULL) - { - m_pSeekHead = new (std::nothrow) SeekHead( - this, - pos, - size, - element_start, - element_size); + if (status) + return status; + } else if (id == 0x0C53BB6B) { // Cues ID + if (m_pCues == NULL) { + m_pCues = new (std::nothrow) + Cues(this, pos, size, element_start, element_size); - if (m_pSeekHead == NULL) - return -1; + if (m_pCues == NULL) + return -1; + } + } else if (id == 0x014D9B74) { // SeekHead ID + if (m_pSeekHead == NULL) { + m_pSeekHead = new (std::nothrow) + SeekHead(this, pos, size, element_start, element_size); - const long status = m_pSeekHead->Parse(); + if (m_pSeekHead == NULL) + return -1; - if (status) - return status; - } - } - else if (id == 0x0043A770) //Chapters ID - { - if (m_pChapters == NULL) - { - m_pChapters = new (std::nothrow) Chapters( - this, - pos, - size, - element_start, - element_size); + const long status = m_pSeekHead->Parse(); - if (m_pChapters == NULL) - return -1; + if (status) + return status; + } + } else if (id == 0x0043A770) { // Chapters ID + if (m_pChapters == NULL) { + m_pChapters = new (std::nothrow) + Chapters(this, pos, size, element_start, element_size); - const long status = m_pChapters->Parse(); + if (m_pChapters == NULL) + return -1; - if (status) - return status; - } - } + const long status = m_pChapters->Parse(); - m_pos = pos + size; //consume payload + if (status) + return status; + } } - assert((segment_stop < 0) || (m_pos <= segment_stop)); + m_pos = pos + size; // consume payload + } - if (m_pInfo == NULL) //TODO: liberalize this behavior - return E_FILE_FORMAT_INVALID; + assert((segment_stop < 0) || (m_pos <= segment_stop)); - if (m_pTracks == NULL) - return E_FILE_FORMAT_INVALID; + if (m_pInfo == NULL) // TODO: liberalize this behavior + return E_FILE_FORMAT_INVALID; - return 0; //success -} + if (m_pTracks == NULL) + return E_FILE_FORMAT_INVALID; + return 0; // success +} -long Segment::LoadCluster( - long long& pos, - long& len) -{ - for (;;) - { - const long result = DoLoadCluster(pos, len); +long Segment::LoadCluster(long long& pos, long& len) { + for (;;) { + const long result = DoLoadCluster(pos, len); - if (result <= 1) - return result; - } + if (result <= 1) + return result; + } } +long Segment::DoLoadCluster(long long& pos, long& len) { + if (m_pos < 0) + return DoLoadClusterUnknownSize(pos, len); -long Segment::DoLoadCluster( - long long& pos, - long& len) -{ - if (m_pos < 0) - return DoLoadClusterUnknownSize(pos, len); - - long long total, avail; + long long total, avail; - long status = m_pReader->Length(&total, &avail); + long status = m_pReader->Length(&total, &avail); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - assert((total < 0) || (avail <= total)); + assert((total < 0) || (avail <= total)); - const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; + const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; - long long cluster_off = -1; //offset relative to start of segment - long long cluster_size = -1; //size of cluster payload + long long cluster_off = -1; // offset relative to start of segment + long long cluster_size = -1; // size of cluster payload - for (;;) - { - if ((total >= 0) && (m_pos >= total)) - return 1; //no more clusters + for (;;) { + if ((total >= 0) && (m_pos >= total)) + return 1; // no more clusters - if ((segment_stop >= 0) && (m_pos >= segment_stop)) - return 1; //no more clusters + if ((segment_stop >= 0) && (m_pos >= segment_stop)) + return 1; // no more clusters - pos = m_pos; + pos = m_pos; - //Read ID + // Read ID - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(m_pReader, pos, len); + long long result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long idpos = pos; - const long long id = ReadUInt(m_pReader, idpos, len); + const long long idpos = pos; + const long long id = ReadUInt(m_pReader, idpos, len); - if (id < 0) //error (or underflow) - return static_cast(id); + if (id < 0) // error (or underflow) + return static_cast(id); - pos += len; //consume ID + pos += len; // consume ID - //Read Size + // Read Size - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(m_pReader, pos, len); + result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(m_pReader, pos, len); + const long long size = ReadUInt(m_pReader, pos, len); - if (size < 0) //error - return static_cast(size); + if (size < 0) // error + return static_cast(size); - pos += len; //consume length of size of element + pos += len; // consume length of size of element - //pos now points to start of payload + // pos now points to start of payload - if (size == 0) //weird - { - m_pos = pos; - continue; - } + if (size == 0) { // weird + m_pos = pos; + continue; + } - const long long unknown_size = (1LL << (7 * len)) - 1; + const long long unknown_size = (1LL << (7 * len)) - 1; -#if 0 //we must handle this to support live webm +#if 0 // we must handle this to support live webm if (size == unknown_size) return E_FILE_FORMAT_INVALID; //TODO: allow this #endif - if ((segment_stop >= 0) && - (size != unknown_size) && - ((pos + size) > segment_stop)) - { - return E_FILE_FORMAT_INVALID; - } + if ((segment_stop >= 0) && (size != unknown_size) && + ((pos + size) > segment_stop)) { + return E_FILE_FORMAT_INVALID; + } -#if 0 //commented-out, to support incremental cluster parsing +#if 0 // commented-out, to support incremental cluster parsing len = static_cast(size); if ((pos + size) > avail) return E_BUFFER_NOT_FULL; #endif - if (id == 0x0C53BB6B) //Cues ID - { - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; //TODO: liberalize - - if (m_pCues == NULL) - { - const long long element_size = (pos - idpos) + size; - - m_pCues = new Cues(this, - pos, - size, - idpos, - element_size); - assert(m_pCues); //TODO - } - - m_pos = pos + size; //consume payload - continue; - } - - if (id != 0x0F43B675) //Cluster ID - { - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; //TODO: liberalize + if (id == 0x0C53BB6B) { // Cues ID + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; // TODO: liberalize - m_pos = pos + size; //consume payload - continue; - } + if (m_pCues == NULL) { + const long long element_size = (pos - idpos) + size; - //We have a cluster. + m_pCues = new Cues(this, pos, size, idpos, element_size); + assert(m_pCues); // TODO + } - cluster_off = idpos - m_start; //relative pos + m_pos = pos + size; // consume payload + continue; + } - if (size != unknown_size) - cluster_size = size; + if (id != 0x0F43B675) { // Cluster ID + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; // TODO: liberalize - break; + m_pos = pos + size; // consume payload + continue; } - assert(cluster_off >= 0); //have cluster + // We have a cluster. - long long pos_; - long len_; + cluster_off = idpos - m_start; // relative pos - status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_); + if (size != unknown_size) + cluster_size = size; - if (status < 0) //error, or underflow - { - pos = pos_; - len = len_; + break; + } - return status; - } + assert(cluster_off >= 0); // have cluster - //status == 0 means "no block entries found" - //status > 0 means "found at least one block entry" - - //TODO: - //The issue here is that the segment increments its own - //pos ptr past the most recent cluster parsed, and then - //starts from there to parse the next cluster. If we - //don't know the size of the current cluster, then we - //must either parse its payload (as we do below), looking - //for the cluster (or cues) ID to terminate the parse. - //This isn't really what we want: rather, we really need - //a way to create the curr cluster object immediately. - //The pity is that cluster::parse can determine its own - //boundary, and we largely duplicate that same logic here. - // - //Maybe we need to get rid of our look-ahead preloading - //in source::parse??? - // - //As we're parsing the blocks in the curr cluster - //(in cluster::parse), we should have some way to signal - //to the segment that we have determined the boundary, - //so it can adjust its own segment::m_pos member. - // - //The problem is that we're asserting in asyncreadinit, - //because we adjust the pos down to the curr seek pos, - //and the resulting adjusted len is > 2GB. I'm suspicious - //that this is even correct, but even if it is, we can't - //be loading that much data in the cache anyway. + long long pos_; + long len_; - const long idx = m_clusterCount; + status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_); - if (m_clusterPreloadCount > 0) - { - assert(idx < m_clusterSize); + if (status < 0) { // error, or underflow + pos = pos_; + len = len_; - Cluster* const pCluster = m_clusters[idx]; - assert(pCluster); - assert(pCluster->m_index < 0); + return status; + } - const long long off = pCluster->GetPosition(); - assert(off >= 0); + // status == 0 means "no block entries found" + // status > 0 means "found at least one block entry" + + // TODO: + // The issue here is that the segment increments its own + // pos ptr past the most recent cluster parsed, and then + // starts from there to parse the next cluster. If we + // don't know the size of the current cluster, then we + // must either parse its payload (as we do below), looking + // for the cluster (or cues) ID to terminate the parse. + // This isn't really what we want: rather, we really need + // a way to create the curr cluster object immediately. + // The pity is that cluster::parse can determine its own + // boundary, and we largely duplicate that same logic here. + // + // Maybe we need to get rid of our look-ahead preloading + // in source::parse??? + // + // As we're parsing the blocks in the curr cluster + //(in cluster::parse), we should have some way to signal + // to the segment that we have determined the boundary, + // so it can adjust its own segment::m_pos member. + // + // The problem is that we're asserting in asyncreadinit, + // because we adjust the pos down to the curr seek pos, + // and the resulting adjusted len is > 2GB. I'm suspicious + // that this is even correct, but even if it is, we can't + // be loading that much data in the cache anyway. + + const long idx = m_clusterCount; + + if (m_clusterPreloadCount > 0) { + assert(idx < m_clusterSize); - if (off == cluster_off) //preloaded already - { - if (status == 0) //no entries found - return E_FILE_FORMAT_INVALID; + Cluster* const pCluster = m_clusters[idx]; + assert(pCluster); + assert(pCluster->m_index < 0); - if (cluster_size >= 0) - pos += cluster_size; - else - { - const long long element_size = pCluster->GetElementSize(); + const long long off = pCluster->GetPosition(); + assert(off >= 0); - if (element_size <= 0) - return E_FILE_FORMAT_INVALID; //TODO: handle this case + if (off == cluster_off) { // preloaded already + if (status == 0) // no entries found + return E_FILE_FORMAT_INVALID; - pos = pCluster->m_element_start + element_size; - } + if (cluster_size >= 0) + pos += cluster_size; + else { + const long long element_size = pCluster->GetElementSize(); - pCluster->m_index = idx; //move from preloaded to loaded - ++m_clusterCount; - --m_clusterPreloadCount; + if (element_size <= 0) + return E_FILE_FORMAT_INVALID; // TODO: handle this case - m_pos = pos; //consume payload - assert((segment_stop < 0) || (m_pos <= segment_stop)); + pos = pCluster->m_element_start + element_size; + } - return 0; //success - } - } + pCluster->m_index = idx; // move from preloaded to loaded + ++m_clusterCount; + --m_clusterPreloadCount; - if (status == 0) //no entries found - { - if (cluster_size < 0) - return E_FILE_FORMAT_INVALID; //TODO: handle this + m_pos = pos; // consume payload + assert((segment_stop < 0) || (m_pos <= segment_stop)); - pos += cluster_size; + return 0; // success + } + } - if ((total >= 0) && (pos >= total)) - { - m_pos = total; - return 1; //no more clusters - } + if (status == 0) { // no entries found + if (cluster_size >= 0) + pos += cluster_size; - if ((segment_stop >= 0) && (pos >= segment_stop)) - { - m_pos = segment_stop; - return 1; //no more clusters - } + if ((total >= 0) && (pos >= total)) { + m_pos = total; + return 1; // no more clusters + } - m_pos = pos; - return 2; //try again + if ((segment_stop >= 0) && (pos >= segment_stop)) { + m_pos = segment_stop; + return 1; // no more clusters } - //status > 0 means we have an entry + m_pos = pos; + return 2; // try again + } - Cluster* const pCluster = Cluster::Create(this, - idx, - cluster_off); - //element_size); - assert(pCluster); + // status > 0 means we have an entry - AppendCluster(pCluster); - assert(m_clusters); - assert(idx < m_clusterSize); - assert(m_clusters[idx] == pCluster); + Cluster* const pCluster = Cluster::Create(this, idx, cluster_off); + // element_size); + assert(pCluster); - if (cluster_size >= 0) - { - pos += cluster_size; + AppendCluster(pCluster); + assert(m_clusters); + assert(idx < m_clusterSize); + assert(m_clusters[idx] == pCluster); - m_pos = pos; - assert((segment_stop < 0) || (m_pos <= segment_stop)); + if (cluster_size >= 0) { + pos += cluster_size; - return 0; - } + m_pos = pos; + assert((segment_stop < 0) || (m_pos <= segment_stop)); + + return 0; + } - m_pUnknownSize = pCluster; - m_pos = -pos; + m_pUnknownSize = pCluster; + m_pos = -pos; - return 0; //partial success, since we have a new cluster + return 0; // partial success, since we have a new cluster - //status == 0 means "no block entries found" +// status == 0 means "no block entries found" - //pos designates start of payload - //m_pos has NOT been adjusted yet (in case we need to come back here) +// pos designates start of payload +// m_pos has NOT been adjusted yet (in case we need to come back here) #if 0 - if (cluster_size < 0) //unknown size - { + if (cluster_size < 0) { //unknown size const long long payload_pos = pos; //absolute pos of cluster payload - for (;;) //determine cluster size - { + for (;;) { //determine cluster size if ((total >= 0) && (pos >= total)) break; @@ -1514,16 +1344,11 @@ long Segment::DoLoadCluster( return 2; //try to find another cluster #endif - } - -long Segment::DoLoadClusterUnknownSize( - long long& pos, - long& len) -{ - assert(m_pos < 0); - assert(m_pUnknownSize); +long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { + assert(m_pos < 0); + assert(m_pUnknownSize); #if 0 assert(m_pUnknownSize->GetElementSize() < 0); //TODO: verify this @@ -1550,8 +1375,7 @@ long Segment::DoLoadClusterUnknownSize( long long element_size = -1; - for (;;) //determine cluster size - { + for (;;) { //determine cluster size if ((total >= 0) && (pos >= total)) { element_size = total - element_start; @@ -1600,8 +1424,7 @@ long Segment::DoLoadClusterUnknownSize( //that we have exhausted the sub-element's inside the cluster //whose ID we parsed earlier. - if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) //Cluster ID or Cues ID - { + if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { //Cluster ID or Cues ID element_size = pos - element_start; assert(element_size > 0); @@ -1678,347 +1501,298 @@ long Segment::DoLoadClusterUnknownSize( return 2; //continue parsing #else - const long status = m_pUnknownSize->Parse(pos, len); + const long status = m_pUnknownSize->Parse(pos, len); - if (status < 0) //error or underflow - return status; + if (status < 0) // error or underflow + return status; - if (status == 0) //parsed a block - return 2; //continue parsing + if (status == 0) // parsed a block + return 2; // continue parsing - assert(status > 0); //nothing left to parse of this cluster + assert(status > 0); // nothing left to parse of this cluster - const long long start = m_pUnknownSize->m_element_start; + const long long start = m_pUnknownSize->m_element_start; - const long long size = m_pUnknownSize->GetElementSize(); - assert(size >= 0); + const long long size = m_pUnknownSize->GetElementSize(); + assert(size >= 0); - pos = start + size; - m_pos = pos; + pos = start + size; + m_pos = pos; - m_pUnknownSize = 0; + m_pUnknownSize = 0; - return 2; //continue parsing + return 2; // continue parsing #endif } +void Segment::AppendCluster(Cluster* pCluster) { + assert(pCluster); + assert(pCluster->m_index >= 0); -void Segment::AppendCluster(Cluster* pCluster) -{ - assert(pCluster); - assert(pCluster->m_index >= 0); - - const long count = m_clusterCount + m_clusterPreloadCount; + const long count = m_clusterCount + m_clusterPreloadCount; - long& size = m_clusterSize; - assert(size >= count); + long& size = m_clusterSize; + assert(size >= count); - const long idx = pCluster->m_index; - assert(idx == m_clusterCount); + const long idx = pCluster->m_index; + assert(idx == m_clusterCount); - if (count >= size) - { - const long n = (size <= 0) ? 2048 : 2*size; + if (count >= size) { + const long n = (size <= 0) ? 2048 : 2 * size; - Cluster** const qq = new Cluster*[n]; - Cluster** q = qq; + Cluster** const qq = new Cluster* [n]; + Cluster** q = qq; - Cluster** p = m_clusters; - Cluster** const pp = p + count; + Cluster** p = m_clusters; + Cluster** const pp = p + count; - while (p != pp) - *q++ = *p++; + while (p != pp) + *q++ = *p++; - delete[] m_clusters; + delete[] m_clusters; - m_clusters = qq; - size = n; - } + m_clusters = qq; + size = n; + } - if (m_clusterPreloadCount > 0) - { - assert(m_clusters); + if (m_clusterPreloadCount > 0) { + assert(m_clusters); - Cluster** const p = m_clusters + m_clusterCount; - assert(*p); - assert((*p)->m_index < 0); + Cluster** const p = m_clusters + m_clusterCount; + assert(*p); + assert((*p)->m_index < 0); - Cluster** q = p + m_clusterPreloadCount; - assert(q < (m_clusters + size)); + Cluster** q = p + m_clusterPreloadCount; + assert(q < (m_clusters + size)); - for (;;) - { - Cluster** const qq = q - 1; - assert((*qq)->m_index < 0); + for (;;) { + Cluster** const qq = q - 1; + assert((*qq)->m_index < 0); - *q = *qq; - q = qq; + *q = *qq; + q = qq; - if (q == p) - break; - } + if (q == p) + break; } + } - m_clusters[idx] = pCluster; - ++m_clusterCount; + m_clusters[idx] = pCluster; + ++m_clusterCount; } +void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { + assert(pCluster); + assert(pCluster->m_index < 0); + assert(idx >= m_clusterCount); -void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) -{ - assert(pCluster); - assert(pCluster->m_index < 0); - assert(idx >= m_clusterCount); - - const long count = m_clusterCount + m_clusterPreloadCount; + const long count = m_clusterCount + m_clusterPreloadCount; - long& size = m_clusterSize; - assert(size >= count); + long& size = m_clusterSize; + assert(size >= count); - if (count >= size) - { - const long n = (size <= 0) ? 2048 : 2*size; + if (count >= size) { + const long n = (size <= 0) ? 2048 : 2 * size; - Cluster** const qq = new Cluster*[n]; - Cluster** q = qq; + Cluster** const qq = new Cluster* [n]; + Cluster** q = qq; - Cluster** p = m_clusters; - Cluster** const pp = p + count; + Cluster** p = m_clusters; + Cluster** const pp = p + count; - while (p != pp) - *q++ = *p++; + while (p != pp) + *q++ = *p++; - delete[] m_clusters; + delete[] m_clusters; - m_clusters = qq; - size = n; - } + m_clusters = qq; + size = n; + } - assert(m_clusters); + assert(m_clusters); - Cluster** const p = m_clusters + idx; + Cluster** const p = m_clusters + idx; - Cluster** q = m_clusters + count; - assert(q >= p); - assert(q < (m_clusters + size)); + Cluster** q = m_clusters + count; + assert(q >= p); + assert(q < (m_clusters + size)); - while (q > p) - { - Cluster** const qq = q - 1; - assert((*qq)->m_index < 0); + while (q > p) { + Cluster** const qq = q - 1; + assert((*qq)->m_index < 0); - *q = *qq; - q = qq; - } + *q = *qq; + q = qq; + } - m_clusters[idx] = pCluster; - ++m_clusterPreloadCount; + m_clusters[idx] = pCluster; + ++m_clusterPreloadCount; } +long Segment::Load() { + assert(m_clusters == NULL); + assert(m_clusterSize == 0); + assert(m_clusterCount == 0); + // assert(m_size >= 0); -long Segment::Load() -{ - assert(m_clusters == NULL); - assert(m_clusterSize == 0); - assert(m_clusterCount == 0); - //assert(m_size >= 0); - - //Outermost (level 0) segment object has been constructed, - //and pos designates start of payload. We need to find the - //inner (level 1) elements. - - const long long header_status = ParseHeaders(); - - if (header_status < 0) //error - return static_cast(header_status); + // Outermost (level 0) segment object has been constructed, + // and pos designates start of payload. We need to find the + // inner (level 1) elements. - if (header_status > 0) //underflow - return E_BUFFER_NOT_FULL; + const long long header_status = ParseHeaders(); - assert(m_pInfo); - assert(m_pTracks); + if (header_status < 0) // error + return static_cast(header_status); - for (;;) - { - const int status = LoadCluster(); + if (header_status > 0) // underflow + return E_BUFFER_NOT_FULL; - if (status < 0) //error - return status; + assert(m_pInfo); + assert(m_pTracks); - if (status >= 1) //no more clusters - return 0; - } -} + for (;;) { + const int status = LoadCluster(); + if (status < 0) // error + return status; -SeekHead::SeekHead( - Segment* pSegment, - long long start, - long long size_, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_start(start), - m_size(size_), - m_element_start(element_start), - m_element_size(element_size), - m_entries(0), - m_entry_count(0), - m_void_elements(0), - m_void_element_count(0) -{ + if (status >= 1) // no more clusters + return 0; + } } +SeekHead::SeekHead(Segment* pSegment, long long start, long long size_, + long long element_start, long long element_size) + : m_pSegment(pSegment), + m_start(start), + m_size(size_), + m_element_start(element_start), + m_element_size(element_size), + m_entries(0), + m_entry_count(0), + m_void_elements(0), + m_void_element_count(0) {} -SeekHead::~SeekHead() -{ - delete[] m_entries; - delete[] m_void_elements; +SeekHead::~SeekHead() { + delete[] m_entries; + delete[] m_void_elements; } +long SeekHead::Parse() { + IMkvReader* const pReader = m_pSegment->m_pReader; -long SeekHead::Parse() -{ - IMkvReader* const pReader = m_pSegment->m_pReader; - - long long pos = m_start; - const long long stop = m_start + m_size; - - //first count the seek head entries + long long pos = m_start; + const long long stop = m_start + m_size; - int entry_count = 0; - int void_element_count = 0; + // first count the seek head entries - while (pos < stop) - { - long long id, size; + int entry_count = 0; + int void_element_count = 0; - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + while (pos < stop) { + long long id, size; - if (status < 0) //error - return status; + const long status = ParseElementHeader(pReader, pos, stop, id, size); - if (id == 0x0DBB) //SeekEntry ID - ++entry_count; - else if (id == 0x6C) //Void ID - ++void_element_count; + if (status < 0) // error + return status; - pos += size; //consume payload - assert(pos <= stop); - } + if (id == 0x0DBB) // SeekEntry ID + ++entry_count; + else if (id == 0x6C) // Void ID + ++void_element_count; - assert(pos == stop); + pos += size; // consume payload + assert(pos <= stop); + } - m_entries = new (std::nothrow) Entry[entry_count]; + assert(pos == stop); - if (m_entries == NULL) - return -1; + m_entries = new (std::nothrow) Entry[entry_count]; - m_void_elements = new (std::nothrow) VoidElement[void_element_count]; + if (m_entries == NULL) + return -1; - if (m_void_elements == NULL) - return -1; + m_void_elements = new (std::nothrow) VoidElement[void_element_count]; - //now parse the entries and void elements + if (m_void_elements == NULL) + return -1; - Entry* pEntry = m_entries; - VoidElement* pVoidElement = m_void_elements; + // now parse the entries and void elements - pos = m_start; + Entry* pEntry = m_entries; + VoidElement* pVoidElement = m_void_elements; - while (pos < stop) - { - const long long idpos = pos; + pos = m_start; - long long id, size; + while (pos < stop) { + const long long idpos = pos; - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + long long id, size; - if (status < 0) //error - return status; + const long status = ParseElementHeader(pReader, pos, stop, id, size); - if (id == 0x0DBB) //SeekEntry ID - { - if (ParseEntry(pReader, pos, size, pEntry)) - { - Entry& e = *pEntry++; + if (status < 0) // error + return status; - e.element_start = idpos; - e.element_size = (pos + size) - idpos; - } - } - else if (id == 0x6C) //Void ID - { - VoidElement& e = *pVoidElement++; + if (id == 0x0DBB) { // SeekEntry ID + if (ParseEntry(pReader, pos, size, pEntry)) { + Entry& e = *pEntry++; - e.element_start = idpos; - e.element_size = (pos + size) - idpos; - } + e.element_start = idpos; + e.element_size = (pos + size) - idpos; + } + } else if (id == 0x6C) { // Void ID + VoidElement& e = *pVoidElement++; - pos += size; //consume payload - assert(pos <= stop); + e.element_start = idpos; + e.element_size = (pos + size) - idpos; } - assert(pos == stop); - - ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries); - assert(count_ >= 0); - assert(count_ <= entry_count); + pos += size; // consume payload + assert(pos <= stop); + } - m_entry_count = static_cast(count_); + assert(pos == stop); - count_ = ptrdiff_t(pVoidElement - m_void_elements); - assert(count_ >= 0); - assert(count_ <= void_element_count); + ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries); + assert(count_ >= 0); + assert(count_ <= entry_count); - m_void_element_count = static_cast(count_); + m_entry_count = static_cast(count_); - return 0; -} + count_ = ptrdiff_t(pVoidElement - m_void_elements); + assert(count_ >= 0); + assert(count_ <= void_element_count); + m_void_element_count = static_cast(count_); -int SeekHead::GetCount() const -{ - return m_entry_count; + return 0; } -const SeekHead::Entry* SeekHead::GetEntry(int idx) const -{ - if (idx < 0) - return 0; +int SeekHead::GetCount() const { return m_entry_count; } - if (idx >= m_entry_count) - return 0; +const SeekHead::Entry* SeekHead::GetEntry(int idx) const { + if (idx < 0) + return 0; - return m_entries + idx; -} + if (idx >= m_entry_count) + return 0; -int SeekHead::GetVoidElementCount() const -{ - return m_void_element_count; + return m_entries + idx; } -const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const -{ - if (idx < 0) - return 0; +int SeekHead::GetVoidElementCount() const { return m_void_element_count; } - if (idx >= m_void_element_count) - return 0; +const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const { + if (idx < 0) + return 0; - return m_void_elements + idx; -} + if (idx >= m_void_element_count) + return 0; + return m_void_elements + idx; +} #if 0 void Segment::ParseCues(long long off) @@ -2069,133 +1843,122 @@ void Segment::ParseCues(long long off) //os << "Segment::ParseCues (end)" << endl; } #else -long Segment::ParseCues( - long long off, - long long& pos, - long& len) -{ - if (m_pCues) - return 0; //success +long Segment::ParseCues(long long off, long long& pos, long& len) { + if (m_pCues) + return 0; // success - if (off < 0) - return -1; + if (off < 0) + return -1; - long long total, avail; + long long total, avail; - const int status = m_pReader->Length(&total, &avail); + const int status = m_pReader->Length(&total, &avail); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - assert((total < 0) || (avail <= total)); + assert((total < 0) || (avail <= total)); - pos = m_start + off; + pos = m_start + off; - if ((total < 0) || (pos >= total)) - return 1; //don't bother parsing cues + if ((total < 0) || (pos >= total)) + return 1; // don't bother parsing cues - const long long element_start = pos; - const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; + const long long element_start = pos; + const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(m_pReader, pos, len); + long long result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //underflow (weird) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if (result > 0) // underflow (weird) + { + len = 1; + return E_BUFFER_NOT_FULL; + } - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long idpos = pos; + const long long idpos = pos; - const long long id = ReadUInt(m_pReader, idpos, len); + const long long id = ReadUInt(m_pReader, idpos, len); - if (id != 0x0C53BB6B) //Cues ID - return E_FILE_FORMAT_INVALID; + if (id != 0x0C53BB6B) // Cues ID + return E_FILE_FORMAT_INVALID; - pos += len; //consume ID - assert((segment_stop < 0) || (pos <= segment_stop)); + pos += len; // consume ID + assert((segment_stop < 0) || (pos <= segment_stop)); - //Read Size + // Read Size - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(m_pReader, pos, len); + result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //underflow (weird) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if (result > 0) // underflow (weird) + { + len = 1; + return E_BUFFER_NOT_FULL; + } - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(m_pReader, pos, len); + const long long size = ReadUInt(m_pReader, pos, len); - if (size < 0) //error - return static_cast(size); + if (size < 0) // error + return static_cast(size); - if (size == 0) //weird, although technically not illegal - return 1; //done + if (size == 0) // weird, although technically not illegal + return 1; // done - pos += len; //consume length of size of element - assert((segment_stop < 0) || (pos <= segment_stop)); + pos += len; // consume length of size of element + assert((segment_stop < 0) || (pos <= segment_stop)); - //Pos now points to start of payload + // Pos now points to start of payload - const long long element_stop = pos + size; + const long long element_stop = pos + size; - if ((segment_stop >= 0) && (element_stop > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && (element_stop > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && (element_stop > total)) - return 1; //don't bother parsing anymore + if ((total >= 0) && (element_stop > total)) + return 1; // don't bother parsing anymore - len = static_cast(size); + len = static_cast(size); - if (element_stop > avail) - return E_BUFFER_NOT_FULL; + if (element_stop > avail) + return E_BUFFER_NOT_FULL; - const long long element_size = element_stop - element_start; + const long long element_size = element_stop - element_start; - m_pCues = new (std::nothrow) Cues( - this, - pos, - size, - element_start, - element_size); - assert(m_pCues); //TODO + m_pCues = + new (std::nothrow) Cues(this, pos, size, element_start, element_size); + assert(m_pCues); // TODO - return 0; //success + return 0; // success } #endif - #if 0 void Segment::ParseSeekEntry( long long start, @@ -2255,302 +2018,269 @@ void Segment::ParseSeekEntry( ParseCues(seekOff); } #else -bool SeekHead::ParseEntry( - IMkvReader* pReader, - long long start, - long long size_, - Entry* pEntry) -{ - if (size_ <= 0) - return false; +bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, + Entry* pEntry) { + if (size_ <= 0) + return false; - long long pos = start; - const long long stop = start + size_; + long long pos = start; + const long long stop = start + size_; - long len; + long len; - //parse the container for the level-1 element ID + // parse the container for the level-1 element ID - const long long seekIdId = ReadUInt(pReader, pos, len); - //seekIdId; + const long long seekIdId = ReadUInt(pReader, pos, len); + // seekIdId; - if (seekIdId != 0x13AB) //SeekID ID - return false; + if (seekIdId != 0x13AB) // SeekID ID + return false; - if ((pos + len) > stop) - return false; + if ((pos + len) > stop) + return false; - pos += len; //consume SeekID id + pos += len; // consume SeekID id - const long long seekIdSize = ReadUInt(pReader, pos, len); + const long long seekIdSize = ReadUInt(pReader, pos, len); - if (seekIdSize <= 0) - return false; + if (seekIdSize <= 0) + return false; - if ((pos + len) > stop) - return false; + if ((pos + len) > stop) + return false; - pos += len; //consume size of field + pos += len; // consume size of field - if ((pos + seekIdSize) > stop) - return false; + if ((pos + seekIdSize) > stop) + return false; - //Note that the SeekId payload really is serialized - //as a "Matroska integer", not as a plain binary value. - //In fact, Matroska requires that ID values in the - //stream exactly match the binary representation as listed - //in the Matroska specification. - // - //This parser is more liberal, and permits IDs to have - //any width. (This could make the representation in the stream - //different from what's in the spec, but it doesn't matter here, - //since we always normalize "Matroska integer" values.) + // Note that the SeekId payload really is serialized + // as a "Matroska integer", not as a plain binary value. + // In fact, Matroska requires that ID values in the + // stream exactly match the binary representation as listed + // in the Matroska specification. + // + // This parser is more liberal, and permits IDs to have + // any width. (This could make the representation in the stream + // different from what's in the spec, but it doesn't matter here, + // since we always normalize "Matroska integer" values.) - pEntry->id = ReadUInt(pReader, pos, len); //payload + pEntry->id = ReadUInt(pReader, pos, len); // payload - if (pEntry->id <= 0) - return false; + if (pEntry->id <= 0) + return false; - if (len != seekIdSize) - return false; + if (len != seekIdSize) + return false; - pos += seekIdSize; //consume SeekID payload + pos += seekIdSize; // consume SeekID payload - const long long seekPosId = ReadUInt(pReader, pos, len); + const long long seekPosId = ReadUInt(pReader, pos, len); - if (seekPosId != 0x13AC) //SeekPos ID - return false; + if (seekPosId != 0x13AC) // SeekPos ID + return false; - if ((pos + len) > stop) - return false; + if ((pos + len) > stop) + return false; - pos += len; //consume id + pos += len; // consume id - const long long seekPosSize = ReadUInt(pReader, pos, len); + const long long seekPosSize = ReadUInt(pReader, pos, len); - if (seekPosSize <= 0) - return false; + if (seekPosSize <= 0) + return false; - if ((pos + len) > stop) - return false; + if ((pos + len) > stop) + return false; - pos += len; //consume size + pos += len; // consume size - if ((pos + seekPosSize) > stop) - return false; + if ((pos + seekPosSize) > stop) + return false; - pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize); + pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize); - if (pEntry->pos < 0) - return false; + if (pEntry->pos < 0) + return false; - pos += seekPosSize; //consume payload + pos += seekPosSize; // consume payload - if (pos != stop) - return false; + if (pos != stop) + return false; - return true; + return true; } #endif +Cues::Cues(Segment* pSegment, long long start_, long long size_, + long long element_start, long long element_size) + : m_pSegment(pSegment), + m_start(start_), + m_size(size_), + m_element_start(element_start), + m_element_size(element_size), + m_cue_points(NULL), + m_count(0), + m_preload_count(0), + m_pos(start_) {} + +Cues::~Cues() { + const long n = m_count + m_preload_count; + + CuePoint** p = m_cue_points; + CuePoint** const q = p + n; + + while (p != q) { + CuePoint* const pCP = *p++; + assert(pCP); -Cues::Cues( - Segment* pSegment, - long long start_, - long long size_, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_start(start_), - m_size(size_), - m_element_start(element_start), - m_element_size(element_size), - m_cue_points(NULL), - m_count(0), - m_preload_count(0), - m_pos(start_) -{ + delete pCP; + } + + delete[] m_cue_points; } +long Cues::GetCount() const { + if (m_cue_points == NULL) + return -1; -Cues::~Cues() -{ - const long n = m_count + m_preload_count; + return m_count; // TODO: really ignore preload count? +} - CuePoint** p = m_cue_points; - CuePoint** const q = p + n; +bool Cues::DoneParsing() const { + const long long stop = m_start + m_size; + return (m_pos >= stop); +} - while (p != q) - { - CuePoint* const pCP = *p++; - assert(pCP); +void Cues::Init() const { + if (m_cue_points) + return; - delete pCP; - } + assert(m_count == 0); + assert(m_preload_count == 0); - delete[] m_cue_points; -} + IMkvReader* const pReader = m_pSegment->m_pReader; + const long long stop = m_start + m_size; + long long pos = m_start; -long Cues::GetCount() const -{ - if (m_cue_points == NULL) - return -1; + long cue_points_size = 0; - return m_count; //TODO: really ignore preload count? -} + while (pos < stop) { + const long long idpos = pos; + long len; -bool Cues::DoneParsing() const -{ - const long long stop = m_start + m_size; - return (m_pos >= stop); -} + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); // TODO + assert((pos + len) <= stop); + pos += len; // consume ID -void Cues::Init() const -{ - if (m_cue_points) - return; + const long long size = ReadUInt(pReader, pos, len); + assert(size >= 0); + assert((pos + len) <= stop); - assert(m_count == 0); - assert(m_preload_count == 0); + pos += len; // consume Size field + assert((pos + size) <= stop); - IMkvReader* const pReader = m_pSegment->m_pReader; - - const long long stop = m_start + m_size; - long long pos = m_start; - - long cue_points_size = 0; - - while (pos < stop) - { - const long long idpos = pos; - - 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 - PreloadCuePoint(cue_points_size, idpos); + if (id == 0x3B) // CuePoint ID + PreloadCuePoint(cue_points_size, idpos); - pos += size; //consume payload - assert(pos <= stop); - } + pos += size; // consume payload + assert(pos <= stop); + } } +void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { + assert(m_count == 0); -void Cues::PreloadCuePoint( - long& cue_points_size, - long long pos) const -{ - assert(m_count == 0); - - if (m_preload_count >= cue_points_size) - { - const long n = (cue_points_size <= 0) ? 2048 : 2*cue_points_size; + if (m_preload_count >= cue_points_size) { + const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; - CuePoint** const qq = new CuePoint*[n]; - CuePoint** q = qq; //beginning of target + CuePoint** const qq = new CuePoint* [n]; + CuePoint** q = qq; // beginning of target - CuePoint** p = m_cue_points; //beginning of source - CuePoint** const pp = p + m_preload_count; //end of source + CuePoint** p = m_cue_points; // beginning of source + CuePoint** const pp = p + m_preload_count; // end of source - while (p != pp) - *q++ = *p++; + while (p != pp) + *q++ = *p++; - delete[] m_cue_points; + delete[] m_cue_points; - m_cue_points = qq; - cue_points_size = n; - } + m_cue_points = qq; + cue_points_size = n; + } - CuePoint* const pCP = new CuePoint(m_preload_count, pos); - m_cue_points[m_preload_count++] = pCP; + CuePoint* const pCP = new CuePoint(m_preload_count, pos); + m_cue_points[m_preload_count++] = pCP; } +bool Cues::LoadCuePoint() const { + // odbgstream os; + // os << "Cues::LoadCuePoint" << endl; -bool Cues::LoadCuePoint() const -{ - //odbgstream os; - //os << "Cues::LoadCuePoint" << endl; - - const long long stop = m_start + m_size; + const long long stop = m_start + m_size; - if (m_pos >= stop) - return false; //nothing else to do + if (m_pos >= stop) + return false; // nothing else to do - Init(); + Init(); - IMkvReader* const pReader = m_pSegment->m_pReader; + IMkvReader* const pReader = m_pSegment->m_pReader; - while (m_pos < stop) - { - const long long idpos = m_pos; + while (m_pos < stop) { + const long long idpos = m_pos; - long len; + long len; - const long long id = ReadUInt(pReader, m_pos, len); - assert(id >= 0); //TODO - assert((m_pos + len) <= stop); + const long long id = ReadUInt(pReader, m_pos, len); + assert(id >= 0); // TODO + assert((m_pos + len) <= stop); - m_pos += len; //consume ID + m_pos += len; // consume ID - const long long size = ReadUInt(pReader, m_pos, len); - assert(size >= 0); - assert((m_pos + len) <= stop); + 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); + m_pos += len; // consume Size field + assert((m_pos + size) <= stop); - if (id != 0x3B) //CuePoint ID - { - m_pos += size; //consume payload - assert(m_pos <= stop); + if (id != 0x3B) { // CuePoint ID + m_pos += size; // consume payload + assert(m_pos <= stop); - continue; - } + continue; + } - assert(m_preload_count > 0); + assert(m_preload_count > 0); - CuePoint* const pCP = m_cue_points[m_count]; - assert(pCP); - assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos)); + CuePoint* const pCP = m_cue_points[m_count]; + assert(pCP); + assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos)); + if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)) + return false; - pCP->Load(pReader); - ++m_count; - --m_preload_count; + pCP->Load(pReader); + ++m_count; + --m_preload_count; - m_pos += size; //consume payload - assert(m_pos <= stop); + m_pos += size; // consume payload + assert(m_pos <= stop); - return true; //yes, we loaded a cue point - } + return true; // yes, we loaded a cue point + } - //return (m_pos < stop); - return false; //no, we did not load a cue point + // return (m_pos < stop); + return false; // no, we did not load a cue point } - -bool Cues::Find( - long long time_ns, - const Track* pTrack, - const CuePoint*& pCP, - const CuePoint::TrackPosition*& pTP) const -{ - assert(time_ns >= 0); - assert(pTrack); +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 0 LoadCuePoint(); //establish invariant @@ -2608,72 +2338,69 @@ bool Cues::Find( assert(pCP); assert(pCP->GetTime(m_pSegment) <= time_ns); #else - if (m_cue_points == NULL) - return false; + if (m_cue_points == NULL) + return false; - if (m_count == 0) - return false; + if (m_count == 0) + return false; - CuePoint** const ii = m_cue_points; - CuePoint** i = ii; + CuePoint** const ii = m_cue_points; + CuePoint** i = ii; - CuePoint** const jj = ii + m_count; - CuePoint** j = jj; + CuePoint** const jj = ii + m_count; + CuePoint** j = jj; - pCP = *i; - assert(pCP); + pCP = *i; + assert(pCP); - if (time_ns <= pCP->GetTime(m_pSegment)) - { - pTP = pCP->Find(pTrack); - return (pTP != NULL); - } + if (time_ns <= pCP->GetTime(m_pSegment)) { + pTP = pCP->Find(pTrack); + return (pTP != NULL); + } - while (i < j) - { - //INVARIANT: - //[ii, i) <= time_ns - //[i, j) ? - //[j, jj) > time_ns + while (i < j) { + // INVARIANT: + //[ii, i) <= time_ns + //[i, j) ? + //[j, jj) > time_ns - CuePoint** const k = i + (j - i) / 2; - assert(k < jj); + CuePoint** const k = i + (j - i) / 2; + assert(k < jj); - CuePoint* const pCP = *k; - assert(pCP); + CuePoint* const pCP = *k; + assert(pCP); - const long long t = pCP->GetTime(m_pSegment); + const long long t = pCP->GetTime(m_pSegment); - if (t <= time_ns) - i = k + 1; - else - j = k; + if (t <= time_ns) + i = k + 1; + else + j = k; - assert(i <= j); - } + assert(i <= j); + } - assert(i == j); - assert(i <= jj); - assert(i > ii); + assert(i == j); + assert(i <= jj); + assert(i > ii); - pCP = *--i; - assert(pCP); - assert(pCP->GetTime(m_pSegment) <= time_ns); + pCP = *--i; + assert(pCP); + assert(pCP->GetTime(m_pSegment) <= time_ns); #endif - //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. + // 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); + pTP = pCP->Find(pTrack); + return (pTP != NULL); } - #if 0 bool Cues::FindNext( long long time_ns, @@ -2733,14 +2460,12 @@ bool Cues::FindNext( } #endif +const CuePoint* Cues::GetFirst() const { + if (m_cue_points == NULL) + return NULL; -const CuePoint* Cues::GetFirst() const -{ - if (m_cue_points == NULL) - return NULL; - - if (m_count == 0) - return NULL; + if (m_count == 0) + return NULL; #if 0 LoadCuePoint(); //init cues @@ -2751,24 +2476,22 @@ const CuePoint* Cues::GetFirst() const return NULL; #endif - CuePoint* const* const pp = m_cue_points; - assert(pp); + CuePoint* const* const pp = m_cue_points; + assert(pp); - CuePoint* const pCP = pp[0]; - assert(pCP); - assert(pCP->GetTimeCode() >= 0); + CuePoint* const pCP = pp[0]; + assert(pCP); + assert(pCP->GetTimeCode() >= 0); - return pCP; + return pCP; } +const CuePoint* Cues::GetLast() const { + if (m_cue_points == NULL) + return NULL; -const CuePoint* Cues::GetLast() const -{ - if (m_cue_points == NULL) - return NULL; - - if (m_count <= 0) - return NULL; + if (m_count <= 0) + return NULL; #if 0 LoadCuePoint(); //init cues @@ -2789,28 +2512,26 @@ const CuePoint* Cues::GetLast() const pCP->Load(m_pSegment->m_pReader); assert(pCP->GetTimeCode() >= 0); #else - const long index = m_count - 1; + const long index = m_count - 1; - CuePoint* const* const pp = m_cue_points; - assert(pp); + CuePoint* const* const pp = m_cue_points; + assert(pp); - CuePoint* const pCP = pp[index]; - assert(pCP); - assert(pCP->GetTimeCode() >= 0); + CuePoint* const pCP = pp[index]; + assert(pCP); + assert(pCP->GetTimeCode() >= 0); #endif - return pCP; + return pCP; } +const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { + if (pCurr == NULL) + return NULL; -const CuePoint* Cues::GetNext(const CuePoint* pCurr) const -{ - if (pCurr == NULL) - return NULL; - - assert(pCurr->GetTimeCode() >= 0); - assert(m_cue_points); - assert(m_count >= 1); + assert(pCurr->GetTimeCode() >= 0); + assert(m_cue_points); + assert(m_count >= 1); #if 0 const size_t count = m_count + m_preload_count; @@ -2832,388 +2553,347 @@ const CuePoint* Cues::GetNext(const CuePoint* pCurr) const pNext->Load(m_pSegment->m_pReader); #else - long index = pCurr->m_index; - assert(index < m_count); + long index = pCurr->m_index; + assert(index < m_count); - CuePoint* const* const pp = m_cue_points; - assert(pp); - assert(pp[index] == pCurr); + CuePoint* const* const pp = m_cue_points; + assert(pp); + assert(pp[index] == pCurr); - ++index; + ++index; - if (index >= m_count) - return NULL; + if (index >= m_count) + return NULL; - CuePoint* const pNext = pp[index]; - assert(pNext); - assert(pNext->GetTimeCode() >= 0); + CuePoint* const pNext = pp[index]; + assert(pNext); + assert(pNext->GetTimeCode() >= 0); #endif - return pNext; + return pNext; } +const BlockEntry* Cues::GetBlock(const CuePoint* pCP, + const CuePoint::TrackPosition* pTP) const { + if (pCP == NULL) + return NULL; -const BlockEntry* Cues::GetBlock( - const CuePoint* pCP, - const CuePoint::TrackPosition* pTP) const -{ - if (pCP == NULL) - return NULL; - - if (pTP == NULL) - return NULL; + if (pTP == NULL) + return NULL; - return m_pSegment->GetBlock(*pCP, *pTP); + return m_pSegment->GetBlock(*pCP, *pTP); } +const BlockEntry* Segment::GetBlock(const CuePoint& cp, + const CuePoint::TrackPosition& tp) { + Cluster** const ii = m_clusters; + Cluster** i = ii; -const BlockEntry* Segment::GetBlock( - const CuePoint& cp, - const CuePoint::TrackPosition& tp) -{ - Cluster** const ii = m_clusters; - Cluster** i = ii; - - const long count = m_clusterCount + m_clusterPreloadCount; + const long count = m_clusterCount + m_clusterPreloadCount; - Cluster** const jj = ii + count; - Cluster** j = jj; + Cluster** const jj = ii + count; + Cluster** j = jj; - while (i < j) - { - //INVARIANT: - //[ii, i) < pTP->m_pos - //[i, j) ? - //[j, jj) > pTP->m_pos + while (i < j) { + // INVARIANT: + //[ii, i) < pTP->m_pos + //[i, j) ? + //[j, jj) > pTP->m_pos - Cluster** const k = i + (j - i) / 2; - assert(k < jj); + Cluster** const k = i + (j - i) / 2; + assert(k < jj); - Cluster* const pCluster = *k; - assert(pCluster); + Cluster* const pCluster = *k; + assert(pCluster); - //const long long pos_ = pCluster->m_pos; - //assert(pos_); - //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); + // const long long pos_ = pCluster->m_pos; + // assert(pos_); + // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); - const long long pos = pCluster->GetPosition(); - assert(pos >= 0); + const long long pos = pCluster->GetPosition(); + assert(pos >= 0); - if (pos < tp.m_pos) - i = k + 1; - else if (pos > tp.m_pos) - j = k; - else - return pCluster->GetEntry(cp, tp); - } + if (pos < tp.m_pos) + i = k + 1; + else if (pos > tp.m_pos) + j = k; + else + return pCluster->GetEntry(cp, tp); + } - assert(i == j); - //assert(Cluster::HasBlockEntries(this, tp.m_pos)); + assert(i == j); + // assert(Cluster::HasBlockEntries(this, tp.m_pos)); - Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1); - assert(pCluster); + Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1); + assert(pCluster); - const ptrdiff_t idx = i - m_clusters; + const ptrdiff_t idx = i - m_clusters; - PreloadCluster(pCluster, idx); - assert(m_clusters); - assert(m_clusterPreloadCount > 0); - assert(m_clusters[idx] == pCluster); + PreloadCluster(pCluster, idx); + assert(m_clusters); + assert(m_clusterPreloadCount > 0); + assert(m_clusters[idx] == pCluster); - return pCluster->GetEntry(cp, tp); + return pCluster->GetEntry(cp, tp); } +const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) { + if (requested_pos < 0) + return 0; -const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) -{ - if (requested_pos < 0) - return 0; + Cluster** const ii = m_clusters; + Cluster** i = ii; - Cluster** const ii = m_clusters; - Cluster** i = ii; + const long count = m_clusterCount + m_clusterPreloadCount; - const long count = m_clusterCount + m_clusterPreloadCount; + Cluster** const jj = ii + count; + Cluster** j = jj; - Cluster** const jj = ii + count; - Cluster** j = jj; + while (i < j) { + // INVARIANT: + //[ii, i) < pTP->m_pos + //[i, j) ? + //[j, jj) > pTP->m_pos - while (i < j) - { - //INVARIANT: - //[ii, i) < pTP->m_pos - //[i, j) ? - //[j, jj) > pTP->m_pos + Cluster** const k = i + (j - i) / 2; + assert(k < jj); - Cluster** const k = i + (j - i) / 2; - assert(k < jj); + Cluster* const pCluster = *k; + assert(pCluster); - Cluster* const pCluster = *k; - assert(pCluster); + // const long long pos_ = pCluster->m_pos; + // assert(pos_); + // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); - //const long long pos_ = pCluster->m_pos; - //assert(pos_); - //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); + const long long pos = pCluster->GetPosition(); + assert(pos >= 0); - const long long pos = pCluster->GetPosition(); - assert(pos >= 0); + if (pos < requested_pos) + i = k + 1; + else if (pos > requested_pos) + j = k; + else + return pCluster; + } - if (pos < requested_pos) - i = k + 1; - else if (pos > requested_pos) - j = k; - else - return pCluster; - } + assert(i == j); + // assert(Cluster::HasBlockEntries(this, tp.m_pos)); - assert(i == j); - //assert(Cluster::HasBlockEntries(this, tp.m_pos)); + Cluster* const pCluster = Cluster::Create(this, -1, requested_pos); + //-1); + assert(pCluster); - Cluster* const pCluster = Cluster::Create( - this, - -1, - requested_pos); - //-1); - assert(pCluster); + const ptrdiff_t idx = i - m_clusters; - const ptrdiff_t idx = i - m_clusters; + PreloadCluster(pCluster, idx); + assert(m_clusters); + assert(m_clusterPreloadCount > 0); + assert(m_clusters[idx] == pCluster); - PreloadCluster(pCluster, idx); - assert(m_clusters); - assert(m_clusterPreloadCount > 0); - assert(m_clusters[idx] == pCluster); + return pCluster; +} - return pCluster; +CuePoint::CuePoint(long idx, long long pos) + : m_element_start(0), + m_element_size(0), + m_index(idx), + m_timecode(-1 * pos), + m_track_positions(NULL), + m_track_positions_count(0) { + assert(pos > 0); } +CuePoint::~CuePoint() { delete[] m_track_positions; } -CuePoint::CuePoint(long idx, long long pos) : - m_element_start(0), - m_element_size(0), - m_index(idx), - m_timecode(-1 * pos), - m_track_positions(NULL), - m_track_positions_count(0) -{ - assert(pos > 0); -} +void CuePoint::Load(IMkvReader* pReader) { + // odbgstream os; + // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; + if (m_timecode >= 0) // already loaded + return; -CuePoint::~CuePoint() -{ - delete[] m_track_positions; -} + assert(m_track_positions == NULL); + assert(m_track_positions_count == 0); + long long pos_ = -m_timecode; + const long long element_start = pos_; -void CuePoint::Load(IMkvReader* pReader) -{ - //odbgstream os; - //os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; + long long stop; - if (m_timecode >= 0) //already loaded - return; + { + long len; - assert(m_track_positions == NULL); - assert(m_track_positions_count == 0); + const long long id = ReadUInt(pReader, pos_, len); + assert(id == 0x3B); // CuePoint ID + if (id != 0x3B) + return; - long long pos_ = -m_timecode; - const long long element_start = pos_; + pos_ += len; // consume ID - long long stop; + const long long size = ReadUInt(pReader, pos_, len); + assert(size >= 0); - { - long len; + pos_ += len; // consume Size field + // pos_ now points to start of payload - const long long id = ReadUInt(pReader, pos_, len); - assert(id == 0x3B); //CuePoint ID - //assert((pos + len) <= stop); + stop = pos_ + size; + } - pos_ += len; //consume ID + const long long element_size = stop - element_start; - const long long size = ReadUInt(pReader, pos_, len); - assert(size >= 0); - //assert((pos + len) <= stop); + long long pos = pos_; - pos_ += len; //consume Size field - //assert((pos + size) <= stop); + // First count number of track positions - //pos_ now points to start of payload + while (pos < stop) { + long len; - stop = pos_ + size; - } + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); // TODO + assert((pos + len) <= stop); - const long long element_size = stop - element_start; + pos += len; // consume ID - long long pos = pos_; + const long long size = ReadUInt(pReader, pos, len); + assert(size >= 0); + assert((pos + len) <= stop); - //First count number of track positions + pos += len; // consume Size field + assert((pos + size) <= stop); - while (pos < stop) - { - long len; + if (id == 0x33) // CueTime ID + m_timecode = UnserializeUInt(pReader, pos, size); - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO - assert((pos + len) <= stop); + else if (id == 0x37) // CueTrackPosition(s) ID + ++m_track_positions_count; - pos += len; //consume ID + pos += size; // consume payload + assert(pos <= stop); + } - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); - assert((pos + len) <= stop); + assert(m_timecode >= 0); + assert(m_track_positions_count > 0); - pos += len; //consume Size field - assert((pos + size) <= stop); + // os << "CuePoint::Load(cont'd): idpos=" << idpos + // << " timecode=" << m_timecode + // << endl; - if (id == 0x33) //CueTime ID - m_timecode = UnserializeUInt(pReader, pos, size); + m_track_positions = new TrackPosition[m_track_positions_count]; - else if (id == 0x37) //CueTrackPosition(s) ID - ++m_track_positions_count; + // Now parse track positions - pos += size; //consume payload - assert(pos <= stop); - } + TrackPosition* p = m_track_positions; + pos = pos_; - assert(m_timecode >= 0); - assert(m_track_positions_count > 0); + while (pos < stop) { + long len; - //os << "CuePoint::Load(cont'd): idpos=" << idpos - // << " timecode=" << m_timecode - // << endl; + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); // TODO + assert((pos + len) <= stop); - m_track_positions = new TrackPosition[m_track_positions_count]; + pos += len; // consume ID - //Now parse track positions + const long long size = ReadUInt(pReader, pos, len); + assert(size >= 0); + assert((pos + len) <= stop); - TrackPosition* p = m_track_positions; - pos = pos_; + pos += len; // consume Size field + assert((pos + size) <= stop); - while (pos < stop) - { - long len; + if (id == 0x37) { // CueTrackPosition(s) ID + TrackPosition& tp = *p++; + tp.Parse(pReader, pos, size); + } - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO - assert((pos + len) <= stop); + pos += size; // consume payload + assert(pos <= stop); + } - pos += len; //consume ID + assert(size_t(p - m_track_positions) == m_track_positions_count); - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); - assert((pos + len) <= stop); + m_element_start = element_start; + m_element_size = element_size; +} - pos += len; //consume Size field - assert((pos + size) <= stop); +void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, + long long size_) { + const long long stop = start_ + size_; + long long pos = start_; - if (id == 0x37) //CueTrackPosition(s) ID - { - TrackPosition& tp = *p++; - tp.Parse(pReader, pos, size); - } + m_track = -1; + m_pos = -1; + m_block = 1; // default - pos += size; //consume payload - assert(pos <= stop); - } + while (pos < stop) { + long len; - assert(size_t(p - m_track_positions) == m_track_positions_count); + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); // TODO + assert((pos + len) <= stop); - m_element_start = element_start; - m_element_size = element_size; -} + 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); -void CuePoint::TrackPosition::Parse( - IMkvReader* pReader, - long long start_, - long long size_) -{ - const long long stop = start_ + size_; - long long pos = start_; + if (id == 0x77) // CueTrack ID + m_track = UnserializeUInt(pReader, pos, size); - m_track = -1; - m_pos = -1; - m_block = 1; //default + else if (id == 0x71) // CueClusterPos ID + m_pos = UnserializeUInt(pReader, pos, size); - 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 + else if (id == 0x1378) // CueBlockNumber + m_block = UnserializeUInt(pReader, pos, size); - 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 == 0x77) //CueTrack ID - m_track = UnserializeUInt(pReader, pos, size); - - else if (id == 0x71) //CueClusterPos ID - m_pos = UnserializeUInt(pReader, pos, size); - - else if (id == 0x1378) //CueBlockNumber - m_block = UnserializeUInt(pReader, pos, size); - - pos += size; //consume payload - assert(pos <= stop); - } + pos += size; // consume payload + assert(pos <= stop); + } - assert(m_pos >= 0); - assert(m_track > 0); - //assert(m_block > 0); + assert(m_pos >= 0); + assert(m_track > 0); + // assert(m_block > 0); } +const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { + assert(pTrack); -const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const -{ - assert(pTrack); + const long long n = pTrack->GetNumber(); - const long long n = pTrack->GetNumber(); + const TrackPosition* i = m_track_positions; + const TrackPosition* const j = i + m_track_positions_count; - const TrackPosition* i = m_track_positions; - const TrackPosition* const j = i + m_track_positions_count; - - while (i != j) - { - const TrackPosition& p = *i++; + while (i != j) { + const TrackPosition& p = *i++; - if (p.m_track == n) - return &p; - } + if (p.m_track == n) + return &p; + } - return NULL; //no matching track number found + return NULL; // no matching track number found } +long long CuePoint::GetTimeCode() const { return m_timecode; } -long long CuePoint::GetTimeCode() const -{ - return m_timecode; -} - -long long CuePoint::GetTime(const Segment* pSegment) const -{ - assert(pSegment); - assert(m_timecode >= 0); +long long CuePoint::GetTime(const Segment* pSegment) const { + assert(pSegment); + assert(m_timecode >= 0); - const SegmentInfo* const pInfo = pSegment->GetInfo(); - assert(pInfo); + const SegmentInfo* const pInfo = pSegment->GetInfo(); + assert(pInfo); - const long long scale = pInfo->GetTimeCodeScale(); - assert(scale >= 1); + const long long scale = pInfo->GetTimeCodeScale(); + assert(scale >= 1); - const long long time = scale * m_timecode; + const long long time = scale * m_timecode; - return time; + return time; } - #if 0 long long Segment::Unparsed() const { @@ -3228,807 +2908,745 @@ long long Segment::Unparsed() const return result; } #else -bool Segment::DoneParsing() const -{ - if (m_size < 0) - { - long long total, avail; +bool Segment::DoneParsing() const { + if (m_size < 0) { + long long total, avail; - const int status = m_pReader->Length(&total, &avail); + const int status = m_pReader->Length(&total, &avail); - if (status < 0) //error - return true; //must assume done + if (status < 0) // error + return true; // must assume done - if (total < 0) - return false; //assume live stream + if (total < 0) + return false; // assume live stream - return (m_pos >= total); - } + return (m_pos >= total); + } - const long long stop = m_start + m_size; + const long long stop = m_start + m_size; - return (m_pos >= stop); + return (m_pos >= stop); } #endif +const Cluster* Segment::GetFirst() const { + if ((m_clusters == NULL) || (m_clusterCount <= 0)) + return &m_eos; -const Cluster* Segment::GetFirst() const -{ - if ((m_clusters == NULL) || (m_clusterCount <= 0)) - return &m_eos; - - Cluster* const pCluster = m_clusters[0]; - assert(pCluster); + Cluster* const pCluster = m_clusters[0]; + assert(pCluster); - return pCluster; + return pCluster; } +const Cluster* Segment::GetLast() const { + if ((m_clusters == NULL) || (m_clusterCount <= 0)) + return &m_eos; -const Cluster* Segment::GetLast() const -{ - if ((m_clusters == NULL) || (m_clusterCount <= 0)) - return &m_eos; - - const long idx = m_clusterCount - 1; + const long idx = m_clusterCount - 1; - Cluster* const pCluster = m_clusters[idx]; - assert(pCluster); + Cluster* const pCluster = m_clusters[idx]; + assert(pCluster); - return pCluster; + return pCluster; } +unsigned long Segment::GetCount() const { return m_clusterCount; } -unsigned long Segment::GetCount() const -{ - return m_clusterCount; -} +const Cluster* Segment::GetNext(const Cluster* pCurr) { + assert(pCurr); + assert(pCurr != &m_eos); + assert(m_clusters); + long idx = pCurr->m_index; -const Cluster* Segment::GetNext(const Cluster* pCurr) -{ - assert(pCurr); + if (idx >= 0) { + assert(m_clusterCount > 0); + assert(idx < m_clusterCount); + assert(pCurr == m_clusters[idx]); - if (pCurr == &m_eos) - { - return &m_eos; - } + ++idx; - assert(m_clusters); + if (idx >= m_clusterCount) + return &m_eos; // caller will LoadCluster as desired - long idx = pCurr->m_index; + Cluster* const pNext = m_clusters[idx]; + assert(pNext); + assert(pNext->m_index >= 0); + assert(pNext->m_index == idx); - if (idx >= 0) - { - assert(m_clusterCount > 0); - assert(idx < m_clusterCount); - assert(pCurr == m_clusters[idx]); + return pNext; + } - ++idx; + assert(m_clusterPreloadCount > 0); - if (idx >= m_clusterCount) - return &m_eos; //caller will LoadCluster as desired + long long pos = pCurr->m_element_start; - Cluster* const pNext = m_clusters[idx]; - assert(pNext); - assert(pNext->m_index >= 0); - assert(pNext->m_index == idx); + assert(m_size >= 0); // TODO + const long long stop = m_start + m_size; // end of segment - return pNext; - } + { + long len; - assert(m_clusterPreloadCount > 0); + long long result = GetUIntLength(m_pReader, pos, len); + assert(result == 0); + assert((pos + len) <= stop); // TODO + if (result != 0) + return NULL; - long long pos = pCurr->m_element_start; + const long long id = ReadUInt(m_pReader, pos, len); + assert(id == 0x0F43B675); // Cluster ID + if (id != 0x0F43B675) + return NULL; - assert(m_size >= 0); //TODO - const long long stop = m_start + m_size; //end of segment + pos += len; // consume ID - { - long len; + // Read Size + result = GetUIntLength(m_pReader, pos, len); + assert(result == 0); // TODO + assert((pos + len) <= stop); // TODO - long long result = GetUIntLength(m_pReader, pos, len); - assert(result == 0); //TODO - assert((pos + len) <= stop); //TODO + const long long size = ReadUInt(m_pReader, pos, len); + assert(size > 0); // TODO + // assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); - const long long id = ReadUInt(m_pReader, pos, len); - assert(id == 0x0F43B675); //Cluster ID //TODO + pos += len; // consume length of size of element + assert((pos + size) <= stop); // TODO - pos += len; //consume ID + // Pos now points to start of payload - //Read Size - result = GetUIntLength(m_pReader, pos, len); - assert(result == 0); //TODO - assert((pos + len) <= stop); //TODO + pos += size; // consume payload + } - const long long size = ReadUInt(m_pReader, pos, len); - assert(size > 0); //TODO - //assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); + long long off_next = 0; - pos += len; //consume length of size of element - assert((pos + size) <= stop); //TODO + while (pos < stop) { + long len; - //Pos now points to start of payload + long long result = GetUIntLength(m_pReader, pos, len); + assert(result == 0); + assert((pos + len) <= stop); // TODO + if (result != 0) + return NULL; - pos += size; //consume payload - } + const long long idpos = pos; // pos of next (potential) cluster - long long off_next = 0; + const long long id = ReadUInt(m_pReader, idpos, len); + assert(id > 0); // TODO - while (pos < stop) - { - long len; + pos += len; // consume ID - long long result = GetUIntLength(m_pReader, pos, len); - assert(result == 0); //TODO - assert((pos + len) <= stop); //TODO + // Read Size + result = GetUIntLength(m_pReader, pos, len); + assert(result == 0); // TODO + assert((pos + len) <= stop); // TODO - const long long idpos = pos; //pos of next (potential) cluster + const long long size = ReadUInt(m_pReader, pos, len); + assert(size >= 0); // TODO - const long long id = ReadUInt(m_pReader, idpos, len); - assert(id > 0); //TODO + pos += len; // consume length of size of element + assert((pos + size) <= stop); // TODO - pos += len; //consume ID + // Pos now points to start of payload - //Read Size - result = GetUIntLength(m_pReader, pos, len); - assert(result == 0); //TODO - assert((pos + len) <= stop); //TODO + if (size == 0) // weird + continue; - const long long size = ReadUInt(m_pReader, pos, len); - assert(size >= 0); //TODO + if (id == 0x0F43B675) { // Cluster ID + const long long off_next_ = idpos - m_start; - pos += len; //consume length of size of element - assert((pos + size) <= stop); //TODO + long long pos_; + long len_; - //Pos now points to start of payload + const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_); - if (size == 0) //weird - continue; + assert(status >= 0); - if (id == 0x0F43B675) //Cluster ID - { - const long long off_next_ = idpos - m_start; + if (status > 0) { + off_next = off_next_; + break; + } + } - long long pos_; - long len_; + pos += size; // consume payload + } - const long status = Cluster::HasBlockEntries( - this, - off_next_, - pos_, - len_); + if (off_next <= 0) + return 0; - assert(status >= 0); + Cluster** const ii = m_clusters + m_clusterCount; + Cluster** i = ii; - if (status > 0) - { - off_next = off_next_; - break; - } - } + Cluster** const jj = ii + m_clusterPreloadCount; + Cluster** j = jj; - pos += size; //consume payload - } + while (i < j) { + // INVARIANT: + //[0, i) < pos_next + //[i, j) ? + //[j, jj) > pos_next - if (off_next <= 0) - return 0; + Cluster** const k = i + (j - i) / 2; + assert(k < jj); - Cluster** const ii = m_clusters + m_clusterCount; - Cluster** i = ii; + Cluster* const pNext = *k; + assert(pNext); + assert(pNext->m_index < 0); - Cluster** const jj = ii + m_clusterPreloadCount; - Cluster** j = jj; + // const long long pos_ = pNext->m_pos; + // assert(pos_); + // pos = pos_ * ((pos_ < 0) ? -1 : 1); - while (i < j) - { - //INVARIANT: - //[0, i) < pos_next - //[i, j) ? - //[j, jj) > pos_next + pos = pNext->GetPosition(); - Cluster** const k = i + (j - i) / 2; - assert(k < jj); + if (pos < off_next) + i = k + 1; + else if (pos > off_next) + j = k; + else + return pNext; + } - Cluster* const pNext = *k; - assert(pNext); - assert(pNext->m_index < 0); + assert(i == j); - //const long long pos_ = pNext->m_pos; - //assert(pos_); - //pos = pos_ * ((pos_ < 0) ? -1 : 1); + Cluster* const pNext = Cluster::Create(this, -1, off_next); + assert(pNext); - pos = pNext->GetPosition(); + const ptrdiff_t idx_next = i - m_clusters; // insertion position - if (pos < off_next) - i = k + 1; - else if (pos > off_next) - j = k; - else - return pNext; - } + PreloadCluster(pNext, idx_next); + assert(m_clusters); + assert(idx_next < m_clusterSize); + assert(m_clusters[idx_next] == pNext); - assert(i == j); + return pNext; +} - Cluster* const pNext = Cluster::Create(this, - -1, - off_next); - assert(pNext); +long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult, + long long& pos, long& len) { + assert(pCurr); + assert(!pCurr->EOS()); + assert(m_clusters); - const ptrdiff_t idx_next = i - m_clusters; //insertion position + pResult = 0; - PreloadCluster(pNext, idx_next); - assert(m_clusters); - assert(idx_next < m_clusterSize); - assert(m_clusters[idx_next] == pNext); + if (pCurr->m_index >= 0) { // loaded (not merely preloaded) + assert(m_clusters[pCurr->m_index] == pCurr); - return pNext; -} + const long next_idx = pCurr->m_index + 1; + if (next_idx < m_clusterCount) { + pResult = m_clusters[next_idx]; + return 0; // success + } -long Segment::ParseNext( - const Cluster* pCurr, - const Cluster*& pResult, - long long& pos, - long& len) -{ - assert(pCurr); - assert(!pCurr->EOS()); - assert(m_clusters); + // curr cluster is last among loaded + + const long result = LoadCluster(pos, len); - pResult = 0; + if (result < 0) // error or underflow + return result; - if (pCurr->m_index >= 0) //loaded (not merely preloaded) + if (result > 0) // no more clusters { - assert(m_clusters[pCurr->m_index] == pCurr); + // pResult = &m_eos; + return 1; + } - const long next_idx = pCurr->m_index + 1; + pResult = GetLast(); + return 0; // success + } - if (next_idx < m_clusterCount) - { - pResult = m_clusters[next_idx]; - return 0; //success - } + assert(m_pos > 0); - //curr cluster is last among loaded + long long total, avail; - const long result = LoadCluster(pos, len); + long status = m_pReader->Length(&total, &avail); - if (result < 0) //error or underflow - return result; + if (status < 0) // error + return status; - if (result > 0) //no more clusters - { - //pResult = &m_eos; - return 1; - } + assert((total < 0) || (avail <= total)); + + const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; - pResult = GetLast(); - return 0; //success + // interrogate curr cluster + + pos = pCurr->m_element_start; + + if (pCurr->m_element_size >= 0) + pos += pCurr->m_element_size; + else { + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; } - assert(m_pos > 0); + long long result = GetUIntLength(m_pReader, pos, len); - long long total, avail; + if (result < 0) // error + return static_cast(result); - long status = m_pReader->Length(&total, &avail); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (status < 0) //error - return status; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - assert((total < 0) || (avail <= total)); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; + const long long id = ReadUInt(m_pReader, pos, len); - //interrogate curr cluster + if (id != 0x0F43B675) // weird: not Cluster ID + return -1; - pos = pCurr->m_element_start; + pos += len; // consume ID - if (pCurr->m_element_size >= 0) - pos += pCurr->m_element_size; - else - { - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + // Read Size - long long result = GetUIntLength(m_pReader, pos, len); + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if (result < 0) //error - return static_cast(result); + result = GetUIntLength(m_pReader, pos, len); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result < 0) // error + return static_cast(result); - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - const long long id = ReadUInt(m_pReader, pos, len); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if (id != 0x0F43B675) //weird: not Cluster ID - return -1; + const long long size = ReadUInt(m_pReader, pos, len); - pos += len; //consume ID + if (size < 0) // error + return static_cast(size); - //Read Size + pos += len; // consume size field - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + const long long unknown_size = (1LL << (7 * len)) - 1; - result = GetUIntLength(m_pReader, pos, len); + if (size == unknown_size) // TODO: should never happen + return E_FILE_FORMAT_INVALID; // TODO: resolve this - if (result < 0) //error - return static_cast(result); + // assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if ((segment_stop >= 0) && ((pos + size) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + // Pos now points to start of payload - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + pos += size; // consume payload (that is, the current cluster) + assert((segment_stop < 0) || (pos <= segment_stop)); - const long long size = ReadUInt(m_pReader, pos, len); + // By consuming the payload, we are assuming that the curr + // cluster isn't interesting. That is, we don't bother checking + // whether the payload of the curr cluster is less than what + // happens to be available (obtained via IMkvReader::Length). + // Presumably the caller has already dispensed with the current + // cluster, and really does want the next cluster. + } - if (size < 0) //error - return static_cast(size); + // pos now points to just beyond the last fully-loaded cluster - pos += len; //consume size field + for (;;) { + const long status = DoParseNext(pResult, pos, len); - const long long unknown_size = (1LL << (7 * len)) - 1; + if (status <= 1) + return status; + } +} - if (size == unknown_size) //TODO: should never happen - return E_FILE_FORMAT_INVALID; //TODO: resolve this +long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) { + long long total, avail; - //assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); + long status = m_pReader->Length(&total, &avail); - if ((segment_stop >= 0) && ((pos + size) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if (status < 0) // error + return status; - //Pos now points to start of payload + assert((total < 0) || (avail <= total)); - pos += size; //consume payload (that is, the current cluster) - assert((segment_stop < 0) || (pos <= segment_stop)); + const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; - //By consuming the payload, we are assuming that the curr - //cluster isn't interesting. That is, we don't bother checking - //whether the payload of the curr cluster is less than what - //happens to be available (obtained via IMkvReader::Length). - //Presumably the caller has already dispensed with the current - //cluster, and really does want the next cluster. - } + // Parse next cluster. This is strictly a parsing activity. + // Creation of a new cluster object happens later, after the + // parsing is done. - //pos now points to just beyond the last fully-loaded cluster + long long off_next = 0; + long long cluster_size = -1; - for (;;) - { - const long status = DoParseNext(pResult, pos, len); + for (;;) { + if ((total >= 0) && (pos >= total)) + return 1; // EOF - if (status <= 1) - return status; + if ((segment_stop >= 0) && (pos >= segment_stop)) + return 1; // EOF + + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; } -} + long long result = GetUIntLength(m_pReader, pos, len); -long Segment::DoParseNext( - const Cluster*& pResult, - long long& pos, - long& len) -{ - long long total, avail; + if (result < 0) // error + return static_cast(result); - long status = m_pReader->Length(&total, &avail); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (status < 0) //error - return status; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - assert((total < 0) || (avail <= total)); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; + const long long idpos = pos; // absolute + const long long idoff = pos - m_start; // relative - //Parse next cluster. This is strictly a parsing activity. - //Creation of a new cluster object happens later, after the - //parsing is done. + const long long id = ReadUInt(m_pReader, idpos, len); // absolute - long long off_next = 0; - long long cluster_size = -1; + if (id < 0) // error + return static_cast(id); - for (;;) - { - if ((total >= 0) && (pos >= total)) - return 1; //EOF + if (id == 0) // weird + return -1; // generic error - if ((segment_stop >= 0) && (pos >= segment_stop)) - return 1; //EOF + pos += len; // consume ID - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + // Read Size - long long result = GetUIntLength(m_pReader, pos, len); + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if (result < 0) //error - return static_cast(result); + result = GetUIntLength(m_pReader, pos, len); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result < 0) // error + return static_cast(result); - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - const long long idpos = pos; //absolute - const long long idoff = pos - m_start; //relative + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long id = ReadUInt(m_pReader, idpos, len); //absolute + const long long size = ReadUInt(m_pReader, pos, len); - if (id < 0) //error - return static_cast(id); + if (size < 0) // error + return static_cast(size); - if (id == 0) //weird - return -1; //generic error + pos += len; // consume length of size of element - pos += len; //consume ID + // Pos now points to start of payload - //Read Size + if (size == 0) // weird + continue; - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + const long long unknown_size = (1LL << (7 * len)) - 1; - result = GetUIntLength(m_pReader, pos, len); + if ((segment_stop >= 0) && (size != unknown_size) && + ((pos + size) > segment_stop)) { + return E_FILE_FORMAT_INVALID; + } - if (result < 0) //error - return static_cast(result); + if (id == 0x0C53BB6B) { // Cues ID + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + const long long element_stop = pos + size; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; - - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; - - const long long size = ReadUInt(m_pReader, pos, len); - - if (size < 0) //error - return static_cast(size); - - pos += len; //consume length of size of element - - //Pos now points to start of payload - - if (size == 0) //weird - continue; - - const long long unknown_size = (1LL << (7 * len)) - 1; - - if ((segment_stop >= 0) && - (size != unknown_size) && - ((pos + size) > segment_stop)) - { - return E_FILE_FORMAT_INVALID; - } - - if (id == 0x0C53BB6B) //Cues ID - { - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; - - const long long element_stop = pos + size; - - if ((segment_stop >= 0) && (element_stop > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && (element_stop > segment_stop)) + return E_FILE_FORMAT_INVALID; - const long long element_start = idpos; - const long long element_size = element_stop - element_start; + const long long element_start = idpos; + const long long element_size = element_stop - element_start; - if (m_pCues == NULL) - { - m_pCues = new Cues(this, - pos, - size, - element_start, - element_size); - assert(m_pCues); //TODO - } + if (m_pCues == NULL) { + m_pCues = new Cues(this, pos, size, element_start, element_size); + assert(m_pCues); // TODO + } - pos += size; //consume payload - assert((segment_stop < 0) || (pos <= segment_stop)); + pos += size; // consume payload + assert((segment_stop < 0) || (pos <= segment_stop)); - continue; - } + continue; + } - if (id != 0x0F43B675) //not a Cluster ID - { - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; + if (id != 0x0F43B675) { // not a Cluster ID + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - pos += size; //consume payload - assert((segment_stop < 0) || (pos <= segment_stop)); + pos += size; // consume payload + assert((segment_stop < 0) || (pos <= segment_stop)); - continue; - } + continue; + } -#if 0 //this is commented-out to support incremental cluster parsing +#if 0 // this is commented-out to support incremental cluster parsing len = static_cast(size); if (element_stop > avail) return E_BUFFER_NOT_FULL; #endif - //We have a cluster. + // We have a cluster. - off_next = idoff; + off_next = idoff; - if (size != unknown_size) - cluster_size = size; + if (size != unknown_size) + cluster_size = size; - break; - } + break; + } - assert(off_next > 0); //have cluster + assert(off_next > 0); // have cluster - //We have parsed the next cluster. - //We have not created a cluster object yet. What we need - //to do now is determine whether it has already be preloaded - //(in which case, an object for this cluster has already been - //created), and if not, create a new cluster object. + // We have parsed the next cluster. + // We have not created a cluster object yet. What we need + // to do now is determine whether it has already be preloaded + //(in which case, an object for this cluster has already been + // created), and if not, create a new cluster object. - Cluster** const ii = m_clusters + m_clusterCount; - Cluster** i = ii; + Cluster** const ii = m_clusters + m_clusterCount; + Cluster** i = ii; - Cluster** const jj = ii + m_clusterPreloadCount; - Cluster** j = jj; + Cluster** const jj = ii + m_clusterPreloadCount; + Cluster** j = jj; - while (i < j) - { - //INVARIANT: - //[0, i) < pos_next - //[i, j) ? - //[j, jj) > pos_next + while (i < j) { + // INVARIANT: + //[0, i) < pos_next + //[i, j) ? + //[j, jj) > pos_next - Cluster** const k = i + (j - i) / 2; - assert(k < jj); + Cluster** const k = i + (j - i) / 2; + assert(k < jj); - const Cluster* const pNext = *k; - assert(pNext); - assert(pNext->m_index < 0); + const Cluster* const pNext = *k; + assert(pNext); + assert(pNext->m_index < 0); - pos = pNext->GetPosition(); - assert(pos >= 0); + pos = pNext->GetPosition(); + assert(pos >= 0); - if (pos < off_next) - i = k + 1; - else if (pos > off_next) - j = k; - else - { - pResult = pNext; - return 0; //success - } + if (pos < off_next) + i = k + 1; + else if (pos > off_next) + j = k; + else { + pResult = pNext; + return 0; // success } + } - assert(i == j); + assert(i == j); - long long pos_; - long len_; + long long pos_; + long len_; - status = Cluster::HasBlockEntries(this, off_next, pos_, len_); + status = Cluster::HasBlockEntries(this, off_next, pos_, len_); - if (status < 0) //error or underflow - { - pos = pos_; - len = len_; + if (status < 0) { // error or underflow + pos = pos_; + len = len_; - return status; - } + return status; + } - if (status > 0) //means "found at least one block entry" - { - Cluster* const pNext = Cluster::Create(this, - -1, //preloaded - off_next); - //element_size); - assert(pNext); + if (status > 0) { // means "found at least one block entry" + Cluster* const pNext = Cluster::Create(this, + -1, // preloaded + off_next); + // element_size); + assert(pNext); - const ptrdiff_t idx_next = i - m_clusters; //insertion position + const ptrdiff_t idx_next = i - m_clusters; // insertion position - PreloadCluster(pNext, idx_next); - assert(m_clusters); - assert(idx_next < m_clusterSize); - assert(m_clusters[idx_next] == pNext); + PreloadCluster(pNext, idx_next); + assert(m_clusters); + assert(idx_next < m_clusterSize); + assert(m_clusters[idx_next] == pNext); - pResult = pNext; - return 0; //success - } + pResult = pNext; + return 0; // success + } - //status == 0 means "no block entries found" + // status == 0 means "no block entries found" - if (cluster_size < 0) //unknown size - { - const long long payload_pos = pos; //absolute pos of cluster payload + if (cluster_size < 0) { // unknown size + const long long payload_pos = pos; // absolute pos of cluster payload - for (;;) //determine cluster size - { - if ((total >= 0) && (pos >= total)) - break; + for (;;) { // determine cluster size + if ((total >= 0) && (pos >= total)) + break; - if ((segment_stop >= 0) && (pos >= segment_stop)) - break; //no more clusters + if ((segment_stop >= 0) && (pos >= segment_stop)) + break; // no more clusters - //Read ID + // Read ID - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(m_pReader, pos, len); + long long result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long idpos = pos; - const long long id = ReadUInt(m_pReader, idpos, len); + const long long idpos = pos; + const long long id = ReadUInt(m_pReader, idpos, len); - if (id < 0) //error (or underflow) - return static_cast(id); + if (id < 0) // error (or underflow) + return static_cast(id); - //This is the distinguished set of ID's we use to determine - //that we have exhausted the sub-element's inside the cluster - //whose ID we parsed earlier. + // This is the distinguished set of ID's we use to determine + // that we have exhausted the sub-element's inside the cluster + // whose ID we parsed earlier. - if (id == 0x0F43B675) //Cluster ID - break; + if (id == 0x0F43B675) // Cluster ID + break; - if (id == 0x0C53BB6B) //Cues ID - break; + if (id == 0x0C53BB6B) // Cues ID + break; - pos += len; //consume ID (of sub-element) + pos += len; // consume ID (of sub-element) - //Read Size + // Read Size - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(m_pReader, pos, len); + result = GetUIntLength(m_pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(m_pReader, pos, len); + const long long size = ReadUInt(m_pReader, pos, len); - if (size < 0) //error - return static_cast(size); + if (size < 0) // error + return static_cast(size); - pos += len; //consume size field of element + pos += len; // consume size field of element - //pos now points to start of sub-element's payload + // pos now points to start of sub-element's payload - if (size == 0) //weird - continue; + if (size == 0) // weird + continue; - const long long unknown_size = (1LL << (7 * len)) - 1; + const long long unknown_size = (1LL << (7 * len)) - 1; - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; //not allowed for sub-elements + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; // not allowed for sub-elements - if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird + return E_FILE_FORMAT_INVALID; - pos += size; //consume payload of sub-element - assert((segment_stop < 0) || (pos <= segment_stop)); - } //determine cluster size + pos += size; // consume payload of sub-element + assert((segment_stop < 0) || (pos <= segment_stop)); + } // determine cluster size - cluster_size = pos - payload_pos; - assert(cluster_size >= 0); //TODO: handle cluster_size = 0 + cluster_size = pos - payload_pos; + assert(cluster_size >= 0); // TODO: handle cluster_size = 0 - pos = payload_pos; //reset and re-parse original cluster - } + pos = payload_pos; // reset and re-parse original cluster + } - pos += cluster_size; //consume payload - assert((segment_stop < 0) || (pos <= segment_stop)); + pos += cluster_size; // consume payload + assert((segment_stop < 0) || (pos <= segment_stop)); - return 2; //try to find a cluster that follows next + return 2; // try to find a cluster that follows next } +const Cluster* Segment::FindCluster(long long time_ns) const { + if ((m_clusters == NULL) || (m_clusterCount <= 0)) + return &m_eos; -const Cluster* Segment::FindCluster(long long time_ns) const -{ - if ((m_clusters == NULL) || (m_clusterCount <= 0)) - return &m_eos; - - { - Cluster* const pCluster = m_clusters[0]; - assert(pCluster); - assert(pCluster->m_index == 0); + { + Cluster* const pCluster = m_clusters[0]; + assert(pCluster); + assert(pCluster->m_index == 0); - if (time_ns <= pCluster->GetTime()) - return pCluster; - } + if (time_ns <= pCluster->GetTime()) + return pCluster; + } - //Binary search of cluster array + // Binary search of cluster array - long i = 0; - long j = m_clusterCount; + long i = 0; + long j = m_clusterCount; - while (i < j) - { - //INVARIANT: - //[0, i) <= time_ns - //[i, j) ? - //[j, m_clusterCount) > time_ns + while (i < j) { + // INVARIANT: + //[0, i) <= time_ns + //[i, j) ? + //[j, m_clusterCount) > time_ns - const long k = i + (j - i) / 2; - assert(k < m_clusterCount); + const long k = i + (j - i) / 2; + assert(k < m_clusterCount); - Cluster* const pCluster = m_clusters[k]; - assert(pCluster); - assert(pCluster->m_index == k); + Cluster* const pCluster = m_clusters[k]; + assert(pCluster); + assert(pCluster->m_index == k); - const long long t = pCluster->GetTime(); + const long long t = pCluster->GetTime(); - if (t <= time_ns) - i = k + 1; - else - j = k; + if (t <= time_ns) + i = k + 1; + else + j = k; - assert(i <= j); - } + assert(i <= j); + } - assert(i == j); - assert(i > 0); - assert(i <= m_clusterCount); + assert(i == j); + assert(i > 0); + assert(i <= m_clusterCount); - const long k = i - 1; + const long k = i - 1; - Cluster* const pCluster = m_clusters[k]; - assert(pCluster); - assert(pCluster->m_index == k); - assert(pCluster->GetTime() <= time_ns); + Cluster* const pCluster = m_clusters[k]; + assert(pCluster); + assert(pCluster->m_index == k); + assert(pCluster->GetTime() <= time_ns); - return pCluster; + return pCluster; } - #if 0 const BlockEntry* Segment::Seek( long long time_ns, @@ -4054,8 +3672,7 @@ const BlockEntry* Segment::Seek( Cluster** const j = i + m_clusterCount; - if (pTrack->GetType() == 2) //audio - { + if (pTrack->GetType() == 2) { //audio //TODO: we could decide to use cues for this, as we do for video. //But we only use it for video because looking around for a keyframe //can get expensive. Audio doesn't require anything special so a @@ -4174,7 +3791,6 @@ const BlockEntry* Segment::Seek( } #endif - #if 0 bool Segment::SearchCues( long long time_ns, @@ -4205,776 +3821,593 @@ bool Segment::SearchCues( } #endif +const Tracks* Segment::GetTracks() const { return m_pTracks; } -const Tracks* Segment::GetTracks() const -{ - return m_pTracks; -} +const SegmentInfo* Segment::GetInfo() const { return m_pInfo; } +const Cues* Segment::GetCues() const { return m_pCues; } -const SegmentInfo* Segment::GetInfo() const -{ - return m_pInfo; -} +const Chapters* Segment::GetChapters() const { return m_pChapters; } +const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; } -const Cues* Segment::GetCues() const -{ - return m_pCues; +long long Segment::GetDuration() const { + assert(m_pInfo); + return m_pInfo->GetDuration(); } +Chapters::Chapters(Segment* pSegment, long long payload_start, + long long payload_size, long long element_start, + long long element_size) + : m_pSegment(pSegment), + m_start(payload_start), + m_size(payload_size), + m_element_start(element_start), + m_element_size(element_size), + m_editions(NULL), + m_editions_size(0), + m_editions_count(0) {} -const Chapters* Segment::GetChapters() const -{ - return m_pChapters; +Chapters::~Chapters() { + while (m_editions_count > 0) { + Edition& e = m_editions[--m_editions_count]; + e.Clear(); + } } +long Chapters::Parse() { + IMkvReader* const pReader = m_pSegment->m_pReader; + + long long pos = m_start; // payload start + const long long stop = pos + m_size; // payload stop -const SeekHead* Segment::GetSeekHead() const -{ - return m_pSeekHead; -} + while (pos < stop) { + long long id, size; + long status = ParseElementHeader(pReader, pos, stop, id, size); -long long Segment::GetDuration() const -{ - assert(m_pInfo); - return m_pInfo->GetDuration(); -} - - -Chapters::Chapters( - Segment* pSegment, - long long payload_start, - long long payload_size, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_start(payload_start), - m_size(payload_size), - m_element_start(element_start), - m_element_size(element_size), - m_editions(NULL), - m_editions_size(0), - m_editions_count(0) -{ -} + if (status < 0) // error + return status; + if (size == 0) // weird + continue; -Chapters::~Chapters() -{ - while (m_editions_count > 0) - { - Edition& e = m_editions[--m_editions_count]; - e.Clear(); + if (id == 0x05B9) { // EditionEntry ID + status = ParseEdition(pos, size); + + if (status < 0) // error + return status; } -} + pos += size; + assert(pos <= stop); + } -long Chapters::Parse() -{ - IMkvReader* const pReader = m_pSegment->m_pReader; + assert(pos == stop); + return 0; +} - long long pos = m_start; // payload start - const long long stop = pos + m_size; // payload stop +int Chapters::GetEditionCount() const { return m_editions_count; } - while (pos < stop) - { - long long id, size; +const Chapters::Edition* Chapters::GetEdition(int idx) const { + if (idx < 0) + return NULL; - long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + if (idx >= m_editions_count) + return NULL; - if (status < 0) // error - return status; + return m_editions + idx; +} - if (size == 0) // weird - continue; +bool Chapters::ExpandEditionsArray() { + if (m_editions_size > m_editions_count) + return true; // nothing else to do - if (id == 0x05B9) // EditionEntry ID - { - status = ParseEdition(pos, size); + const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size; - if (status < 0) // error - return status; - } + Edition* const editions = new (std::nothrow) Edition[size]; - pos += size; - assert(pos <= stop); - } + if (editions == NULL) + return false; - assert(pos == stop); - return 0; -} + for (int idx = 0; idx < m_editions_count; ++idx) { + m_editions[idx].ShallowCopy(editions[idx]); + } + delete[] m_editions; + m_editions = editions; -int Chapters::GetEditionCount() const -{ - return m_editions_count; + m_editions_size = size; + return true; } +long Chapters::ParseEdition(long long pos, long long size) { + if (!ExpandEditionsArray()) + return -1; -const Chapters::Edition* Chapters::GetEdition(int idx) const -{ - if (idx < 0) - return NULL; - - if (idx >= m_editions_count) - return NULL; + Edition& e = m_editions[m_editions_count++]; + e.Init(); - return m_editions + idx; + return e.Parse(m_pSegment->m_pReader, pos, size); } +Chapters::Edition::Edition() {} -bool Chapters::ExpandEditionsArray() -{ - if (m_editions_size > m_editions_count) - return true; // nothing else to do +Chapters::Edition::~Edition() {} - const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size; +int Chapters::Edition::GetAtomCount() const { return m_atoms_count; } - Edition* const editions = new (std::nothrow) Edition[size]; +const Chapters::Atom* Chapters::Edition::GetAtom(int index) const { + if (index < 0) + return NULL; - if (editions == NULL) - return false; + if (index >= m_atoms_count) + return NULL; - for (int idx = 0; idx < m_editions_count; ++idx) - { - m_editions[idx].ShallowCopy(editions[idx]); - } + return m_atoms + index; +} - delete[] m_editions; - m_editions = editions; +void Chapters::Edition::Init() { + m_atoms = NULL; + m_atoms_size = 0; + m_atoms_count = 0; +} - m_editions_size = size; - return true; +void Chapters::Edition::ShallowCopy(Edition& rhs) const { + rhs.m_atoms = m_atoms; + rhs.m_atoms_size = m_atoms_size; + rhs.m_atoms_count = m_atoms_count; } +void Chapters::Edition::Clear() { + while (m_atoms_count > 0) { + Atom& a = m_atoms[--m_atoms_count]; + a.Clear(); + } -long Chapters::ParseEdition( - long long pos, - long long size) -{ - if (!ExpandEditionsArray()) - return -1; - - Edition& e = m_editions[m_editions_count++]; - e.Init(); + delete[] m_atoms; + m_atoms = NULL; - return e.Parse(m_pSegment->m_pReader, pos, size); + m_atoms_size = 0; } +long Chapters::Edition::Parse(IMkvReader* pReader, long long pos, + long long size) { + const long long stop = pos + size; -Chapters::Edition::Edition() -{ -} - + while (pos < stop) { + long long id, size; -Chapters::Edition::~Edition() -{ -} + long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error + return status; -int Chapters::Edition::GetAtomCount() const -{ - return m_atoms_count; -} + if (size == 0) // weird + continue; + if (id == 0x36) { // Atom ID + status = ParseAtom(pReader, pos, size); -const Chapters::Atom* Chapters::Edition::GetAtom(int index) const -{ - if (index < 0) - return NULL; + if (status < 0) // error + return status; + } - if (index >= m_atoms_count) - return NULL; + pos += size; + assert(pos <= stop); + } - return m_atoms + index; + assert(pos == stop); + return 0; } +long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos, + long long size) { + if (!ExpandAtomsArray()) + return -1; -void Chapters::Edition::Init() -{ - m_atoms = NULL; - m_atoms_size = 0; - m_atoms_count = 0; -} - + Atom& a = m_atoms[m_atoms_count++]; + a.Init(); -void Chapters::Edition::ShallowCopy(Edition& rhs) const -{ - rhs.m_atoms = m_atoms; - rhs.m_atoms_size = m_atoms_size; - rhs.m_atoms_count = m_atoms_count; + return a.Parse(pReader, pos, size); } +bool Chapters::Edition::ExpandAtomsArray() { + if (m_atoms_size > m_atoms_count) + return true; // nothing else to do -void Chapters::Edition::Clear() -{ - while (m_atoms_count > 0) - { - Atom& a = m_atoms[--m_atoms_count]; - a.Clear(); - } + const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size; - delete[] m_atoms; - m_atoms = NULL; + Atom* const atoms = new (std::nothrow) Atom[size]; - m_atoms_size = 0; -} + if (atoms == NULL) + return false; + for (int idx = 0; idx < m_atoms_count; ++idx) { + m_atoms[idx].ShallowCopy(atoms[idx]); + } -long Chapters::Edition::Parse( - IMkvReader* pReader, - long long pos, - long long size) -{ - const long long stop = pos + size; + delete[] m_atoms; + m_atoms = atoms; - while (pos < stop) - { - long long id, size; + m_atoms_size = size; + return true; +} - long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); +Chapters::Atom::Atom() {} - if (status < 0) // error - return status; +Chapters::Atom::~Atom() {} - if (size == 0) // weird - continue; +unsigned long long Chapters::Atom::GetUID() const { return m_uid; } - if (id == 0x36) // Atom ID - { - status = ParseAtom(pReader, pos, size); +const char* Chapters::Atom::GetStringUID() const { return m_string_uid; } - if (status < 0) // error - return status; - } +long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; } - pos += size; - assert(pos <= stop); - } +long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; } - assert(pos == stop); - return 0; +long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const { + return GetTime(pChapters, m_start_timecode); } - -long Chapters::Edition::ParseAtom( - IMkvReader* pReader, - long long pos, - long long size) -{ - if (!ExpandAtomsArray()) - return -1; - - Atom& a = m_atoms[m_atoms_count++]; - a.Init(); - - return a.Parse(pReader, pos, size); +long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const { + return GetTime(pChapters, m_stop_timecode); } +int Chapters::Atom::GetDisplayCount() const { return m_displays_count; } -bool Chapters::Edition::ExpandAtomsArray() -{ - if (m_atoms_size > m_atoms_count) - return true; // nothing else to do - - const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size; - - Atom* const atoms = new (std::nothrow) Atom[size]; - - if (atoms == NULL) - return false; - - for (int idx = 0; idx < m_atoms_count; ++idx) - { - m_atoms[idx].ShallowCopy(atoms[idx]); - } +const Chapters::Display* Chapters::Atom::GetDisplay(int index) const { + if (index < 0) + return NULL; - delete[] m_atoms; - m_atoms = atoms; + if (index >= m_displays_count) + return NULL; - m_atoms_size = size; - return true; + return m_displays + index; } +void Chapters::Atom::Init() { + m_string_uid = NULL; + m_uid = 0; + m_start_timecode = -1; + m_stop_timecode = -1; -Chapters::Atom::Atom() -{ + m_displays = NULL; + m_displays_size = 0; + m_displays_count = 0; } +void Chapters::Atom::ShallowCopy(Atom& rhs) const { + rhs.m_string_uid = m_string_uid; + rhs.m_uid = m_uid; + rhs.m_start_timecode = m_start_timecode; + rhs.m_stop_timecode = m_stop_timecode; -Chapters::Atom::~Atom() -{ + rhs.m_displays = m_displays; + rhs.m_displays_size = m_displays_size; + rhs.m_displays_count = m_displays_count; } +void Chapters::Atom::Clear() { + delete[] m_string_uid; + m_string_uid = NULL; -long long Chapters::Atom::GetStartTimecode() const -{ - return m_start_timecode; -} + while (m_displays_count > 0) { + Display& d = m_displays[--m_displays_count]; + d.Clear(); + } + delete[] m_displays; + m_displays = NULL; -long long Chapters::Atom::GetStopTimecode() const -{ - return m_stop_timecode; + m_displays_size = 0; } +long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) { + const long long stop = pos + size; -int Chapters::Atom::GetDisplayCount() const -{ - return m_displays_count; -} + while (pos < stop) { + long long id, size; + long status = ParseElementHeader(pReader, pos, stop, id, size); -const Chapters::Display* Chapters::Atom::GetDisplay(int index) const -{ - if (index < 0) - return NULL; + if (status < 0) // error + return status; - if (index >= m_displays_count) - return NULL; + if (size == 0) // weird + continue; - return m_displays + index; -} + if (id == 0x00) { // Display ID + status = ParseDisplay(pReader, pos, size); + if (status < 0) // error + return status; + } else if (id == 0x1654) { // StringUID ID + status = UnserializeString(pReader, pos, size, m_string_uid); -void Chapters::Atom::Init() -{ - m_uid = 0; - m_start_timecode = -1; - m_stop_timecode = -1; + if (status < 0) // error + return status; + } else if (id == 0x33C4) { // UID ID + long long val; + status = UnserializeInt(pReader, pos, size, val); - m_displays = NULL; - m_displays_size = 0; - m_displays_count = 0; -} + if (val < 0) // error + return status; + m_uid = static_cast(val); + } else if (id == 0x11) { // TimeStart ID + const long long val = UnserializeUInt(pReader, pos, size); -void Chapters::Atom::ShallowCopy(Atom& rhs) const -{ - rhs.m_uid = m_uid; - rhs.m_start_timecode = m_start_timecode; - rhs.m_stop_timecode = m_stop_timecode; + if (val < 0) // error + return static_cast(val); - rhs.m_displays = m_displays; - rhs.m_displays_size = m_displays_size; - rhs.m_displays_count = m_displays_count; -} + m_start_timecode = val; + } else if (id == 0x12) { // TimeEnd ID + const long long val = UnserializeUInt(pReader, pos, size); + if (val < 0) // error + return static_cast(val); -void Chapters::Atom::Clear() -{ - while (m_displays_count > 0) - { - Display& d = m_displays[--m_displays_count]; - d.Clear(); + m_stop_timecode = val; } - delete[] m_displays; - m_displays = NULL; + pos += size; + assert(pos <= stop); + } - m_displays_size = 0; + assert(pos == stop); + return 0; } +long long Chapters::Atom::GetTime(const Chapters* pChapters, + long long timecode) { + if (pChapters == NULL) + return -1; -long Chapters::Atom::Parse( - IMkvReader* pReader, - long long pos, - long long size) -{ - const long long stop = pos + size; - - while (pos < stop) - { - long long id, size; - - long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); - - if (status < 0) // error - return status; - - if (size == 0) // weird - continue; - - if (id == 0x00) // Display ID - { - status = ParseDisplay(pReader, pos, size); - - if (status < 0) // error - return status; - } - else if (id == 0x33C4) // UID ID - { - const long long val = UnserializeUInt(pReader, pos, size); + Segment* const pSegment = pChapters->m_pSegment; - if (val < 0) // error - return static_cast(val); + if (pSegment == NULL) // weird + return -1; - m_uid = val; - } - else if (id == 0x11) // TimeStart ID - { - const long long val = UnserializeUInt(pReader, pos, size); + const SegmentInfo* const pInfo = pSegment->GetInfo(); - if (val < 0) // error - return static_cast(val); + if (pInfo == NULL) + return -1; - m_start_timecode = val; - } - else if (id == 0x12) // TimeEnd ID - { - const long long val = UnserializeUInt(pReader, pos, size); + const long long timecode_scale = pInfo->GetTimeCodeScale(); - if (val < 0) // error - return static_cast(val); + if (timecode_scale < 1) // weird + return -1; - m_stop_timecode = val; - } + if (timecode < 0) + return -1; - pos += size; - assert(pos <= stop); - } + const long long result = timecode_scale * timecode; - assert(pos == stop); - return 0; + return result; } +long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos, + long long size) { + if (!ExpandDisplaysArray()) + return -1; -long Chapters::Atom::ParseDisplay( - IMkvReader* pReader, - long long pos, - long long size) -{ - if (!ExpandDisplaysArray()) - return -1; - - Display& d = m_displays[m_displays_count++]; - d.Init(); + Display& d = m_displays[m_displays_count++]; + d.Init(); - return d.Parse(pReader, pos, size); + return d.Parse(pReader, pos, size); } +bool Chapters::Atom::ExpandDisplaysArray() { + if (m_displays_size > m_displays_count) + return true; // nothing else to do -bool Chapters::Atom::ExpandDisplaysArray() -{ - if (m_displays_size > m_displays_count) - return true; // nothing else to do - - const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; - - Display* const displays = new (std::nothrow) Display[size]; - - if (displays == NULL) - return false; - - for (int idx = 0; idx < m_displays_count; ++idx) - { - m_displays[idx].ShallowCopy(displays[idx]); - } - - delete[] m_displays; - m_displays = displays; - - m_displays_size = size; - return true; -} - + const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; -Chapters::Display::Display() -{ -} + Display* const displays = new (std::nothrow) Display[size]; + if (displays == NULL) + return false; -Chapters::Display::~Display() -{ -} + for (int idx = 0; idx < m_displays_count; ++idx) { + m_displays[idx].ShallowCopy(displays[idx]); + } + delete[] m_displays; + m_displays = displays; -const char* Chapters::Display::GetString() const -{ - return m_string; + m_displays_size = size; + return true; } +Chapters::Display::Display() {} -const char* Chapters::Display::GetLanguage() const -{ - return m_language; -} +Chapters::Display::~Display() {} +const char* Chapters::Display::GetString() const { return m_string; } -const char* Chapters::Display::GetCountry() const -{ - return m_country; -} +const char* Chapters::Display::GetLanguage() const { return m_language; } +const char* Chapters::Display::GetCountry() const { return m_country; } -void Chapters::Display::Init() -{ - m_string = NULL; - m_language = NULL; - m_country = NULL; +void Chapters::Display::Init() { + m_string = NULL; + m_language = NULL; + m_country = NULL; } - -void Chapters::Display::ShallowCopy(Display& rhs) const -{ - rhs.m_string = m_string; - rhs.m_language = m_language; - rhs.m_country = m_country; +void Chapters::Display::ShallowCopy(Display& rhs) const { + rhs.m_string = m_string; + rhs.m_language = m_language; + rhs.m_country = m_country; } +void Chapters::Display::Clear() { + delete[] m_string; + m_string = NULL; -void Chapters::Display::Clear() -{ - delete[] m_string; - m_string = NULL; - - delete[] m_language; - m_language = NULL; + delete[] m_language; + m_language = NULL; - delete[] m_country; - m_country = NULL; + delete[] m_country; + m_country = NULL; } +long Chapters::Display::Parse(IMkvReader* pReader, long long pos, + long long size) { + const long long stop = pos + size; -long Chapters::Display::Parse( - IMkvReader* pReader, - long long pos, - long long size) -{ - const long long stop = pos + size; - - while (pos < stop) - { - long long id, size; - - long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + while (pos < stop) { + long long id, size; - if (status < 0) // error - return status; + long status = ParseElementHeader(pReader, pos, stop, id, size); - if (size == 0) // weird - continue; + if (status < 0) // error + return status; - if (id == 0x05) // ChapterString ID - { - status = UnserializeString(pReader, pos, size, m_string); + if (size == 0) // weird + continue; - if (status) - return status; - } - else if (id == 0x037C) // ChapterLanguage ID - { - status = UnserializeString(pReader, pos, size, m_language); + if (id == 0x05) { // ChapterString ID + status = UnserializeString(pReader, pos, size, m_string); - if (status) - return status; - } - else if (id == 0x037E) // ChapterCountry ID - { - status = UnserializeString(pReader, pos, size, m_country); + if (status) + return status; + } else if (id == 0x037C) { // ChapterLanguage ID + status = UnserializeString(pReader, pos, size, m_language); - if (status) - return status; - } + if (status) + return status; + } else if (id == 0x037E) { // ChapterCountry ID + status = UnserializeString(pReader, pos, size, m_country); - pos += size; - assert(pos <= stop); + if (status) + return status; } - assert(pos == stop); - return 0; -} - + pos += size; + assert(pos <= stop); + } -SegmentInfo::SegmentInfo( - Segment* pSegment, - long long start, - long long size_, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_start(start), - m_size(size_), - m_element_start(element_start), - m_element_size(element_size), - m_pMuxingAppAsUTF8(NULL), - m_pWritingAppAsUTF8(NULL), - m_pTitleAsUTF8(NULL) -{ + assert(pos == stop); + return 0; } -SegmentInfo::~SegmentInfo() -{ - delete[] m_pMuxingAppAsUTF8; - m_pMuxingAppAsUTF8 = NULL; +SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_, + long long element_start, long long element_size) + : m_pSegment(pSegment), + m_start(start), + m_size(size_), + m_element_start(element_start), + m_element_size(element_size), + m_pMuxingAppAsUTF8(NULL), + m_pWritingAppAsUTF8(NULL), + m_pTitleAsUTF8(NULL) {} + +SegmentInfo::~SegmentInfo() { + delete[] m_pMuxingAppAsUTF8; + m_pMuxingAppAsUTF8 = NULL; - delete[] m_pWritingAppAsUTF8; - m_pWritingAppAsUTF8 = NULL; + delete[] m_pWritingAppAsUTF8; + m_pWritingAppAsUTF8 = NULL; - delete[] m_pTitleAsUTF8; - m_pTitleAsUTF8 = NULL; + delete[] m_pTitleAsUTF8; + m_pTitleAsUTF8 = NULL; } +long SegmentInfo::Parse() { + assert(m_pMuxingAppAsUTF8 == NULL); + assert(m_pWritingAppAsUTF8 == NULL); + assert(m_pTitleAsUTF8 == NULL); -long SegmentInfo::Parse() -{ - assert(m_pMuxingAppAsUTF8 == NULL); - assert(m_pWritingAppAsUTF8 == NULL); - assert(m_pTitleAsUTF8 == NULL); + IMkvReader* const pReader = m_pSegment->m_pReader; - IMkvReader* const pReader = m_pSegment->m_pReader; + long long pos = m_start; + const long long stop = m_start + m_size; - long long pos = m_start; - const long long stop = m_start + m_size; + m_timecodeScale = 1000000; + m_duration = -1; - m_timecodeScale = 1000000; - m_duration = -1; + while (pos < stop) { + long long id, size; - while (pos < stop) - { - long long id, size; + const long status = ParseElementHeader(pReader, pos, stop, id, size); - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + if (status < 0) // error + return status; - if (status < 0) //error - return status; + if (id == 0x0AD7B1) { // Timecode Scale + m_timecodeScale = UnserializeUInt(pReader, pos, size); - if (id == 0x0AD7B1) //Timecode Scale - { - m_timecodeScale = UnserializeUInt(pReader, pos, size); + if (m_timecodeScale <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x0489) { // Segment duration + const long status = UnserializeFloat(pReader, pos, size, m_duration); - if (m_timecodeScale <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x0489) //Segment duration - { - const long status = UnserializeFloat( - pReader, - pos, - size, - m_duration); + if (status < 0) + return status; - if (status < 0) - return status; + if (m_duration < 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x0D80) { // MuxingApp + const long status = + UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8); - if (m_duration < 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x0D80) //MuxingApp - { - const long status = UnserializeString( - pReader, - pos, - size, - m_pMuxingAppAsUTF8); - - if (status) - return status; - } - else if (id == 0x1741) //WritingApp - { - const long status = UnserializeString( - pReader, - pos, - size, - m_pWritingAppAsUTF8); - - if (status) - return status; - } - else if (id == 0x3BA9) //Title - { - const long status = UnserializeString( - pReader, - pos, - size, - m_pTitleAsUTF8); - - if (status) - return status; - } + if (status) + return status; + } else if (id == 0x1741) { // WritingApp + const long status = + UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8); - pos += size; - assert(pos <= stop); - } + if (status) + return status; + } else if (id == 0x3BA9) { // Title + const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8); - assert(pos == stop); + if (status) + return status; + } - return 0; -} + pos += size; + assert(pos <= stop); + } + assert(pos == stop); -long long SegmentInfo::GetTimeCodeScale() const -{ - return m_timecodeScale; + return 0; } +long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; } -long long SegmentInfo::GetDuration() const -{ - if (m_duration < 0) - return -1; +long long SegmentInfo::GetDuration() const { + if (m_duration < 0) + return -1; - assert(m_timecodeScale >= 1); + assert(m_timecodeScale >= 1); - const double dd = double(m_duration) * double(m_timecodeScale); - const long long d = static_cast(dd); + const double dd = double(m_duration) * double(m_timecodeScale); + const long long d = static_cast(dd); - return d; + return d; } -const char* SegmentInfo::GetMuxingAppAsUTF8() const -{ - return m_pMuxingAppAsUTF8; +const char* SegmentInfo::GetMuxingAppAsUTF8() const { + return m_pMuxingAppAsUTF8; } - -const char* SegmentInfo::GetWritingAppAsUTF8() const -{ - return m_pWritingAppAsUTF8; +const char* SegmentInfo::GetWritingAppAsUTF8() const { + return m_pWritingAppAsUTF8; } -const char* SegmentInfo::GetTitleAsUTF8() const -{ - return m_pTitleAsUTF8; -} +const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; } /////////////////////////////////////////////////////////////// // ContentEncoding element ContentEncoding::ContentCompression::ContentCompression() - : algo(0), - settings(NULL) { -} + : algo(0), settings(NULL), settings_len(0) {} ContentEncoding::ContentCompression::~ContentCompression() { - delete [] settings; + delete[] settings; } ContentEncoding::ContentEncryption::ContentEncryption() @@ -4986,13 +4419,12 @@ ContentEncoding::ContentEncryption::ContentEncryption() sig_key_id(NULL), sig_key_id_len(0), sig_algo(0), - sig_hash_algo(0) { -} + sig_hash_algo(0) {} ContentEncoding::ContentEncryption::~ContentEncryption() { - delete [] key_id; - delete [] signature; - delete [] sig_key_id; + delete[] key_id; + delete[] signature; + delete[] sig_key_id; } ContentEncoding::ContentEncoding() @@ -5002,8 +4434,7 @@ ContentEncoding::ContentEncoding() encryption_entries_end_(NULL), encoding_order_(0), encoding_scope_(1), - encoding_type_(0) { -} + encoding_type_(0) {} ContentEncoding::~ContentEncoding() { ContentCompression** comp_i = compression_entries_; @@ -5014,7 +4445,7 @@ ContentEncoding::~ContentEncoding() { delete comp; } - delete [] compression_entries_; + delete[] compression_entries_; ContentEncryption** enc_i = encryption_entries_; ContentEncryption** const enc_j = encryption_entries_end_; @@ -5024,10 +4455,9 @@ ContentEncoding::~ContentEncoding() { delete enc; } - delete [] encryption_entries_; + delete[] encryption_entries_; } - const ContentEncoding::ContentCompression* ContentEncoding::GetCompressionByIndex(unsigned long idx) const { const ptrdiff_t count = compression_entries_end_ - compression_entries_; @@ -5046,8 +4476,8 @@ unsigned long ContentEncoding::GetCompressionCount() const { return static_cast(count); } -const ContentEncoding::ContentEncryption* -ContentEncoding::GetEncryptionByIndex(unsigned long idx) const { +const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex( + unsigned long idx) const { const ptrdiff_t count = encryption_entries_end_ - encryption_entries_; assert(count >= 0); @@ -5065,9 +4495,7 @@ unsigned long ContentEncoding::GetEncryptionCount() const { } long ContentEncoding::ParseContentEncAESSettingsEntry( - long long start, - long long size, - IMkvReader* pReader, + long long start, long long size, IMkvReader* pReader, ContentEncAESSettings* aes) { assert(pReader); assert(aes); @@ -5077,12 +4505,8 @@ long ContentEncoding::ParseContentEncAESSettingsEntry( while (pos < stop) { long long id, size; - const long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + const long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; if (id == 0x7E8) { @@ -5092,15 +4516,14 @@ long ContentEncoding::ParseContentEncAESSettingsEntry( return E_FILE_FORMAT_INVALID; } - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } return 0; } -long ContentEncoding::ParseContentEncodingEntry(long long start, - long long size, +long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, IMkvReader* pReader) { assert(pReader); @@ -5113,12 +4536,8 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, while (pos < stop) { long long id, size; - const long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + const long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; if (id == 0x1034) // ContentCompression ID @@ -5127,7 +4546,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, if (id == 0x1035) // ContentEncryption ID ++encryption_count; - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } @@ -5136,7 +4555,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, if (compression_count > 0) { compression_entries_ = - new (std::nothrow) ContentCompression*[compression_count]; + new (std::nothrow) ContentCompression* [compression_count]; if (!compression_entries_) return -1; compression_entries_end_ = compression_entries_; @@ -5144,9 +4563,9 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, if (encryption_count > 0) { encryption_entries_ = - new (std::nothrow) ContentEncryption*[encryption_count]; + new (std::nothrow) ContentEncryption* [encryption_count]; if (!encryption_entries_) { - delete [] compression_entries_; + delete[] compression_entries_; return -1; } encryption_entries_end_ = encryption_entries_; @@ -5155,12 +4574,8 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, pos = start; while (pos < stop) { long long id, size; - long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; if (id == 0x1031) { @@ -5176,7 +4591,17 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, encoding_type_ = UnserializeUInt(pReader, pos, size); } else if (id == 0x1034) { // ContentCompression ID - // TODO(fgaligan): Add code to parse ContentCompression elements. + ContentCompression* const compression = + new (std::nothrow) ContentCompression(); + if (!compression) + return -1; + + status = ParseCompressionEntry(pos, size, pReader, compression); + if (status) { + delete compression; + return status; + } + *compression_entries_end_++ = compression; } else if (id == 0x1035) { // ContentEncryption ID ContentEncryption* const encryption = @@ -5192,7 +4617,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, *encryption_entries_end_++ = encryption; } - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } @@ -5200,36 +4625,87 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, return 0; } -long ContentEncoding::ParseEncryptionEntry( - long long start, - long long size, - IMkvReader* pReader, - ContentEncryption* encryption) { +long ContentEncoding::ParseCompressionEntry(long long start, long long size, + IMkvReader* pReader, + ContentCompression* compression) { assert(pReader); - assert(encryption); + assert(compression); long long pos = start; const long long stop = start + size; + bool valid = false; + while (pos < stop) { long long id, size; - const long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + const long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; - if (id == 0x7E1) { - // ContentEncAlgo - encryption->algo = UnserializeUInt(pReader, pos, size); - if (encryption->algo != 5) + if (id == 0x254) { + // ContentCompAlgo + long long algo = UnserializeUInt(pReader, pos, size); + if (algo < 0) return E_FILE_FORMAT_INVALID; - } else if (id == 0x7E2) { - // ContentEncKeyID - delete[] encryption->key_id; - encryption->key_id = NULL; + compression->algo = algo; + valid = true; + } else if (id == 0x255) { + // ContentCompSettings + if (size <= 0) + return E_FILE_FORMAT_INVALID; + + const size_t buflen = static_cast(size); + typedef unsigned char* buf_t; + const buf_t buf = new (std::nothrow) unsigned char[buflen]; + if (buf == NULL) + return -1; + + const int read_status = + pReader->Read(pos, static_cast(buflen), buf); + if (read_status) { + delete[] buf; + return status; + } + + compression->settings = buf; + compression->settings_len = buflen; + } + + pos += size; // consume payload + assert(pos <= stop); + } + + // ContentCompAlgo is mandatory + if (!valid) + return E_FILE_FORMAT_INVALID; + + return 0; +} + +long ContentEncoding::ParseEncryptionEntry(long long start, long long size, + IMkvReader* pReader, + ContentEncryption* encryption) { + assert(pReader); + assert(encryption); + + long long pos = start; + const long long stop = start + size; + + while (pos < stop) { + long long id, size; + const long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error + return status; + + if (id == 0x7E1) { + // ContentEncAlgo + encryption->algo = UnserializeUInt(pReader, pos, size); + if (encryption->algo != 5) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x7E2) { + // ContentEncKeyID + delete[] encryption -> key_id; + encryption->key_id = NULL; encryption->key_id_len = 0; if (size <= 0) @@ -5241,9 +4717,10 @@ long ContentEncoding::ParseEncryptionEntry( if (buf == NULL) return -1; - const int read_status = pReader->Read(pos, buflen, buf); + const int read_status = + pReader->Read(pos, static_cast(buflen), buf); if (read_status) { - delete [] buf; + delete[] buf; return status; } @@ -5251,7 +4728,7 @@ long ContentEncoding::ParseEncryptionEntry( encryption->key_id_len = buflen; } else if (id == 0x7E3) { // ContentSignature - delete[] encryption->signature; + delete[] encryption -> signature; encryption->signature = NULL; encryption->signature_len = 0; @@ -5264,9 +4741,10 @@ long ContentEncoding::ParseEncryptionEntry( if (buf == NULL) return -1; - const int read_status = pReader->Read(pos, buflen, buf); + const int read_status = + pReader->Read(pos, static_cast(buflen), buf); if (read_status) { - delete [] buf; + delete[] buf; return status; } @@ -5274,7 +4752,7 @@ long ContentEncoding::ParseEncryptionEntry( encryption->signature_len = buflen; } else if (id == 0x7E4) { // ContentSigKeyID - delete[] encryption->sig_key_id; + delete[] encryption -> sig_key_id; encryption->sig_key_id = NULL; encryption->sig_key_id_len = 0; @@ -5287,9 +4765,10 @@ long ContentEncoding::ParseEncryptionEntry( if (buf == NULL) return -1; - const int read_status = pReader->Read(pos, buflen, buf); + const int read_status = + pReader->Read(pos, static_cast(buflen), buf); if (read_status) { - delete [] buf; + delete[] buf; return status; } @@ -5304,364 +4783,322 @@ long ContentEncoding::ParseEncryptionEntry( } else if (id == 0x7E7) { // ContentEncAESSettings const long status = ParseContentEncAESSettingsEntry( - pos, - size, - pReader, - &encryption->aes_settings); + pos, size, pReader, &encryption->aes_settings); if (status) return status; } - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } return 0; } -Track::Track( - Segment* pSegment, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_element_start(element_start), - m_element_size(element_size), - content_encoding_entries_(NULL), - content_encoding_entries_end_(NULL) -{ -} +Track::Track(Segment* pSegment, long long element_start, long long element_size) + : m_pSegment(pSegment), + m_element_start(element_start), + m_element_size(element_size), + content_encoding_entries_(NULL), + content_encoding_entries_end_(NULL) {} -Track::~Track() -{ - Info& info = const_cast(m_info); - info.Clear(); +Track::~Track() { + Info& info = const_cast(m_info); + info.Clear(); - ContentEncoding** i = content_encoding_entries_; - ContentEncoding** const j = content_encoding_entries_end_; + ContentEncoding** i = content_encoding_entries_; + ContentEncoding** const j = content_encoding_entries_end_; - while (i != j) { - ContentEncoding* const encoding = *i++; - delete encoding; - } + while (i != j) { + ContentEncoding* const encoding = *i++; + delete encoding; + } - delete [] content_encoding_entries_; + delete[] content_encoding_entries_; } -long Track::Create( - Segment* pSegment, - const Info& info, - long long element_start, - long long element_size, - Track*& pResult) -{ - if (pResult) - return -1; +long Track::Create(Segment* pSegment, const Info& info, long long element_start, + long long element_size, Track*& pResult) { + if (pResult) + return -1; - Track* const pTrack = new (std::nothrow) Track(pSegment, - element_start, - element_size); + Track* const pTrack = + new (std::nothrow) Track(pSegment, element_start, element_size); - if (pTrack == NULL) - return -1; //generic error + if (pTrack == NULL) + return -1; // generic error - const int status = info.Copy(pTrack->m_info); + const int status = info.Copy(pTrack->m_info); - if (status) // error - { - delete pTrack; - return status; - } + if (status) { // error + delete pTrack; + return status; + } - pResult = pTrack; - return 0; //success + pResult = pTrack; + return 0; // success } -Track::Info::Info(): - nameAsUTF8(NULL), - codecId(NULL), - codecNameAsUTF8(NULL), - codecPrivate(NULL), - codecPrivateSize(0) -{ -} +Track::Info::Info() + : uid(0), + defaultDuration(0), + codecDelay(0), + seekPreRoll(0), + nameAsUTF8(NULL), + language(NULL), + codecId(NULL), + codecNameAsUTF8(NULL), + codecPrivate(NULL), + codecPrivateSize(0), + lacing(false) {} -Track::Info::~Info() -{ - Clear(); -} +Track::Info::~Info() { Clear(); } -void Track::Info::Clear() -{ - delete[] nameAsUTF8; - nameAsUTF8 = NULL; +void Track::Info::Clear() { + delete[] nameAsUTF8; + nameAsUTF8 = NULL; + + delete[] language; + language = NULL; - delete[] codecId; - codecId = NULL; + delete[] codecId; + codecId = NULL; - delete[] codecPrivate; - codecPrivate = NULL; - codecPrivateSize = 0; + delete[] codecPrivate; + codecPrivate = NULL; + codecPrivateSize = 0; - delete[] codecNameAsUTF8; - codecNameAsUTF8 = NULL; + delete[] codecNameAsUTF8; + codecNameAsUTF8 = NULL; } -int Track::Info::CopyStr(char* Info::*str, Info& dst_) const -{ - if (str == static_cast(NULL)) - return -1; +int Track::Info::CopyStr(char* Info::*str, Info& dst_) const { + if (str == static_cast(NULL)) + return -1; - char*& dst = dst_.*str; + char*& dst = dst_.*str; - if (dst) //should be NULL already - return -1; + if (dst) // should be NULL already + return -1; - const char* const src = this->*str; + const char* const src = this->*str; - if (src == NULL) - return 0; + if (src == NULL) + return 0; - const size_t len = strlen(src); + const size_t len = strlen(src); - dst = new (std::nothrow) char[len+1]; + dst = new (std::nothrow) char[len + 1]; - if (dst == NULL) - return -1; + if (dst == NULL) + return -1; - strcpy(dst, src); + strcpy(dst, src); - return 0; + return 0; } +int Track::Info::Copy(Info& dst) const { + if (&dst == this) + return 0; -int Track::Info::Copy(Info& dst) const -{ - if (&dst == this) - return 0; - - dst.type = type; - dst.number = number; - dst.uid = uid; - dst.lacing = lacing; - dst.settings = settings; - - //We now copy the string member variables from src to dst. - //This involves memory allocation so in principle the operation - //can fail (indeed, that's why we have Info::Copy), so we must - //report this to the caller. An error return from this function - //therefore implies that the copy was only partially successful. + dst.type = type; + dst.number = number; + dst.defaultDuration = defaultDuration; + dst.codecDelay = codecDelay; + dst.seekPreRoll = seekPreRoll; + dst.uid = uid; + dst.lacing = lacing; + dst.settings = settings; + + // We now copy the string member variables from src to dst. + // This involves memory allocation so in principle the operation + // can fail (indeed, that's why we have Info::Copy), so we must + // report this to the caller. An error return from this function + // therefore implies that the copy was only partially successful. + + if (int status = CopyStr(&Info::nameAsUTF8, dst)) + return status; - if (int status = CopyStr(&Info::nameAsUTF8, dst)) - return status; + if (int status = CopyStr(&Info::language, dst)) + return status; - if (int status = CopyStr(&Info::codecId, dst)) - return status; + if (int status = CopyStr(&Info::codecId, dst)) + return status; - if (int status = CopyStr(&Info::codecNameAsUTF8, dst)) - return status; + if (int status = CopyStr(&Info::codecNameAsUTF8, dst)) + return status; - if (codecPrivateSize > 0) - { - if (codecPrivate == NULL) - return -1; + if (codecPrivateSize > 0) { + if (codecPrivate == NULL) + return -1; - if (dst.codecPrivate) - return -1; + if (dst.codecPrivate) + return -1; - if (dst.codecPrivateSize != 0) - return -1; + if (dst.codecPrivateSize != 0) + return -1; - dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize]; + dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize]; - if (dst.codecPrivate == NULL) - return -1; + if (dst.codecPrivate == NULL) + return -1; - memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize); - dst.codecPrivateSize = codecPrivateSize; - } + memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize); + dst.codecPrivateSize = codecPrivateSize; + } - return 0; + return 0; } -const BlockEntry* Track::GetEOS() const -{ - return &m_eos; -} +const BlockEntry* Track::GetEOS() const { return &m_eos; } -long Track::GetType() const -{ - return m_info.type; -} +long Track::GetType() const { return m_info.type; } -long Track::GetNumber() const -{ - return m_info.number; -} +long Track::GetNumber() const { return m_info.number; } -unsigned long long Track::GetUid() const -{ - return m_info.uid; -} +unsigned long long Track::GetUid() const { return m_info.uid; } -const char* Track::GetNameAsUTF8() const -{ - return m_info.nameAsUTF8; -} +const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; } -const char* Track::GetCodecNameAsUTF8() const -{ - return m_info.codecNameAsUTF8; -} +const char* Track::GetLanguage() const { return m_info.language; } +const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; } -const char* Track::GetCodecId() const -{ - return m_info.codecId; -} +const char* Track::GetCodecId() const { return m_info.codecId; } -const unsigned char* Track::GetCodecPrivate(size_t& size) const -{ - size = m_info.codecPrivateSize; - return m_info.codecPrivate; +const unsigned char* Track::GetCodecPrivate(size_t& size) const { + size = m_info.codecPrivateSize; + return m_info.codecPrivate; } +bool Track::GetLacing() const { return m_info.lacing; } -bool Track::GetLacing() const -{ - return m_info.lacing; +unsigned long long Track::GetDefaultDuration() const { + return m_info.defaultDuration; } +unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; } -long Track::GetFirst(const BlockEntry*& pBlockEntry) const -{ - const Cluster* pCluster = m_pSegment->GetFirst(); +unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; } - for (int i = 0; ; ) - { - if (pCluster == NULL) - { - pBlockEntry = GetEOS(); - return 1; - } +long Track::GetFirst(const BlockEntry*& pBlockEntry) const { + const Cluster* pCluster = m_pSegment->GetFirst(); - if (pCluster->EOS()) - { + for (int i = 0;;) { + if (pCluster == NULL) { + pBlockEntry = GetEOS(); + return 1; + } + + if (pCluster->EOS()) { #if 0 - if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded - { + if (m_pSegment->Unparsed() <= 0) { //all clusters have been loaded pBlockEntry = GetEOS(); return 1; } #else - if (m_pSegment->DoneParsing()) - { - pBlockEntry = GetEOS(); - return 1; - } + if (m_pSegment->DoneParsing()) { + pBlockEntry = GetEOS(); + return 1; + } #endif - pBlockEntry = 0; - return E_BUFFER_NOT_FULL; - } + pBlockEntry = 0; + return E_BUFFER_NOT_FULL; + } - long status = pCluster->GetFirst(pBlockEntry); + long status = pCluster->GetFirst(pBlockEntry); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - if (pBlockEntry == 0) //empty cluster - { - pCluster = m_pSegment->GetNext(pCluster); - continue; - } + if (pBlockEntry == 0) { // empty cluster + pCluster = m_pSegment->GetNext(pCluster); + continue; + } - for (;;) - { - const Block* const pBlock = pBlockEntry->GetBlock(); - assert(pBlock); + for (;;) { + const Block* const pBlock = pBlockEntry->GetBlock(); + assert(pBlock); - const long long tn = pBlock->GetTrackNumber(); + const long long tn = pBlock->GetTrackNumber(); - if ((tn == m_info.number) && VetEntry(pBlockEntry)) - return 0; + if ((tn == m_info.number) && VetEntry(pBlockEntry)) + return 0; - const BlockEntry* pNextEntry; + const BlockEntry* pNextEntry; - status = pCluster->GetNext(pBlockEntry, pNextEntry); + status = pCluster->GetNext(pBlockEntry, pNextEntry); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - if (pNextEntry == 0) - break; + if (pNextEntry == 0) + break; - pBlockEntry = pNextEntry; - } + pBlockEntry = pNextEntry; + } - ++i; + ++i; - if (i >= 100) - break; + if (i >= 100) + break; - pCluster = m_pSegment->GetNext(pCluster); - } + pCluster = m_pSegment->GetNext(pCluster); + } - //NOTE: if we get here, it means that we didn't find a block with - //a matching track number. We interpret that as an error (which - //might be too conservative). + // NOTE: if we get here, it means that we didn't find a block with + // a matching track number. We interpret that as an error (which + // might be too conservative). - pBlockEntry = GetEOS(); //so we can return a non-NULL value - return 1; + pBlockEntry = GetEOS(); // so we can return a non-NULL value + return 1; } +long Track::GetNext(const BlockEntry* pCurrEntry, + const BlockEntry*& pNextEntry) const { + assert(pCurrEntry); + assert(!pCurrEntry->EOS()); //? -long Track::GetNext( - const BlockEntry* pCurrEntry, - const BlockEntry*& pNextEntry) const -{ - assert(pCurrEntry); - assert(!pCurrEntry->EOS()); //? - - const Block* const pCurrBlock = pCurrEntry->GetBlock(); - assert(pCurrBlock->GetTrackNumber() == m_info.number); + const Block* const pCurrBlock = pCurrEntry->GetBlock(); + assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number); + if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number) + return -1; - const Cluster* pCluster = pCurrEntry->GetCluster(); - assert(pCluster); - assert(!pCluster->EOS()); + const Cluster* pCluster = pCurrEntry->GetCluster(); + assert(pCluster); + assert(!pCluster->EOS()); - long status = pCluster->GetNext(pCurrEntry, pNextEntry); + long status = pCluster->GetNext(pCurrEntry, pNextEntry); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - for (int i = 0; ; ) - { - while (pNextEntry) - { - const Block* const pNextBlock = pNextEntry->GetBlock(); - assert(pNextBlock); + for (int i = 0;;) { + while (pNextEntry) { + const Block* const pNextBlock = pNextEntry->GetBlock(); + assert(pNextBlock); - if (pNextBlock->GetTrackNumber() == m_info.number) - return 0; + if (pNextBlock->GetTrackNumber() == m_info.number) + return 0; - pCurrEntry = pNextEntry; + pCurrEntry = pNextEntry; - status = pCluster->GetNext(pCurrEntry, pNextEntry); + status = pCluster->GetNext(pCurrEntry, pNextEntry); - if (status < 0) //error - return status; - } + if (status < 0) // error + return status; + } - pCluster = m_pSegment->GetNext(pCluster); + pCluster = m_pSegment->GetNext(pCluster); - if (pCluster == NULL) - { - pNextEntry = GetEOS(); - return 1; - } + if (pCluster == NULL) { + pNextEntry = GetEOS(); + return 1; + } - if (pCluster->EOS()) - { + if (pCluster->EOS()) { #if 0 if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded { @@ -5669,78 +5106,148 @@ long Track::GetNext( return 1; } #else - if (m_pSegment->DoneParsing()) - { - pNextEntry = GetEOS(); - return 1; - } + if (m_pSegment->DoneParsing()) { + pNextEntry = GetEOS(); + return 1; + } #endif - //TODO: there is a potential O(n^2) problem here: we tell the - //caller to (pre)load another cluster, which he does, but then he - //calls GetNext again, which repeats the same search. This is - //a pathological case, since the only way it can happen is if - //there exists a long sequence of clusters none of which contain a - // block from this track. One way around this problem is for the - //caller to be smarter when he loads another cluster: don't call - //us back until you have a cluster that contains a block from this - //track. (Of course, that's not cheap either, since our caller - //would have to scan the each cluster as it's loaded, so that - //would just push back the problem.) - - pNextEntry = NULL; - return E_BUFFER_NOT_FULL; - } + // TODO: there is a potential O(n^2) problem here: we tell the + // caller to (pre)load another cluster, which he does, but then he + // calls GetNext again, which repeats the same search. This is + // a pathological case, since the only way it can happen is if + // there exists a long sequence of clusters none of which contain a + // block from this track. One way around this problem is for the + // caller to be smarter when he loads another cluster: don't call + // us back until you have a cluster that contains a block from this + // track. (Of course, that's not cheap either, since our caller + // would have to scan the each cluster as it's loaded, so that + // would just push back the problem.) - status = pCluster->GetFirst(pNextEntry); + pNextEntry = NULL; + return E_BUFFER_NOT_FULL; + } - if (status < 0) //error - return status; + status = pCluster->GetFirst(pNextEntry); - if (pNextEntry == NULL) //empty cluster - continue; + if (status < 0) // error + return status; - ++i; + if (pNextEntry == NULL) // empty cluster + continue; - if (i >= 100) - break; - } + ++i; + + if (i >= 100) + break; + } - //NOTE: if we get here, it means that we didn't find a block with - //a matching track number after lots of searching, so we give - //up trying. + // NOTE: if we get here, it means that we didn't find a block with + // a matching track number after lots of searching, so we give + // up trying. - pNextEntry = GetEOS(); //so we can return a non-NULL value - return 1; + pNextEntry = GetEOS(); // so we can return a non-NULL value + return 1; } -bool Track::VetEntry(const BlockEntry* pBlockEntry) const -{ - assert(pBlockEntry); - const Block* const pBlock = pBlockEntry->GetBlock(); - assert(pBlock); - assert(pBlock->GetTrackNumber() == m_info.number); +bool Track::VetEntry(const BlockEntry* pBlockEntry) const { + assert(pBlockEntry); + const Block* const pBlock = pBlockEntry->GetBlock(); + assert(pBlock); + assert(pBlock->GetTrackNumber() == m_info.number); + if (!pBlock || pBlock->GetTrackNumber() != m_info.number) + return false; - // This function is used during a seek to determine whether the - // frame is a valid seek target. This default function simply - // returns true, which means all frames are valid seek targets. - // It gets overridden by the VideoTrack class, because only video - // keyframes can be used as seek target. + // This function is used during a seek to determine whether the + // frame is a valid seek target. This default function simply + // returns true, which means all frames are valid seek targets. + // It gets overridden by the VideoTrack class, because only video + // keyframes can be used as seek target. - return true; + return true; } -long Track::Seek( - long long /* time_ns */ , - const BlockEntry*& pResult) const -{ - // TODO(matthewjheaney): need to implement this? - pResult = NULL; - return -1; // generic error +long Track::Seek(long long time_ns, const BlockEntry*& pResult) const { + const long status = GetFirst(pResult); + + if (status < 0) // buffer underflow, etc + return status; + + assert(pResult); + + if (pResult->EOS()) + return 0; + + const Cluster* pCluster = pResult->GetCluster(); + assert(pCluster); + assert(pCluster->GetIndex() >= 0); + + if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) + return 0; + + Cluster** const clusters = m_pSegment->m_clusters; + assert(clusters); + + const long count = m_pSegment->GetCount(); // loaded only, not preloaded + assert(count > 0); + + Cluster** const i = clusters + pCluster->GetIndex(); + assert(i); + assert(*i == pCluster); + assert(pCluster->GetTime() <= time_ns); + + Cluster** const j = clusters + count; + + Cluster** lo = i; + Cluster** hi = j; + + while (lo < hi) { + // INVARIANT: + //[i, lo) <= time_ns + //[lo, hi) ? + //[hi, j) > time_ns + + Cluster** const mid = lo + (hi - lo) / 2; + assert(mid < hi); + + pCluster = *mid; + assert(pCluster); + assert(pCluster->GetIndex() >= 0); + assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); + + const long long t = pCluster->GetTime(); + + if (t <= time_ns) + lo = mid + 1; + else + hi = mid; + + assert(lo <= hi); + } + + assert(lo == hi); + assert(lo > i); + assert(lo <= j); + + while (lo > i) { + pCluster = *--lo; + assert(pCluster); + assert(pCluster->GetTime() <= time_ns); + + pResult = pCluster->GetEntry(this); + + if ((pResult != 0) && !pResult->EOS()) + return 0; + + // landed on empty cluster (no entries) + } + + pResult = GetEOS(); // weird + return 0; } -const ContentEncoding* -Track::GetContentEncodingByIndex(unsigned long idx) const { +const ContentEncoding* Track::GetContentEncodingByIndex( + unsigned long idx) const { const ptrdiff_t count = content_encoding_entries_end_ - content_encoding_entries_; assert(count >= 0); @@ -5770,27 +5277,22 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { int count = 0; while (pos < stop) { long long id, size; - const long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + const long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; - - //pos now designates start of element + // pos now designates start of element if (id == 0x2240) // ContentEncoding ID ++count; - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } if (count <= 0) return -1; - content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; + content_encoding_entries_ = new (std::nothrow) ContentEncoding* [count]; if (!content_encoding_entries_) return -1; @@ -5799,24 +5301,18 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { pos = start; while (pos < stop) { long long id, size; - long status = ParseElementHeader(pReader, - pos, - stop, - id, - size); - if (status < 0) //error + long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error return status; - //pos now designates start of element - if (id == 0x2240) { // ContentEncoding ID + // pos now designates start of element + if (id == 0x2240) { // ContentEncoding ID ContentEncoding* const content_encoding = new (std::nothrow) ContentEncoding(); if (!content_encoding) return -1; - status = content_encoding->ParseContentEncodingEntry(pos, - size, - pReader); + status = content_encoding->ParseContentEncodingEntry(pos, size, pReader); if (status) { delete content_encoding; return status; @@ -5825,7 +5321,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { *content_encoding_entries_end_++ = content_encoding; } - pos += size; //consume payload + pos += size; // consume payload assert(pos <= stop); } @@ -5834,219 +5330,175 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { return 0; } -Track::EOSBlock::EOSBlock() : - BlockEntry(NULL, LONG_MIN) -{ -} +Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {} -BlockEntry::Kind Track::EOSBlock::GetKind() const -{ - return kBlockEOS; -} +BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; } +const Block* Track::EOSBlock::GetBlock() const { return NULL; } -const Block* Track::EOSBlock::GetBlock() const -{ - return NULL; -} +VideoTrack::VideoTrack(Segment* pSegment, long long element_start, + long long element_size) + : Track(pSegment, element_start, element_size) {} +long VideoTrack::Parse(Segment* pSegment, const Info& info, + long long element_start, long long element_size, + VideoTrack*& pResult) { + if (pResult) + return -1; -VideoTrack::VideoTrack( - Segment* pSegment, - long long element_start, - long long element_size) : - Track(pSegment, element_start, element_size) -{ -} + if (info.type != Track::kVideo) + return -1; + long long width = 0; + long long height = 0; + double rate = 0.0; -long VideoTrack::Parse( - Segment* pSegment, - const Info& info, - long long element_start, - long long element_size, - VideoTrack*& pResult) -{ - if (pResult) - return -1; + IMkvReader* const pReader = pSegment->m_pReader; - if (info.type != Track::kVideo) - return -1; + const Settings& s = info.settings; + assert(s.start >= 0); + assert(s.size >= 0); - long long width = 0; - long long height = 0; - double rate = 0.0; + long long pos = s.start; + assert(pos >= 0); - IMkvReader* const pReader = pSegment->m_pReader; + const long long stop = pos + s.size; - const Settings& s = info.settings; - assert(s.start >= 0); - assert(s.size >= 0); + while (pos < stop) { + long long id, size; - long long pos = s.start; - assert(pos >= 0); + const long status = ParseElementHeader(pReader, pos, stop, id, size); - const long long stop = pos + s.size; + if (status < 0) // error + return status; - while (pos < stop) - { - long long id, size; + if (id == 0x30) { // pixel width + width = UnserializeUInt(pReader, pos, size); - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + if (width <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x3A) { // pixel height + height = UnserializeUInt(pReader, pos, size); - if (status < 0) //error - return status; + if (height <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x0383E3) { // frame rate + const long status = UnserializeFloat(pReader, pos, size, rate); - if (id == 0x30) //pixel width - { - width = UnserializeUInt(pReader, pos, size); + if (status < 0) + return status; - if (width <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x3A) //pixel height - { - height = UnserializeUInt(pReader, pos, size); + if (rate <= 0) + return E_FILE_FORMAT_INVALID; + } - if (height <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x0383E3) //frame rate - { - const long status = UnserializeFloat( - pReader, - pos, - size, - rate); + pos += size; // consume payload + assert(pos <= stop); + } - if (status < 0) - return status; + assert(pos == stop); - if (rate <= 0) - return E_FILE_FORMAT_INVALID; - } + VideoTrack* const pTrack = + new (std::nothrow) VideoTrack(pSegment, element_start, element_size); - pos += size; //consume payload - assert(pos <= stop); - } - - assert(pos == stop); - - VideoTrack* const pTrack = new (std::nothrow) VideoTrack(pSegment, - element_start, - element_size); + if (pTrack == NULL) + return -1; // generic error - if (pTrack == NULL) - return -1; //generic error + const int status = info.Copy(pTrack->m_info); - const int status = info.Copy(pTrack->m_info); + if (status) { // error + delete pTrack; + return status; + } - if (status) // error - { - delete pTrack; - return status; - } + pTrack->m_width = width; + pTrack->m_height = height; + pTrack->m_rate = rate; - pTrack->m_width = width; - pTrack->m_height = height; - pTrack->m_rate = rate; + pResult = pTrack; + return 0; // success +} - pResult = pTrack; - return 0; //success +bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const { + return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey(); } +long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const { + const long status = GetFirst(pResult); -bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const -{ - return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey(); -} + if (status < 0) // buffer underflow, etc + return status; -long VideoTrack::Seek( - long long time_ns, - const BlockEntry*& pResult) const -{ - const long status = GetFirst(pResult); + assert(pResult); - if (status < 0) //buffer underflow, etc - return status; + if (pResult->EOS()) + return 0; - assert(pResult); + const Cluster* pCluster = pResult->GetCluster(); + assert(pCluster); + assert(pCluster->GetIndex() >= 0); - if (pResult->EOS()) - return 0; + if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) + return 0; - const Cluster* pCluster = pResult->GetCluster(); - assert(pCluster); - assert(pCluster->GetIndex() >= 0); + Cluster** const clusters = m_pSegment->m_clusters; + assert(clusters); - if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) - return 0; + const long count = m_pSegment->GetCount(); // loaded only, not pre-loaded + assert(count > 0); - Cluster** const clusters = m_pSegment->m_clusters; - assert(clusters); + Cluster** const i = clusters + pCluster->GetIndex(); + assert(i); + assert(*i == pCluster); + assert(pCluster->GetTime() <= time_ns); - const long count = m_pSegment->GetCount(); //loaded only, not pre-loaded - assert(count > 0); + Cluster** const j = clusters + count; - Cluster** const i = clusters + pCluster->GetIndex(); - assert(i); - assert(*i == pCluster); - assert(pCluster->GetTime() <= time_ns); + Cluster** lo = i; + Cluster** hi = j; - Cluster** const j = clusters + count; + while (lo < hi) { + // INVARIANT: + //[i, lo) <= time_ns + //[lo, hi) ? + //[hi, j) > time_ns - Cluster** lo = i; - Cluster** hi = j; + Cluster** const mid = lo + (hi - lo) / 2; + assert(mid < hi); - while (lo < hi) - { - //INVARIANT: - //[i, lo) <= time_ns - //[lo, hi) ? - //[hi, j) > time_ns + pCluster = *mid; + assert(pCluster); + assert(pCluster->GetIndex() >= 0); + assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); - Cluster** const mid = lo + (hi - lo) / 2; - assert(mid < hi); + const long long t = pCluster->GetTime(); - pCluster = *mid; - assert(pCluster); - assert(pCluster->GetIndex() >= 0); - assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); + if (t <= time_ns) + lo = mid + 1; + else + hi = mid; - const long long t = pCluster->GetTime(); + assert(lo <= hi); + } - if (t <= time_ns) - lo = mid + 1; - else - hi = mid; + assert(lo == hi); + assert(lo > i); + assert(lo <= j); - assert(lo <= hi); - } + pCluster = *--lo; + assert(pCluster); + assert(pCluster->GetTime() <= time_ns); - assert(lo == hi); - assert(lo > i); - assert(lo <= j); + pResult = pCluster->GetEntry(this, time_ns); + + if ((pResult != 0) && !pResult->EOS()) // found a keyframe + return 0; + while (lo != i) { pCluster = *--lo; assert(pCluster); assert(pCluster->GetTime() <= time_ns); - pResult = pCluster->GetEntry(this, time_ns); - - if ((pResult != 0) && !pResult->EOS()) //found a keyframe - return 0; - - while (lo != i) - { - pCluster = *--lo; - assert(pCluster); - assert(pCluster->GetTime() <= time_ns); - #if 0 //TODO: //We need to handle the case when a cluster @@ -6055,712 +5507,501 @@ long VideoTrack::Seek( //good enough. pResult = pCluster->GetMaxKey(this); #else - pResult = pCluster->GetEntry(this, time_ns); + pResult = pCluster->GetEntry(this, time_ns); #endif - if ((pResult != 0) && !pResult->EOS()) - return 0; - } - - //weird: we're on the first cluster, but no keyframe found - //should never happen but we must return something anyway - - pResult = GetEOS(); - return 0; -} - - -long long VideoTrack::GetWidth() const -{ - return m_width; -} - - -long long VideoTrack::GetHeight() const -{ - return m_height; -} - - -double VideoTrack::GetFrameRate() const -{ - return m_rate; -} + if ((pResult != 0) && !pResult->EOS()) + return 0; + } + // weird: we're on the first cluster, but no keyframe found + // should never happen but we must return something anyway -AudioTrack::AudioTrack( - Segment* pSegment, - long long element_start, - long long element_size) : - Track(pSegment, element_start, element_size) -{ + pResult = GetEOS(); + return 0; } +long long VideoTrack::GetWidth() const { return m_width; } -long AudioTrack::Parse( - Segment* pSegment, - const Info& info, - long long element_start, - long long element_size, - AudioTrack*& pResult) -{ - if (pResult) - return -1; - - if (info.type != Track::kAudio) - return -1; - - IMkvReader* const pReader = pSegment->m_pReader; - - const Settings& s = info.settings; - assert(s.start >= 0); - assert(s.size >= 0); - - long long pos = s.start; - assert(pos >= 0); - - const long long stop = pos + s.size; - - double rate = 8000.0; // MKV default - long long channels = 1; - long long bit_depth = 0; - - while (pos < stop) - { - long long id, size; - - long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); - - if (status < 0) //error - return status; - - if (id == 0x35) //Sample Rate - { - status = UnserializeFloat(pReader, pos, size, rate); - - if (status < 0) - return status; +long long VideoTrack::GetHeight() const { return m_height; } - if (rate <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x1F) //Channel Count - { - channels = UnserializeUInt(pReader, pos, size); +double VideoTrack::GetFrameRate() const { return m_rate; } - if (channels <= 0) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x2264) //Bit Depth - { - bit_depth = UnserializeUInt(pReader, pos, size); +AudioTrack::AudioTrack(Segment* pSegment, long long element_start, + long long element_size) + : Track(pSegment, element_start, element_size) {} - if (bit_depth <= 0) - return E_FILE_FORMAT_INVALID; - } +long AudioTrack::Parse(Segment* pSegment, const Info& info, + long long element_start, long long element_size, + AudioTrack*& pResult) { + if (pResult) + return -1; - pos += size; //consume payload - assert(pos <= stop); - } + if (info.type != Track::kAudio) + return -1; - assert(pos == stop); + IMkvReader* const pReader = pSegment->m_pReader; - AudioTrack* const pTrack = new (std::nothrow) AudioTrack(pSegment, - element_start, - element_size); + const Settings& s = info.settings; + assert(s.start >= 0); + assert(s.size >= 0); - if (pTrack == NULL) - return -1; //generic error + long long pos = s.start; + assert(pos >= 0); - const int status = info.Copy(pTrack->m_info); + const long long stop = pos + s.size; - if (status) - { - delete pTrack; - return status; - } + double rate = 8000.0; // MKV default + long long channels = 1; + long long bit_depth = 0; - pTrack->m_rate = rate; - pTrack->m_channels = channels; - pTrack->m_bitDepth = bit_depth; + while (pos < stop) { + long long id, size; - pResult = pTrack; - return 0; //success -} + long status = ParseElementHeader(pReader, pos, stop, id, size); + if (status < 0) // error + return status; -long AudioTrack::Seek( - long long time_ns, - const BlockEntry*& pResult) const -{ - const long status = GetFirst(pResult); + if (id == 0x35) { // Sample Rate + status = UnserializeFloat(pReader, pos, size, rate); - if (status < 0) //buffer underflow, etc + if (status < 0) return status; - assert(pResult); - - if (pResult->EOS()) - return 0; - - const Cluster* pCluster = pResult->GetCluster(); - assert(pCluster); - assert(pCluster->GetIndex() >= 0); - - if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) - return 0; - - Cluster** const clusters = m_pSegment->m_clusters; - assert(clusters); - - const long count = m_pSegment->GetCount(); //loaded only, not preloaded - assert(count > 0); - - Cluster** const i = clusters + pCluster->GetIndex(); - assert(i); - assert(*i == pCluster); - assert(pCluster->GetTime() <= time_ns); - - Cluster** const j = clusters + count; - - Cluster** lo = i; - Cluster** hi = j; - - while (lo < hi) - { - //INVARIANT: - //[i, lo) <= time_ns - //[lo, hi) ? - //[hi, j) > time_ns - - Cluster** const mid = lo + (hi - lo) / 2; - assert(mid < hi); - - pCluster = *mid; - assert(pCluster); - assert(pCluster->GetIndex() >= 0); - assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); - - const long long t = pCluster->GetTime(); + if (rate <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x1F) { // Channel Count + channels = UnserializeUInt(pReader, pos, size); - if (t <= time_ns) - lo = mid + 1; - else - hi = mid; + if (channels <= 0) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x2264) { // Bit Depth + bit_depth = UnserializeUInt(pReader, pos, size); - assert(lo <= hi); + if (bit_depth <= 0) + return E_FILE_FORMAT_INVALID; } - assert(lo == hi); - assert(lo > i); - assert(lo <= j); - - while (lo > i) - { - pCluster = *--lo; - assert(pCluster); - assert(pCluster->GetTime() <= time_ns); - - pResult = pCluster->GetEntry(this); + pos += size; // consume payload + assert(pos <= stop); + } - if ((pResult != 0) && !pResult->EOS()) - return 0; + assert(pos == stop); - //landed on empty cluster (no entries) - } + AudioTrack* const pTrack = + new (std::nothrow) AudioTrack(pSegment, element_start, element_size); - pResult = GetEOS(); //weird - return 0; -} + if (pTrack == NULL) + return -1; // generic error + const int status = info.Copy(pTrack->m_info); -double AudioTrack::GetSamplingRate() const -{ - return m_rate; -} + if (status) { + delete pTrack; + return status; + } + pTrack->m_rate = rate; + pTrack->m_channels = channels; + pTrack->m_bitDepth = bit_depth; -long long AudioTrack::GetChannels() const -{ - return m_channels; + pResult = pTrack; + return 0; // success } -long long AudioTrack::GetBitDepth() const -{ - return m_bitDepth; -} +double AudioTrack::GetSamplingRate() const { return m_rate; } -Tracks::Tracks( - Segment* pSegment, - long long start, - long long size_, - long long element_start, - long long element_size) : - m_pSegment(pSegment), - m_start(start), - m_size(size_), - m_element_start(element_start), - m_element_size(element_size), - m_trackEntries(NULL), - m_trackEntriesEnd(NULL) -{ -} +long long AudioTrack::GetChannels() const { return m_channels; } +long long AudioTrack::GetBitDepth() const { return m_bitDepth; } -long Tracks::Parse() -{ - assert(m_trackEntries == NULL); - assert(m_trackEntriesEnd == NULL); +Tracks::Tracks(Segment* pSegment, long long start, long long size_, + long long element_start, long long element_size) + : m_pSegment(pSegment), + m_start(start), + m_size(size_), + m_element_start(element_start), + m_element_size(element_size), + m_trackEntries(NULL), + m_trackEntriesEnd(NULL) {} - const long long stop = m_start + m_size; - IMkvReader* const pReader = m_pSegment->m_pReader; +long Tracks::Parse() { + assert(m_trackEntries == NULL); + assert(m_trackEntriesEnd == NULL); - int count = 0; - long long pos = m_start; + const long long stop = m_start + m_size; + IMkvReader* const pReader = m_pSegment->m_pReader; - while (pos < stop) - { - long long id, size; + int count = 0; + long long pos = m_start; - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - size); + while (pos < stop) { + long long id, size; - if (status < 0) //error - return status; + const long status = ParseElementHeader(pReader, pos, stop, id, size); - if (size == 0) //weird - continue; + if (status < 0) // error + return status; - if (id == 0x2E) //TrackEntry ID - ++count; + if (size == 0) // weird + continue; - pos += size; //consume payload - assert(pos <= stop); - } + if (id == 0x2E) // TrackEntry ID + ++count; - assert(pos == stop); + pos += size; // consume payload + assert(pos <= stop); + } - if (count <= 0) - return 0; //success + assert(pos == stop); - m_trackEntries = new (std::nothrow) Track*[count]; + if (count <= 0) + return 0; // success - if (m_trackEntries == NULL) - return -1; + m_trackEntries = new (std::nothrow) Track* [count]; - m_trackEntriesEnd = m_trackEntries; + if (m_trackEntries == NULL) + return -1; - pos = m_start; + m_trackEntriesEnd = m_trackEntries; - while (pos < stop) - { - const long long element_start = pos; + pos = m_start; - long long id, payload_size; + while (pos < stop) { + const long long element_start = pos; - const long status = ParseElementHeader( - pReader, - pos, - stop, - id, - payload_size); + long long id, payload_size; - if (status < 0) //error - return status; + const long status = + ParseElementHeader(pReader, pos, stop, id, payload_size); - if (payload_size == 0) //weird - continue; + if (status < 0) // error + return status; - const long long payload_stop = pos + payload_size; - assert(payload_stop <= stop); //checked in ParseElement + if (payload_size == 0) // weird + continue; - const long long element_size = payload_stop - element_start; + const long long payload_stop = pos + payload_size; + assert(payload_stop <= stop); // checked in ParseElement - if (id == 0x2E) //TrackEntry ID - { - Track*& pTrack = *m_trackEntriesEnd; - pTrack = NULL; + const long long element_size = payload_stop - element_start; - const long status = ParseTrackEntry( - pos, - payload_size, - element_start, - element_size, - pTrack); + if (id == 0x2E) { // TrackEntry ID + Track*& pTrack = *m_trackEntriesEnd; + pTrack = NULL; - if (status) - return status; + const long status = ParseTrackEntry(pos, payload_size, element_start, + element_size, pTrack); - if (pTrack) - ++m_trackEntriesEnd; - } + if (status) + return status; - pos = payload_stop; - assert(pos <= stop); + if (pTrack) + ++m_trackEntriesEnd; } - assert(pos == stop); + pos = payload_stop; + assert(pos <= stop); + } - return 0; //success -} + assert(pos == stop); + return 0; // success +} -unsigned long Tracks::GetTracksCount() const -{ - const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; - assert(result >= 0); +unsigned long Tracks::GetTracksCount() const { + const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; + assert(result >= 0); - return static_cast(result); + return static_cast(result); } -long Tracks::ParseTrackEntry( - long long track_start, - long long track_size, - long long element_start, - long long element_size, - Track*& pResult) const -{ - if (pResult) - return -1; - - IMkvReader* const pReader = m_pSegment->m_pReader; +long Tracks::ParseTrackEntry(long long track_start, long long track_size, + long long element_start, long long element_size, + Track*& pResult) const { + if (pResult) + return -1; - long long pos = track_start; - const long long track_stop = track_start + track_size; + IMkvReader* const pReader = m_pSegment->m_pReader; - Track::Info info; + long long pos = track_start; + const long long track_stop = track_start + track_size; - info.type = 0; - info.number = 0; - info.uid = 0; + Track::Info info; - Track::Settings v; - v.start = -1; - v.size = -1; + info.type = 0; + info.number = 0; + info.uid = 0; + info.defaultDuration = 0; - Track::Settings a; - a.start = -1; - a.size = -1; + Track::Settings v; + v.start = -1; + v.size = -1; - Track::Settings e; //content_encodings_settings; - e.start = -1; - e.size = -1; + Track::Settings a; + a.start = -1; + a.size = -1; - long long lacing = 1; //default is true + Track::Settings e; // content_encodings_settings; + e.start = -1; + e.size = -1; - while (pos < track_stop) - { - long long id, size; + long long lacing = 1; // default is true - const long status = ParseElementHeader( - pReader, - pos, - track_stop, - id, - size); + while (pos < track_stop) { + long long id, size; - if (status < 0) //error - return status; + const long status = ParseElementHeader(pReader, pos, track_stop, id, size); - const long long start = pos; + if (status < 0) // error + return status; - if (id == 0x60) // VideoSettings ID - { - if (size <= 0) - return E_FILE_FORMAT_INVALID; + if (size < 0) + return E_FILE_FORMAT_INVALID; + + const long long start = pos; + + 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; - v.start = start; - v.size = size; - } - else if (id == 0x61) // AudioSettings ID - { - if (size <= 0) - return E_FILE_FORMAT_INVALID; + info.uid = 0; - a.start = start; - a.size = size; - } - else if (id == 0x2D80) // ContentEncodings ID - { - if (size <= 0) - return E_FILE_FORMAT_INVALID; + long long pos_ = start; + const long long pos_end = start + size; - e.start = start; - e.size = size; - } - else if (id == 0x33C5) //Track UID - { - if ((size <= 0) || (size > 8)) - return E_FILE_FORMAT_INVALID; + while (pos_ != pos_end) { + unsigned char b; - info.uid = 0; + const int status = pReader->Read(pos_, 1, &b); - long long pos_ = start; - const long long pos_end = start + size; + if (status) + return status; - while (pos_ != pos_end) - { - unsigned char b; + info.uid <<= 8; + info.uid |= b; - const int status = pReader->Read(pos_, 1, &b); + ++pos_; + } + } else if (id == 0x57) { // Track Number + const long long num = UnserializeUInt(pReader, pos, size); - if (status) - return status; + if ((num <= 0) || (num > 127)) + return E_FILE_FORMAT_INVALID; - info.uid <<= 8; - info.uid |= b; + info.number = static_cast(num); + } else if (id == 0x03) { // Track Type + const long long type = UnserializeUInt(pReader, pos, size); - ++pos_; - } - } - else if (id == 0x57) //Track Number - { - const long long num = UnserializeUInt(pReader, pos, size); + if ((type <= 0) || (type > 254)) + return E_FILE_FORMAT_INVALID; - if ((num <= 0) || (num > 127)) - return E_FILE_FORMAT_INVALID; + info.type = static_cast(type); + } else if (id == 0x136E) { // Track Name + const long status = + UnserializeString(pReader, pos, size, info.nameAsUTF8); - info.number = static_cast(num); - } - else if (id == 0x03) //Track Type - { - const long long type = UnserializeUInt(pReader, pos, size); + if (status) + return status; + } else if (id == 0x02B59C) { // Track Language + const long status = UnserializeString(pReader, pos, size, info.language); - if ((type <= 0) || (type > 254)) - return E_FILE_FORMAT_INVALID; + if (status) + return status; + } else if (id == 0x03E383) { // Default Duration + const long long duration = UnserializeUInt(pReader, pos, size); - info.type = static_cast(type); - } - else if (id == 0x136E) //Track Name - { - const long status = UnserializeString( - pReader, - pos, - size, - info.nameAsUTF8); - - if (status) - return status; - } - else if (id == 0x06) //CodecID - { - const long status = UnserializeString( - pReader, - pos, - size, - info.codecId); - - if (status) - return status; - } - else if (id == 0x1C) //lacing - { - lacing = UnserializeUInt(pReader, pos, size); + if (duration < 0) + return E_FILE_FORMAT_INVALID; - if ((lacing < 0) || (lacing > 1)) - return E_FILE_FORMAT_INVALID; - } - else if (id == 0x23A2) //Codec Private - { - delete[] info.codecPrivate; - info.codecPrivate = NULL; - info.codecPrivateSize = 0; + info.defaultDuration = static_cast(duration); + } else if (id == 0x06) { // CodecID + const long status = UnserializeString(pReader, pos, size, info.codecId); - if (size <= 0) - return E_FILE_FORMAT_INVALID; + if (status) + return status; + } else if (id == 0x1C) { // lacing + lacing = UnserializeUInt(pReader, pos, size); - const size_t buflen = static_cast(size); + if ((lacing < 0) || (lacing > 1)) + return E_FILE_FORMAT_INVALID; + } else if (id == 0x23A2) { // Codec Private + delete[] info.codecPrivate; + info.codecPrivate = NULL; + info.codecPrivateSize = 0; - typedef unsigned char* buf_t; + const size_t buflen = static_cast(size); - const buf_t buf = new (std::nothrow) unsigned char[buflen]; + if (buflen) { + typedef unsigned char* buf_t; - if (buf == NULL) - return -1; + const buf_t buf = new (std::nothrow) unsigned char[buflen]; - const int status = pReader->Read(pos, buflen, buf); + if (buf == NULL) + return -1; - if (status) - { - delete[] buf; - return status; - } + const int status = pReader->Read(pos, static_cast(buflen), buf); - info.codecPrivate = buf; - info.codecPrivateSize = buflen; - } - else if (id == 0x058688) //Codec Name - { - const long status = UnserializeString( - pReader, - pos, - size, - info.codecNameAsUTF8); - - if (status) - return status; + if (status) { + delete[] buf; + return status; } - pos += size; //consume payload - assert(pos <= track_stop); + info.codecPrivate = buf; + info.codecPrivateSize = buflen; + } + } else if (id == 0x058688) { // Codec Name + const long status = + UnserializeString(pReader, pos, size, info.codecNameAsUTF8); + + if (status) + return status; + } else if (id == 0x16AA) { // Codec Delay + info.codecDelay = UnserializeUInt(pReader, pos, size); + } else if (id == 0x16BB) { // Seek Pre Roll + info.seekPreRoll = UnserializeUInt(pReader, pos, size); } - assert(pos == track_stop); + pos += size; // consume payload + assert(pos <= track_stop); + } - if (info.number <= 0) //not specified - return E_FILE_FORMAT_INVALID; + assert(pos == track_stop); - if (GetTrackByNumber(info.number)) - return E_FILE_FORMAT_INVALID; + if (info.number <= 0) // not specified + return E_FILE_FORMAT_INVALID; - if (info.type <= 0) //not specified - return E_FILE_FORMAT_INVALID; + if (GetTrackByNumber(info.number)) + return E_FILE_FORMAT_INVALID; - info.lacing = (lacing > 0) ? true : false; + if (info.type <= 0) // not specified + return E_FILE_FORMAT_INVALID; - if (info.type == Track::kVideo) - { - if (v.start < 0) - return E_FILE_FORMAT_INVALID; + info.lacing = (lacing > 0) ? true : false; - if (a.start >= 0) - return E_FILE_FORMAT_INVALID; + if (info.type == Track::kVideo) { + if (v.start < 0) + return E_FILE_FORMAT_INVALID; - info.settings = v; + if (a.start >= 0) + return E_FILE_FORMAT_INVALID; - VideoTrack* pTrack = NULL; + info.settings = v; - const long status = VideoTrack::Parse(m_pSegment, - info, - element_start, - element_size, - pTrack); + VideoTrack* pTrack = NULL; - if (status) - return status; + const long status = VideoTrack::Parse(m_pSegment, info, element_start, + element_size, pTrack); - pResult = pTrack; - assert(pResult); + if (status) + return status; - 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; + pResult = pTrack; + assert(pResult); - if (v.start >= 0) - return E_FILE_FORMAT_INVALID; + 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; - info.settings = a; + if (v.start >= 0) + return E_FILE_FORMAT_INVALID; - AudioTrack* pTrack = NULL; + info.settings = a; - const long status = AudioTrack::Parse(m_pSegment, - info, - element_start, - element_size, - pTrack); + AudioTrack* pTrack = NULL; - if (status) - return status; + const long status = AudioTrack::Parse(m_pSegment, info, element_start, + element_size, pTrack); - pResult = pTrack; - assert(pResult); + if (status) + return status; - if (e.start >= 0) - pResult->ParseContentEncodingsEntry(e.start, e.size); - } - else - { - // neither video nor audio - probably metadata + pResult = pTrack; + assert(pResult); - if (a.start >= 0) - return E_FILE_FORMAT_INVALID; + if (e.start >= 0) + pResult->ParseContentEncodingsEntry(e.start, e.size); + } else { + // neither video nor audio - probably metadata or subtitles - if (v.start >= 0) - return E_FILE_FORMAT_INVALID; + if (a.start >= 0) + return E_FILE_FORMAT_INVALID; - if (e.start >= 0) - return E_FILE_FORMAT_INVALID; + if (v.start >= 0) + return E_FILE_FORMAT_INVALID; - info.settings.start = -1; - info.settings.size = 0; + if (e.start >= 0) + return E_FILE_FORMAT_INVALID; - Track* pTrack = NULL; + info.settings.start = -1; + info.settings.size = 0; - const long status = Track::Create(m_pSegment, - info, - element_start, - element_size, - pTrack); + Track* pTrack = NULL; - if (status) - return status; + const long status = + Track::Create(m_pSegment, info, element_start, element_size, pTrack); - pResult = pTrack; - assert(pResult); - } + if (status) + return status; + + pResult = pTrack; + assert(pResult); + } - return 0; //success + return 0; // success } +Tracks::~Tracks() { + Track** i = m_trackEntries; + Track** const j = m_trackEntriesEnd; -Tracks::~Tracks() -{ - Track** i = m_trackEntries; - Track** const j = m_trackEntriesEnd; - - while (i != j) - { - Track* const pTrack = *i++; - delete pTrack; - } + while (i != j) { + Track* const pTrack = *i++; + delete pTrack; + } - delete[] m_trackEntries; + delete[] m_trackEntries; } -const Track* Tracks::GetTrackByNumber(long tn) const -{ - if (tn < 0) - return NULL; +const Track* Tracks::GetTrackByNumber(long tn) const { + if (tn < 0) + return NULL; - Track** i = m_trackEntries; - Track** const j = m_trackEntriesEnd; + Track** i = m_trackEntries; + Track** const j = m_trackEntriesEnd; - while (i != j) - { - Track* const pTrack = *i++; + while (i != j) { + Track* const pTrack = *i++; - if (pTrack == NULL) - continue; + if (pTrack == NULL) + continue; - if (tn == pTrack->GetNumber()) - return pTrack; - } + if (tn == pTrack->GetNumber()) + return pTrack; + } - return NULL; //not found + return NULL; // not found } +const Track* Tracks::GetTrackByIndex(unsigned long idx) const { + const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; -const Track* Tracks::GetTrackByIndex(unsigned long idx) const -{ - const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; - - if (idx >= static_cast(count)) - return NULL; + if (idx >= static_cast(count)) + return NULL; - return m_trackEntries[idx]; + return m_trackEntries[idx]; } #if 0 @@ -6782,107 +6023,100 @@ long long Cluster::Unparsed() const } #endif +long Cluster::Load(long long& pos, long& len) const { + assert(m_pSegment); + assert(m_pos >= m_element_start); -long Cluster::Load(long long& pos, long& len) const -{ - if (m_pSegment == NULL) - { - return -1; - } - assert(m_pos >= m_element_start); - - if (m_timecode >= 0) //at least partially loaded - return 0; + if (m_timecode >= 0) // at least partially loaded + return 0; - assert(m_pos == m_element_start); - assert(m_element_size < 0); + assert(m_pos == m_element_start); + assert(m_element_size < 0); - IMkvReader* const pReader = m_pSegment->m_pReader; + IMkvReader* const pReader = m_pSegment->m_pReader; - long long total, avail; + long long total, avail; - const int status = pReader->Length(&total, &avail); + const int status = pReader->Length(&total, &avail); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - assert((total < 0) || (avail <= total)); - assert((total < 0) || (m_pos <= total)); //TODO: verify this + assert((total < 0) || (avail <= total)); + assert((total < 0) || (m_pos <= total)); // TODO: verify this - pos = m_pos; + pos = m_pos; - long long cluster_size = -1; + long long cluster_size = -1; - { - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + { + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(pReader, pos, len); + long long result = GetUIntLength(pReader, pos, len); - if (result < 0) //error or underflow - return static_cast(result); + if (result < 0) // error or underflow + return static_cast(result); - if (result > 0) //underflow (weird) - return E_BUFFER_NOT_FULL; + if (result > 0) // underflow (weird) + return E_BUFFER_NOT_FULL; - //if ((pos + len) > segment_stop) - // return E_FILE_FORMAT_INVALID; + // if ((pos + len) > segment_stop) + // return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long id_ = ReadUInt(pReader, pos, len); + const long long id_ = ReadUInt(pReader, pos, len); - if (id_ < 0) //error - return static_cast(id_); + if (id_ < 0) // error + return static_cast(id_); - if (id_ != 0x0F43B675) //Cluster ID - return E_FILE_FORMAT_INVALID; + if (id_ != 0x0F43B675) // Cluster ID + return E_FILE_FORMAT_INVALID; - pos += len; //consume id + pos += len; // consume id - //read cluster size + // read cluster size - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(pReader, pos, len); + result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - //if ((pos + len) > segment_stop) - // return E_FILE_FORMAT_INVALID; + // if ((pos + len) > segment_stop) + // return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(pReader, pos, len); + const long long size = ReadUInt(pReader, pos, len); - if (size < 0) //error - return static_cast(cluster_size); + if (size < 0) // error + return static_cast(cluster_size); - if (size == 0) - return E_FILE_FORMAT_INVALID; //TODO: verify this + if (size == 0) + return E_FILE_FORMAT_INVALID; // TODO: verify this - pos += len; //consume length of size of element + pos += len; // consume length of size of element - const long long unknown_size = (1LL << (7 * len)) - 1; + const long long unknown_size = (1LL << (7 * len)) - 1; - if (size != unknown_size) - cluster_size = size; - } + if (size != unknown_size) + cluster_size = size; + } - //pos points to start of payload +// pos points to start of payload #if 0 len = static_cast(size_); @@ -6891,397 +6125,376 @@ long Cluster::Load(long long& pos, long& len) const return E_BUFFER_NOT_FULL; #endif - long long timecode = -1; - long long new_pos = -1; - bool bBlock = false; + long long timecode = -1; + long long new_pos = -1; + bool bBlock = false; - long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; + long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; - for (;;) - { - if ((cluster_stop >= 0) && (pos >= cluster_stop)) - break; + for (;;) { + if ((cluster_stop >= 0) && (pos >= cluster_stop)) + break; - //Parse ID - - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + // Parse ID - long long result = GetUIntLength(pReader, pos, len); + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if (result < 0) //error - return static_cast(result); + long long result = GetUIntLength(pReader, pos, len); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result < 0) // error + return static_cast(result); - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - const long long id = ReadUInt(pReader, pos, len); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if (id < 0) //error - return static_cast(id); + const long long id = ReadUInt(pReader, pos, len); - if (id == 0) - return E_FILE_FORMAT_INVALID; + if (id < 0) // error + return static_cast(id); - //This is the distinguished set of ID's we use to determine - //that we have exhausted the sub-element's inside the cluster - //whose ID we parsed earlier. + if (id == 0) + return E_FILE_FORMAT_INVALID; - if (id == 0x0F43B675) //Cluster ID - break; + // This is the distinguished set of ID's we use to determine + // that we have exhausted the sub-element's inside the cluster + // whose ID we parsed earlier. - if (id == 0x0C53BB6B) //Cues ID - break; + if (id == 0x0F43B675) // Cluster ID + break; - pos += len; //consume ID field + if (id == 0x0C53BB6B) // Cues ID + break; - //Parse Size + pos += len; // consume ID field - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + // Parse Size - result = GetUIntLength(pReader, pos, len); + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if (result < 0) //error - return static_cast(result); + result = GetUIntLength(pReader, pos, len); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result < 0) // error + return static_cast(result); - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - const long long size = ReadUInt(pReader, pos, len); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if (size < 0) //error - return static_cast(size); + const long long size = ReadUInt(pReader, pos, len); - const long long unknown_size = (1LL << (7 * len)) - 1; + if (size < 0) // error + return static_cast(size); - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; + const long long unknown_size = (1LL << (7 * len)) - 1; - pos += len; //consume size field + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - if ((cluster_stop >= 0) && (pos > cluster_stop)) - return E_FILE_FORMAT_INVALID; + pos += len; // consume size field - //pos now points to start of payload + if ((cluster_stop >= 0) && (pos > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if (size == 0) //weird - continue; + // pos now points to start of payload - if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if (size == 0) // weird + continue; - if (id == 0x67) //TimeCode ID - { - len = static_cast(size); + if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + size) > avail) - return E_BUFFER_NOT_FULL; + if (id == 0x67) { // TimeCode ID + len = static_cast(size); - timecode = UnserializeUInt(pReader, pos, size); + if ((pos + size) > avail) + return E_BUFFER_NOT_FULL; - if (timecode < 0) //error (or underflow) - return static_cast(timecode); + timecode = UnserializeUInt(pReader, pos, size); - new_pos = pos + size; + if (timecode < 0) // error (or underflow) + return static_cast(timecode); - if (bBlock) - break; - } - else if (id == 0x20) //BlockGroup ID - { - bBlock = true; - break; - } - else if (id == 0x23) //SimpleBlock ID - { - bBlock = true; - break; - } + new_pos = pos + size; - pos += size; //consume payload - assert((cluster_stop < 0) || (pos <= cluster_stop)); + if (bBlock) + break; + } else if (id == 0x20) { // BlockGroup ID + bBlock = true; + break; + } else if (id == 0x23) { // SimpleBlock ID + bBlock = true; + break; } + pos += size; // consume payload assert((cluster_stop < 0) || (pos <= cluster_stop)); + } - if (timecode < 0) //no timecode found - return E_FILE_FORMAT_INVALID; + assert((cluster_stop < 0) || (pos <= cluster_stop)); - if (!bBlock) - return E_FILE_FORMAT_INVALID; + if (timecode < 0) // no timecode found + return E_FILE_FORMAT_INVALID; - m_pos = new_pos; //designates position just beyond timecode payload - m_timecode = timecode; // m_timecode >= 0 means we're partially loaded + if (!bBlock) + return E_FILE_FORMAT_INVALID; - if (cluster_size >= 0) - m_element_size = cluster_stop - m_element_start; + m_pos = new_pos; // designates position just beyond timecode payload + m_timecode = timecode; // m_timecode >= 0 means we're partially loaded - return 0; + if (cluster_size >= 0) + m_element_size = cluster_stop - m_element_start; + + return 0; } +long Cluster::Parse(long long& pos, long& len) const { + long status = Load(pos, len); -long Cluster::Parse(long long& pos, long& len) const -{ - long status = Load(pos, len); + if (status < 0) + return status; - if (status < 0) - return status; + assert(m_pos >= m_element_start); + assert(m_timecode >= 0); + // assert(m_size > 0); + // assert(m_element_size > m_size); - assert(m_pos >= m_element_start); - assert(m_timecode >= 0); - //assert(m_size > 0); - //assert(m_element_size > m_size); + const long long cluster_stop = + (m_element_size < 0) ? -1 : m_element_start + m_element_size; - const long long cluster_stop = - (m_element_size < 0) ? -1 : m_element_start + m_element_size; + if ((cluster_stop >= 0) && (m_pos >= cluster_stop)) + return 1; // nothing else to do - if ((cluster_stop >= 0) && (m_pos >= cluster_stop)) - return 1; //nothing else to do + IMkvReader* const pReader = m_pSegment->m_pReader; - IMkvReader* const pReader = m_pSegment->m_pReader; + long long total, avail; - long long total, avail; + status = pReader->Length(&total, &avail); - status = pReader->Length(&total, &avail); + if (status < 0) // error + return status; - if (status < 0) //error - return status; + assert((total < 0) || (avail <= total)); - assert((total < 0) || (avail <= total)); + pos = m_pos; - pos = m_pos; + for (;;) { + if ((cluster_stop >= 0) && (pos >= cluster_stop)) + break; - for (;;) - { - if ((cluster_stop >= 0) && (pos >= cluster_stop)) - break; + if ((total >= 0) && (pos >= total)) { + if (m_element_size < 0) + m_element_size = pos - m_element_start; - if ((total >= 0) && (pos >= total)) - { - if (m_element_size < 0) - m_element_size = pos - m_element_start; + break; + } - break; - } + // Parse ID - //Parse ID + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + long long result = GetUIntLength(pReader, pos, len); - long long result = GetUIntLength(pReader, pos, len); + if (result < 0) // error + return static_cast(result); - if (result < 0) //error - return static_cast(result); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + const long long id = ReadUInt(pReader, pos, len); - const long long id = ReadUInt(pReader, pos, len); + if (id < 0) // error + return static_cast(id); - if (id < 0) //error - return static_cast(id); + if (id == 0) // weird + return E_FILE_FORMAT_INVALID; - if (id == 0) //weird - return E_FILE_FORMAT_INVALID; + // This is the distinguished set of ID's we use to determine + // that we have exhausted the sub-element's inside the cluster + // whose ID we parsed earlier. - //This is the distinguished set of ID's we use to determine - //that we have exhausted the sub-element's inside the cluster - //whose ID we parsed earlier. + if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID + if (m_element_size < 0) + m_element_size = pos - m_element_start; - if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) //Cluster or Cues ID - { - if (m_element_size < 0) - m_element_size = pos - m_element_start; + break; + } - break; - } + pos += len; // consume ID field - pos += len; //consume ID field + // Parse Size - //Parse Size + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + result = GetUIntLength(pReader, pos, len); - result = GetUIntLength(pReader, pos, len); + if (result < 0) // error + return static_cast(result); - if (result < 0) //error - return static_cast(result); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + const long long size = ReadUInt(pReader, pos, len); - const long long size = ReadUInt(pReader, pos, len); + if (size < 0) // error + return static_cast(size); - if (size < 0) //error - return static_cast(size); + const long long unknown_size = (1LL << (7 * len)) - 1; - const long long unknown_size = (1LL << (7 * len)) - 1; + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; + pos += len; // consume size field - pos += len; //consume size field + if ((cluster_stop >= 0) && (pos > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((cluster_stop >= 0) && (pos > cluster_stop)) - return E_FILE_FORMAT_INVALID; + // pos now points to start of payload - //pos now points to start of payload + if (size == 0) // weird + continue; - if (size == 0) //weird - continue; + // const long long block_start = pos; + const long long block_stop = pos + size; - //const long long block_start = pos; - const long long block_stop = pos + size; + if (cluster_stop >= 0) { + if (block_stop > cluster_stop) { + if ((id == 0x20) || (id == 0x23)) + return E_FILE_FORMAT_INVALID; - if (cluster_stop >= 0) - { - if (block_stop > cluster_stop) - return E_FILE_FORMAT_INVALID; - } - else if ((total >= 0) && (block_stop > total)) - { - m_element_size = total - m_element_start; - pos = total; - break; - } - else if (block_stop > avail) - { - len = static_cast(size); - return E_BUFFER_NOT_FULL; - } + pos = cluster_stop; + break; + } + } else if ((total >= 0) && (block_stop > total)) { + m_element_size = total - m_element_start; + pos = total; + break; + } else if (block_stop > avail) { + len = static_cast(size); + return E_BUFFER_NOT_FULL; + } - Cluster* const this_ = const_cast(this); + Cluster* const this_ = const_cast(this); - if (id == 0x20) //BlockGroup - return this_->ParseBlockGroup(size, pos, len); + if (id == 0x20) // BlockGroup + return this_->ParseBlockGroup(size, pos, len); - if (id == 0x23) //SimpleBlock - return this_->ParseSimpleBlock(size, pos, len); + if (id == 0x23) // SimpleBlock + return this_->ParseSimpleBlock(size, pos, len); - pos += size; //consume payload - assert((cluster_stop < 0) || (pos <= cluster_stop)); - } + pos += size; // consume payload + assert((cluster_stop < 0) || (pos <= cluster_stop)); + } - assert(m_element_size > 0); + assert(m_element_size > 0); - m_pos = pos; - assert((cluster_stop < 0) || (m_pos <= cluster_stop)); + m_pos = pos; + assert((cluster_stop < 0) || (m_pos <= cluster_stop)); - if (m_entries_count > 0) - { - const long idx = m_entries_count - 1; + if (m_entries_count > 0) { + const long idx = m_entries_count - 1; - const BlockEntry* const pLast = m_entries[idx]; - assert(pLast); + const BlockEntry* const pLast = m_entries[idx]; + assert(pLast); - const Block* const pBlock = pLast->GetBlock(); - assert(pBlock); + const Block* const pBlock = pLast->GetBlock(); + assert(pBlock); - const long long start = pBlock->m_start; + const long long start = pBlock->m_start; - if ((total >= 0) && (start > total)) - return -1; //defend against trucated stream + if ((total >= 0) && (start > total)) + return -1; // defend against trucated stream - const long long size = pBlock->m_size; + const long long size = pBlock->m_size; - const long long stop = start + size; - assert((cluster_stop < 0) || (stop <= cluster_stop)); + const long long stop = start + size; + assert((cluster_stop < 0) || (stop <= cluster_stop)); - if ((total >= 0) && (stop > total)) - return -1; //defend against trucated stream - } + if ((total >= 0) && (stop > total)) + return -1; // defend against trucated stream + } - return 1; //no more entries + return 1; // no more entries } +long Cluster::ParseSimpleBlock(long long block_size, long long& pos, + long& len) { + const long long block_start = pos; + const long long block_stop = pos + block_size; -long Cluster::ParseSimpleBlock( - long long block_size, - long long& pos, - long& len) -{ - const long long block_start = pos; - const long long block_stop = pos + block_size; - - IMkvReader* const pReader = m_pSegment->m_pReader; - - long long total, avail; - - long status = pReader->Length(&total, &avail); + IMkvReader* const pReader = m_pSegment->m_pReader; - if (status < 0) //error - return status; + long long total, avail; - assert((total < 0) || (avail <= total)); + long status = pReader->Length(&total, &avail); - //parse track number + if (status < 0) // error + return status; - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + assert((total < 0) || (avail <= total)); - long long result = GetUIntLength(pReader, pos, len); + // parse track number - if (result < 0) //error - return static_cast(result); + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + long long result = GetUIntLength(pReader, pos, len); - if ((pos + len) > block_stop) - return E_FILE_FORMAT_INVALID; + if (result < 0) // error + return static_cast(result); - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - const long long track = ReadUInt(pReader, pos, len); + if ((pos + len) > block_stop) + return E_FILE_FORMAT_INVALID; - if (track < 0) //error - return static_cast(track); + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if (track == 0) - return E_FILE_FORMAT_INVALID; + const long long track = ReadUInt(pReader, pos, len); + + if (track < 0) // error + return static_cast(track); + + if (track == 0) + return E_FILE_FORMAT_INVALID; #if 0 //TODO(matthewjheaney) @@ -7313,211 +6526,208 @@ long Cluster::ParseSimpleBlock( return E_FILE_FORMAT_INVALID; #endif - pos += len; //consume track number + pos += len; // consume track number - if ((pos + 2) > block_stop) - return E_FILE_FORMAT_INVALID; + if ((pos + 2) > block_stop) + return E_FILE_FORMAT_INVALID; - if ((pos + 2) > avail) - { - len = 2; - return E_BUFFER_NOT_FULL; - } + if ((pos + 2) > avail) { + len = 2; + return E_BUFFER_NOT_FULL; + } - pos += 2; //consume timecode + pos += 2; // consume timecode - if ((pos + 1) > block_stop) - return E_FILE_FORMAT_INVALID; + if ((pos + 1) > block_stop) + return E_FILE_FORMAT_INVALID; - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - unsigned char flags; + unsigned char flags; - status = pReader->Read(pos, 1, &flags); + status = pReader->Read(pos, 1, &flags); - if (status < 0) //error or underflow - { - len = 1; - return status; - } + if (status < 0) { // error or underflow + len = 1; + return status; + } - ++pos; //consume flags byte - assert(pos <= avail); + ++pos; // consume flags byte + assert(pos <= avail); - if (pos >= block_stop) - return E_FILE_FORMAT_INVALID; + if (pos >= block_stop) + return E_FILE_FORMAT_INVALID; - const int lacing = int(flags & 0x06) >> 1; + const int lacing = int(flags & 0x06) >> 1; - if ((lacing != 0) && (block_stop > avail)) - { - len = static_cast(block_stop - pos); - return E_BUFFER_NOT_FULL; - } + if ((lacing != 0) && (block_stop > avail)) { + len = static_cast(block_stop - pos); + return E_BUFFER_NOT_FULL; + } - status = CreateBlock(0x23, block_start, block_size); //simple block id + status = CreateBlock(0x23, // simple block id + block_start, block_size, + 0); // DiscardPadding - if (status != 0) - return status; + if (status != 0) + return status; - m_pos = block_stop; + m_pos = block_stop; - return 0; //success + return 0; // success } +long Cluster::ParseBlockGroup(long long payload_size, long long& pos, + long& len) { + const long long payload_start = pos; + const long long payload_stop = pos + payload_size; -long Cluster::ParseBlockGroup( - long long payload_size, - long long& pos, - long& len) -{ - const long long payload_start = pos; - const long long payload_stop = pos + payload_size; + IMkvReader* const pReader = m_pSegment->m_pReader; - IMkvReader* const pReader = m_pSegment->m_pReader; + long long total, avail; - long long total, avail; + long status = pReader->Length(&total, &avail); - long status = pReader->Length(&total, &avail); + if (status < 0) // error + return status; - if (status < 0) //error - return status; + assert((total < 0) || (avail <= total)); - assert((total < 0) || (avail <= total)); + if ((total >= 0) && (payload_stop > total)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && (payload_stop > total)) - return E_FILE_FORMAT_INVALID; + if (payload_stop > avail) { + len = static_cast(payload_size); + return E_BUFFER_NOT_FULL; + } - if (payload_stop > avail) - { - len = static_cast(payload_size); - return E_BUFFER_NOT_FULL; + long long discard_padding = 0; + + while (pos < payload_stop) { + // parse sub-block element ID + + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; } - while (pos < payload_stop) - { - //parse sub-block element ID + long long result = GetUIntLength(pReader, pos, len); - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if (result < 0) // error + return static_cast(result); - long long result = GetUIntLength(pReader, pos, len); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (result < 0) //error - return static_cast(result); + if ((pos + len) > payload_stop) + return E_FILE_FORMAT_INVALID; - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if ((pos + len) > payload_stop) - return E_FILE_FORMAT_INVALID; + const long long id = ReadUInt(pReader, pos, len); - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if (id < 0) // error + return static_cast(id); - const long long id = ReadUInt(pReader, pos, len); + if (id == 0) // not a value ID + return E_FILE_FORMAT_INVALID; - if (id < 0) //error - return static_cast(id); + pos += len; // consume ID field - if (id == 0) //not a value ID - return E_FILE_FORMAT_INVALID; + // Parse Size - pos += len; //consume ID field + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - //Parse Size + result = GetUIntLength(pReader, pos, len); - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if (result < 0) // error + return static_cast(result); - result = GetUIntLength(pReader, pos, len); + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if (result < 0) //error - return static_cast(result); + if ((pos + len) > payload_stop) + return E_FILE_FORMAT_INVALID; - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - if ((pos + len) > payload_stop) - return E_FILE_FORMAT_INVALID; + const long long size = ReadUInt(pReader, pos, len); - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if (size < 0) // error + return static_cast(size); - const long long size = ReadUInt(pReader, pos, len); + pos += len; // consume size field - if (size < 0) //error - return static_cast(size); + // pos now points to start of sub-block group payload - pos += len; //consume size field + if (pos > payload_stop) + return E_FILE_FORMAT_INVALID; - //pos now points to start of sub-block group payload + if (size == 0) // weird + continue; - if (pos > payload_stop) - return E_FILE_FORMAT_INVALID; + const long long unknown_size = (1LL << (7 * len)) - 1; - if (size == 0) //weird - continue; + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; - const long long unknown_size = (1LL << (7 * len)) - 1; + if (id == 0x35A2) { // DiscardPadding + status = UnserializeInt(pReader, pos, size, discard_padding); - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; + if (status < 0) // error + return status; + } - if (id != 0x21) //sub-part of BlockGroup is not a Block - { - pos += size; //consume sub-part of block group + if (id != 0x21) { // sub-part of BlockGroup is not a Block + pos += size; // consume sub-part of block group - if (pos > payload_stop) - return E_FILE_FORMAT_INVALID; + if (pos > payload_stop) + return E_FILE_FORMAT_INVALID; - continue; - } + continue; + } - const long long block_stop = pos + size; + const long long block_stop = pos + size; - if (block_stop > payload_stop) - return E_FILE_FORMAT_INVALID; + if (block_stop > payload_stop) + return E_FILE_FORMAT_INVALID; - //parse track number + // parse track number - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(pReader, pos, len); + result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((pos + len) > block_stop) - return E_FILE_FORMAT_INVALID; + if ((pos + len) > block_stop) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long track = ReadUInt(pReader, pos, len); + const long long track = ReadUInt(pReader, pos, len); - if (track < 0) //error - return static_cast(track); + if (track < 0) // error + return static_cast(track); - if (track == 0) - return E_FILE_FORMAT_INVALID; + if (track == 0) + return E_FILE_FORMAT_INVALID; #if 0 //TODO(matthewjheaney) @@ -7549,212 +6759,173 @@ long Cluster::ParseBlockGroup( return E_FILE_FORMAT_INVALID; #endif - pos += len; //consume track number - - if ((pos + 2) > block_stop) - return E_FILE_FORMAT_INVALID; + pos += len; // consume track number - if ((pos + 2) > avail) - { - len = 2; - return E_BUFFER_NOT_FULL; - } + if ((pos + 2) > block_stop) + return E_FILE_FORMAT_INVALID; - pos += 2; //consume timecode + if ((pos + 2) > avail) { + len = 2; + return E_BUFFER_NOT_FULL; + } - if ((pos + 1) > block_stop) - return E_FILE_FORMAT_INVALID; + pos += 2; // consume timecode - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > block_stop) + return E_FILE_FORMAT_INVALID; - unsigned char flags; + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - status = pReader->Read(pos, 1, &flags); + unsigned char flags; - if (status < 0) //error or underflow - { - len = 1; - return status; - } + status = pReader->Read(pos, 1, &flags); - ++pos; //consume flags byte - assert(pos <= avail); + if (status < 0) { // error or underflow + len = 1; + return status; + } - if (pos >= block_stop) - return E_FILE_FORMAT_INVALID; + ++pos; // consume flags byte + assert(pos <= avail); - const int lacing = int(flags & 0x06) >> 1; + if (pos >= block_stop) + return E_FILE_FORMAT_INVALID; - if ((lacing != 0) && (block_stop > avail)) - { - len = static_cast(block_stop - pos); - return E_BUFFER_NOT_FULL; - } + const int lacing = int(flags & 0x06) >> 1; - pos = block_stop; //consume block-part of block group - assert(pos <= payload_stop); + if ((lacing != 0) && (block_stop > avail)) { + len = static_cast(block_stop - pos); + return E_BUFFER_NOT_FULL; } - assert(pos == payload_stop); + pos = block_stop; // consume block-part of block group + assert(pos <= payload_stop); + } - status = CreateBlock(0x20, payload_start, payload_size); //BlockGroup ID + assert(pos == payload_stop); - if (status != 0) - return status; + status = CreateBlock(0x20, // BlockGroup ID + payload_start, payload_size, discard_padding); + if (status != 0) + return status; - m_pos = payload_stop; + m_pos = payload_stop; - return 0; //success + return 0; // success } +long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const { + assert(m_pos >= m_element_start); -long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const -{ - assert(m_pos >= m_element_start); - - pEntry = NULL; + pEntry = NULL; - if (index < 0) - return -1; //generic error + if (index < 0) + return -1; // generic error - if (m_entries_count < 0) - return E_BUFFER_NOT_FULL; + if (m_entries_count < 0) + return E_BUFFER_NOT_FULL; - assert(m_entries); - assert(m_entries_size > 0); - assert(m_entries_count <= m_entries_size); + assert(m_entries); + assert(m_entries_size > 0); + assert(m_entries_count <= m_entries_size); - if (index < m_entries_count) - { - pEntry = m_entries[index]; - assert(pEntry); + if (index < m_entries_count) { + pEntry = m_entries[index]; + assert(pEntry); - return 1; //found entry - } + return 1; // found entry + } - if (m_element_size < 0) //we don't know cluster end yet - return E_BUFFER_NOT_FULL; //underflow + if (m_element_size < 0) // we don't know cluster end yet + return E_BUFFER_NOT_FULL; // underflow - const long long element_stop = m_element_start + m_element_size; + const long long element_stop = m_element_start + m_element_size; - if (m_pos >= element_stop) - return 0; //nothing left to parse + if (m_pos >= element_stop) + return 0; // nothing left to parse - return E_BUFFER_NOT_FULL; //underflow, since more remains to be parsed + return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed } - -Cluster* Cluster::Create( - Segment* pSegment, - long idx, - long long off) - //long long element_size) +Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) +// long long element_size) { - assert(pSegment); - assert(off >= 0); - - const long long element_start = pSegment->m_start + off; - - Cluster* const pCluster = new Cluster(pSegment, - idx, - element_start); - //element_size); - assert(pCluster); - - return pCluster; -} + assert(pSegment); + assert(off >= 0); + const long long element_start = pSegment->m_start + off; -Cluster::Cluster() : - m_pSegment(NULL), - m_element_start(0), - m_index(0), - m_pos(0), - m_element_size(0), - m_timecode(0), - m_entries(NULL), - m_entries_size(0), - m_entries_count(0) //means "no entries" -{ -} + Cluster* const pCluster = new Cluster(pSegment, idx, element_start); + // element_size); + assert(pCluster); - -Cluster::Cluster( - Segment* pSegment, - long idx, - long long element_start - /* long long element_size */ ) : - m_pSegment(pSegment), - m_element_start(element_start), - m_index(idx), - m_pos(element_start), - m_element_size(-1 /* element_size */ ), - m_timecode(-1), - m_entries(NULL), - m_entries_size(0), - m_entries_count(-1) //means "has not been parsed yet" -{ + return pCluster; } +Cluster::Cluster() + : m_pSegment(NULL), + m_element_start(0), + m_index(0), + m_pos(0), + m_element_size(0), + m_timecode(0), + m_entries(NULL), + m_entries_size(0), + m_entries_count(0) // means "no entries" +{} -Cluster::~Cluster() -{ - if (m_entries_count <= 0) - return; - - BlockEntry** i = m_entries; - BlockEntry** const j = m_entries + m_entries_count; - - while (i != j) - { - BlockEntry* p = *i++; - assert(p); - - delete p; - } +Cluster::Cluster(Segment* pSegment, long idx, long long element_start + /* long long element_size */) + : m_pSegment(pSegment), + m_element_start(element_start), + m_index(idx), + m_pos(element_start), + m_element_size(-1 /* element_size */), + m_timecode(-1), + m_entries(NULL), + m_entries_size(0), + m_entries_count(-1) // means "has not been parsed yet" +{} - delete[] m_entries; -} +Cluster::~Cluster() { + if (m_entries_count <= 0) + return; + BlockEntry** i = m_entries; + BlockEntry** const j = m_entries + m_entries_count; -bool Cluster::EOS() const -{ - return (m_pSegment == NULL); -} + while (i != j) { + BlockEntry* p = *i++; + assert(p); + delete p; + } -long Cluster::GetIndex() const -{ - return m_index; + delete[] m_entries; } +bool Cluster::EOS() const { return (m_pSegment == NULL); } -long long Cluster::GetPosition() const -{ - const long long pos = m_element_start - m_pSegment->m_start; - assert(pos >= 0); - - return pos; -} +long Cluster::GetIndex() const { return m_index; } +long long Cluster::GetPosition() const { + const long long pos = m_element_start - m_pSegment->m_start; + assert(pos >= 0); -long long Cluster::GetElementSize() const -{ - return m_element_size; + return pos; } +long long Cluster::GetElementSize() const { return m_element_size; } #if 0 bool Cluster::HasBlockEntries( const Segment* pSegment, - long long off) //relative to start of segment payload -{ + long long off) { assert(pSegment); - assert(off >= 0); //relative to segment + assert(off >= 0); //relative to start of segment payload IMkvReader* const pReader = pSegment->m_pReader; @@ -7811,626 +6982,558 @@ bool Cluster::HasBlockEntries( } #endif - long Cluster::HasBlockEntries( const Segment* pSegment, - long long off, //relative to start of segment payload - long long& pos, - long& len) -{ - assert(pSegment); - assert(off >= 0); //relative to segment + long long off, // relative to start of segment payload + long long& pos, long& len) { + assert(pSegment); + assert(off >= 0); // relative to segment - IMkvReader* const pReader = pSegment->m_pReader; + IMkvReader* const pReader = pSegment->m_pReader; - long long total, avail; + long long total, avail; - long status = pReader->Length(&total, &avail); + long status = pReader->Length(&total, &avail); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - assert((total < 0) || (avail <= total)); + assert((total < 0) || (avail <= total)); - pos = pSegment->m_start + off; //absolute + pos = pSegment->m_start + off; // absolute - if ((total >= 0) && (pos >= total)) - return 0; //we don't even have a complete cluster + if ((total >= 0) && (pos >= total)) + return 0; // we don't even have a complete cluster - const long long segment_stop = - (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size; + const long long segment_stop = + (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size; - long long cluster_stop = -1; //interpreted later to mean "unknown size" + long long cluster_stop = -1; // interpreted later to mean "unknown size" - { - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + { + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(pReader, pos, len); + long long result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //need more data - return E_BUFFER_NOT_FULL; + if (result > 0) // need more data + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && ((pos + len) > total)) - return 0; + if ((total >= 0) && ((pos + len) > total)) + return 0; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long id = ReadUInt(pReader, pos, len); + const long long id = ReadUInt(pReader, pos, len); - if (id < 0) //error - return static_cast(id); + if (id < 0) // error + return static_cast(id); - if (id != 0x0F43B675) //weird: not cluster ID - return -1; //generic error + if (id != 0x0F43B675) // weird: not cluster ID + return -1; // generic error - pos += len; //consume Cluster ID field + pos += len; // consume Cluster ID field - //read size field + // read size field - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(pReader, pos, len); + result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //weird - return E_BUFFER_NOT_FULL; + if (result > 0) // weird + return E_BUFFER_NOT_FULL; - if ((segment_stop >= 0) && ((pos + len) > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && ((pos + len) > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && ((pos + len) > total)) - return 0; + if ((total >= 0) && ((pos + len) > total)) + return 0; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(pReader, pos, len); + const long long size = ReadUInt(pReader, pos, len); - if (size < 0) //error - return static_cast(size); + if (size < 0) // error + return static_cast(size); - if (size == 0) - return 0; //cluster does not have entries + if (size == 0) + return 0; // cluster does not have entries - pos += len; //consume size field + pos += len; // consume size field - //pos now points to start of payload + // pos now points to start of payload - const long long unknown_size = (1LL << (7 * len)) - 1; + const long long unknown_size = (1LL << (7 * len)) - 1; - if (size != unknown_size) - { - cluster_stop = pos + size; - assert(cluster_stop >= 0); + if (size != unknown_size) { + cluster_stop = pos + size; + assert(cluster_stop >= 0); - if ((segment_stop >= 0) && (cluster_stop > segment_stop)) - return E_FILE_FORMAT_INVALID; + if ((segment_stop >= 0) && (cluster_stop > segment_stop)) + return E_FILE_FORMAT_INVALID; - if ((total >= 0) && (cluster_stop > total)) - //return E_FILE_FORMAT_INVALID; //too conservative - return 0; //cluster does not have any entries - } + if ((total >= 0) && (cluster_stop > total)) + // return E_FILE_FORMAT_INVALID; //too conservative + return 0; // cluster does not have any entries } + } - for (;;) - { - if ((cluster_stop >= 0) && (pos >= cluster_stop)) - return 0; //no entries detected + for (;;) { + if ((cluster_stop >= 0) && (pos >= cluster_stop)) + return 0; // no entries detected - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - long long result = GetUIntLength(pReader, pos, len); + long long result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //need more data - return E_BUFFER_NOT_FULL; + if (result > 0) // need more data + return E_BUFFER_NOT_FULL; - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long id = ReadUInt(pReader, pos, len); + const long long id = ReadUInt(pReader, pos, len); - if (id < 0) //error - return static_cast(id); + if (id < 0) // error + return static_cast(id); - //This is the distinguished set of ID's we use to determine - //that we have exhausted the sub-element's inside the cluster - //whose ID we parsed earlier. + // This is the distinguished set of ID's we use to determine + // that we have exhausted the sub-element's inside the cluster + // whose ID we parsed earlier. - if (id == 0x0F43B675) //Cluster ID - return 0; //no entries found + if (id == 0x0F43B675) // Cluster ID + return 0; // no entries found - if (id == 0x0C53BB6B) //Cues ID - return 0; //no entries found + if (id == 0x0C53BB6B) // Cues ID + return 0; // no entries found - pos += len; //consume id field + pos += len; // consume id field - if ((cluster_stop >= 0) && (pos >= cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((cluster_stop >= 0) && (pos >= cluster_stop)) + return E_FILE_FORMAT_INVALID; - //read size field + // read size field - if ((pos + 1) > avail) - { - len = 1; - return E_BUFFER_NOT_FULL; - } + if ((pos + 1) > avail) { + len = 1; + return E_BUFFER_NOT_FULL; + } - result = GetUIntLength(pReader, pos, len); + result = GetUIntLength(pReader, pos, len); - if (result < 0) //error - return static_cast(result); + if (result < 0) // error + return static_cast(result); - if (result > 0) //underflow - return E_BUFFER_NOT_FULL; + if (result > 0) // underflow + return E_BUFFER_NOT_FULL; - if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if ((pos + len) > avail) - return E_BUFFER_NOT_FULL; + if ((pos + len) > avail) + return E_BUFFER_NOT_FULL; - const long long size = ReadUInt(pReader, pos, len); + const long long size = ReadUInt(pReader, pos, len); - if (size < 0) //error - return static_cast(size); + if (size < 0) // error + return static_cast(size); - pos += len; //consume size field + pos += len; // consume size field - //pos now points to start of payload + // pos now points to start of payload - if ((cluster_stop >= 0) && (pos > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((cluster_stop >= 0) && (pos > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if (size == 0) //weird - continue; + if (size == 0) // weird + continue; - const long long unknown_size = (1LL << (7 * len)) - 1; + const long long unknown_size = (1LL << (7 * len)) - 1; - if (size == unknown_size) - return E_FILE_FORMAT_INVALID; //not supported inside cluster + if (size == unknown_size) + return E_FILE_FORMAT_INVALID; // not supported inside cluster - if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) - return E_FILE_FORMAT_INVALID; + if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) + return E_FILE_FORMAT_INVALID; - if (id == 0x20) //BlockGroup ID - return 1; //have at least one entry + if (id == 0x20) // BlockGroup ID + return 1; // have at least one entry - if (id == 0x23) //SimpleBlock ID - return 1; //have at least one entry + if (id == 0x23) // SimpleBlock ID + return 1; // have at least one entry - pos += size; //consume payload - assert((cluster_stop < 0) || (pos <= cluster_stop)); - } + pos += size; // consume payload + assert((cluster_stop < 0) || (pos <= cluster_stop)); + } } +long long Cluster::GetTimeCode() const { + long long pos; + long len; -long long Cluster::GetTimeCode() const -{ - long long pos; - long len; - - const long status = Load(pos, len); + const long status = Load(pos, len); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - return m_timecode; + return m_timecode; } +long long Cluster::GetTime() const { + const long long tc = GetTimeCode(); -long long Cluster::GetTime() const -{ - const long long tc = GetTimeCode(); - - if (tc < 0) - return tc; + if (tc < 0) + return tc; - const SegmentInfo* const pInfo = m_pSegment->GetInfo(); - assert(pInfo); + const SegmentInfo* const pInfo = m_pSegment->GetInfo(); + assert(pInfo); - const long long scale = pInfo->GetTimeCodeScale(); - assert(scale >= 1); + const long long scale = pInfo->GetTimeCodeScale(); + assert(scale >= 1); - const long long t = m_timecode * scale; + const long long t = m_timecode * scale; - return t; + return t; } +long long Cluster::GetFirstTime() const { + const BlockEntry* pEntry; -long long Cluster::GetFirstTime() const -{ - const BlockEntry* pEntry; - - const long status = GetFirst(pEntry); + const long status = GetFirst(pEntry); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - if (pEntry == NULL) //empty cluster - return GetTime(); + if (pEntry == NULL) // empty cluster + return GetTime(); - const Block* const pBlock = pEntry->GetBlock(); - assert(pBlock); + const Block* const pBlock = pEntry->GetBlock(); + assert(pBlock); - return pBlock->GetTime(this); + return pBlock->GetTime(this); } +long long Cluster::GetLastTime() const { + const BlockEntry* pEntry; -long long Cluster::GetLastTime() const -{ - const BlockEntry* pEntry; - - const long status = GetLast(pEntry); + const long status = GetLast(pEntry); - if (status < 0) //error - return status; + if (status < 0) // error + return status; - if (pEntry == NULL) //empty cluster - return GetTime(); + if (pEntry == NULL) // empty cluster + return GetTime(); - const Block* const pBlock = pEntry->GetBlock(); - assert(pBlock); + const Block* const pBlock = pEntry->GetBlock(); + assert(pBlock); - return pBlock->GetTime(this); + return pBlock->GetTime(this); } +long Cluster::CreateBlock(long long id, + long long pos, // absolute pos of payload + long long size, long long discard_padding) { + assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock -long Cluster::CreateBlock( - long long id, - long long pos, //absolute pos of payload - long long size) -{ - assert((id == 0x20) || (id == 0x23)); //BlockGroup or SimpleBlock - - if (m_entries_count < 0) //haven't parsed anything yet - { - assert(m_entries == NULL); - assert(m_entries_size == 0); + if (m_entries_count < 0) { // haven't parsed anything yet + assert(m_entries == NULL); + assert(m_entries_size == 0); - m_entries_size = 1024; - m_entries = new BlockEntry*[m_entries_size]; + m_entries_size = 1024; + m_entries = new BlockEntry* [m_entries_size]; - m_entries_count = 0; - } - else - { - assert(m_entries); - assert(m_entries_size > 0); - assert(m_entries_count <= m_entries_size); + m_entries_count = 0; + } else { + assert(m_entries); + assert(m_entries_size > 0); + assert(m_entries_count <= m_entries_size); - if (m_entries_count >= m_entries_size) - { - const long entries_size = 2 * m_entries_size; + if (m_entries_count >= m_entries_size) { + const long entries_size = 2 * m_entries_size; - BlockEntry** const entries = new BlockEntry*[entries_size]; - assert(entries); + BlockEntry** const entries = new BlockEntry* [entries_size]; + assert(entries); - BlockEntry** src = m_entries; - BlockEntry** const src_end = src + m_entries_count; + BlockEntry** src = m_entries; + BlockEntry** const src_end = src + m_entries_count; - BlockEntry** dst = entries; + BlockEntry** dst = entries; - while (src != src_end) - *dst++ = *src++; + while (src != src_end) + *dst++ = *src++; - delete[] m_entries; + delete[] m_entries; - m_entries = entries; - m_entries_size = entries_size; - } + m_entries = entries; + m_entries_size = entries_size; } + } - if (id == 0x20) //BlockGroup ID - return CreateBlockGroup(pos, size); - else //SimpleBlock ID - return CreateSimpleBlock(pos, size); + if (id == 0x20) // BlockGroup ID + return CreateBlockGroup(pos, size, discard_padding); + else // SimpleBlock ID + return CreateSimpleBlock(pos, size); } +long Cluster::CreateBlockGroup(long long start_offset, long long size, + long long discard_padding) { + assert(m_entries); + assert(m_entries_size > 0); + assert(m_entries_count >= 0); + assert(m_entries_count < m_entries_size); -long Cluster::CreateBlockGroup( - long long st, - long long sz) -{ - assert(m_entries); - assert(m_entries_size > 0); - assert(m_entries_count >= 0); - assert(m_entries_count < m_entries_size); - - IMkvReader* const pReader = m_pSegment->m_pReader; - - long long pos = st; - const long long stop = st + sz; + IMkvReader* const pReader = m_pSegment->m_pReader; - //For WebM files, there is a bias towards previous reference times - //(in order to support alt-ref frames, which refer back to the previous - //keyframe). Normally a 0 value is not possible, but here we tenatively - //allow 0 as the value of a reference frame, with the interpretation - //that this is a "previous" reference time. + long long pos = start_offset; + const long long stop = start_offset + size; - long long prev = 1; //nonce - long long next = 0; //nonce - long long duration = -1; //really, this is unsigned + // For WebM files, there is a bias towards previous reference times + //(in order to support alt-ref frames, which refer back to the previous + // keyframe). Normally a 0 value is not possible, but here we tenatively + // allow 0 as the value of a reference frame, with the interpretation + // that this is a "previous" reference time. - long long bpos = -1; - long long bsize = -1; + long long prev = 1; // nonce + long long next = 0; // nonce + long long duration = -1; // really, this is unsigned - while (pos < stop) - { - long len; - const long long id = ReadUInt(pReader, pos, len); - assert(id >= 0); //TODO - assert((pos + len) <= stop); + long long bpos = -1; + long long bsize = -1; - pos += len; //consume ID + while (pos < stop) { + long len; + const long long id = ReadUInt(pReader, pos, len); + assert(id >= 0); // TODO + assert((pos + len) <= stop); - const long long size = ReadUInt(pReader, pos, len); - assert(size >= 0); //TODO - assert((pos + len) <= stop); + pos += len; // consume ID - pos += len; //consume size + const long long size = ReadUInt(pReader, pos, len); + assert(size >= 0); // TODO + assert((pos + len) <= stop); - if (id == 0x21) //Block ID - { - if (bpos < 0) //Block ID - { - bpos = pos; - bsize = size; - } - } - else if (id == 0x1B) //Duration ID - { - assert(size <= 8); + pos += len; // consume size - duration = UnserializeUInt(pReader, pos, size); - assert(duration >= 0); //TODO - } - else if (id == 0x7B) //ReferenceBlock - { - assert(size <= 8); - const long size_ = static_cast(size); + if (id == 0x21) { // Block ID + if (bpos < 0) { // Block ID + bpos = pos; + bsize = size; + } + } else if (id == 0x1B) { // Duration ID + assert(size <= 8); - long long time; + duration = UnserializeUInt(pReader, pos, size); + assert(duration >= 0); // TODO + } else if (id == 0x7B) { // ReferenceBlock + assert(size <= 8); + const long size_ = static_cast(size); - long status = UnserializeInt(pReader, pos, size_, time); - assert(status == 0); //TODO + long long time; - if (time <= 0) //see note above - prev = time; - else //weird - next = time; - } + long status = UnserializeInt(pReader, pos, size_, time); + assert(status == 0); + if (status != 0) + return -1; - pos += size; //consume payload - assert(pos <= stop); + if (time <= 0) // see note above + prev = time; + else // weird + next = time; } - assert(pos == stop); - assert(bpos >= 0); - assert(bsize >= 0); - - const long idx = m_entries_count; + pos += size; // consume payload + assert(pos <= stop); + } - BlockEntry** const ppEntry = m_entries + idx; - BlockEntry*& pEntry = *ppEntry; + assert(pos == stop); + assert(bpos >= 0); + assert(bsize >= 0); - pEntry = new (std::nothrow) BlockGroup( - this, - idx, - bpos, - bsize, - prev, - next, - duration); + const long idx = m_entries_count; - if (pEntry == NULL) - return -1; //generic error + BlockEntry** const ppEntry = m_entries + idx; + BlockEntry*& pEntry = *ppEntry; - BlockGroup* const p = static_cast(pEntry); + pEntry = new (std::nothrow) + BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding); - const long status = p->Parse(); + if (pEntry == NULL) + return -1; // generic error - if (status == 0) //success - { - ++m_entries_count; - return 0; - } + BlockGroup* const p = static_cast(pEntry); - delete pEntry; - pEntry = 0; + const long status = p->Parse(); - return status; -} + if (status == 0) { // success + ++m_entries_count; + return 0; + } + delete pEntry; + pEntry = 0; + return status; +} -long Cluster::CreateSimpleBlock( - long long st, - long long sz) -{ - assert(m_entries); - assert(m_entries_size > 0); - assert(m_entries_count >= 0); - assert(m_entries_count < m_entries_size); +long Cluster::CreateSimpleBlock(long long st, long long sz) { + assert(m_entries); + assert(m_entries_size > 0); + assert(m_entries_count >= 0); + assert(m_entries_count < m_entries_size); - const long idx = m_entries_count; + const long idx = m_entries_count; - BlockEntry** const ppEntry = m_entries + idx; - BlockEntry*& pEntry = *ppEntry; + BlockEntry** const ppEntry = m_entries + idx; + BlockEntry*& pEntry = *ppEntry; - pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz); + pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz); - if (pEntry == NULL) - return -1; //generic error + if (pEntry == NULL) + return -1; // generic error - SimpleBlock* const p = static_cast(pEntry); + SimpleBlock* const p = static_cast(pEntry); - const long status = p->Parse(); + const long status = p->Parse(); - if (status == 0) - { - ++m_entries_count; - return 0; - } + if (status == 0) { + ++m_entries_count; + return 0; + } - delete pEntry; - pEntry = 0; + delete pEntry; + pEntry = 0; - return status; + return status; } +long Cluster::GetFirst(const BlockEntry*& pFirst) const { + if (m_entries_count <= 0) { + long long pos; + long len; -long Cluster::GetFirst(const BlockEntry*& pFirst) const -{ - if (m_entries_count <= 0) - { - long long pos; - long len; - - const long status = Parse(pos, len); + const long status = Parse(pos, len); - if (status < 0) //error - { - pFirst = NULL; - return status; - } + if (status < 0) { // error + pFirst = NULL; + return status; + } - if (m_entries_count <= 0) //empty cluster - { - pFirst = NULL; - return 0; - } + if (m_entries_count <= 0) { // empty cluster + pFirst = NULL; + return 0; } + } - assert(m_entries); + assert(m_entries); - pFirst = m_entries[0]; - assert(pFirst); + pFirst = m_entries[0]; + assert(pFirst); - return 0; //success + return 0; // success } -long Cluster::GetLast(const BlockEntry*& pLast) const -{ - for (;;) - { - long long pos; - long len; - - const long status = Parse(pos, len); - - if (status < 0) //error - { - pLast = NULL; - return status; - } +long Cluster::GetLast(const BlockEntry*& pLast) const { + for (;;) { + long long pos; + long len; - if (status > 0) //no new block - break; - } + const long status = Parse(pos, len); - if (m_entries_count <= 0) - { - pLast = NULL; - return 0; + if (status < 0) { // error + pLast = NULL; + return status; } - assert(m_entries); - - const long idx = m_entries_count - 1; - - pLast = m_entries[idx]; - assert(pLast); + if (status > 0) // no new block + break; + } + if (m_entries_count <= 0) { + pLast = NULL; return 0; -} + } + assert(m_entries); -long Cluster::GetNext( - const BlockEntry* pCurr, - const BlockEntry*& pNext) const -{ - assert(pCurr); - assert(m_entries); - assert(m_entries_count > 0); + const long idx = m_entries_count - 1; - size_t idx = pCurr->GetIndex(); - assert(idx < size_t(m_entries_count)); - assert(m_entries[idx] == pCurr); + pLast = m_entries[idx]; + assert(pLast); - ++idx; + return 0; +} - if (idx >= size_t(m_entries_count)) - { - long long pos; - long len; +long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const { + assert(pCurr); + assert(m_entries); + assert(m_entries_count > 0); - const long status = Parse(pos, len); + size_t idx = pCurr->GetIndex(); + assert(idx < size_t(m_entries_count)); + assert(m_entries[idx] == pCurr); - if (status < 0) //error - { - pNext = NULL; - return status; - } + ++idx; - if (status > 0) - { - pNext = NULL; - return 0; - } + if (idx >= size_t(m_entries_count)) { + long long pos; + long len; - assert(m_entries); - assert(m_entries_count > 0); - assert(idx < size_t(m_entries_count)); + const long status = Parse(pos, len); + + if (status < 0) { // error + pNext = NULL; + return status; } - pNext = m_entries[idx]; - assert(pNext); + if (status > 0) { + pNext = NULL; + return 0; + } - return 0; -} + assert(m_entries); + assert(m_entries_count > 0); + assert(idx < size_t(m_entries_count)); + } + pNext = m_entries[idx]; + assert(pNext); -long Cluster::GetEntryCount() const -{ - return m_entries_count; + return 0; } +long Cluster::GetEntryCount() const { return m_entries_count; } -const BlockEntry* Cluster::GetEntry( - const Track* pTrack, - long long time_ns) const -{ - assert(pTrack); +const BlockEntry* Cluster::GetEntry(const Track* pTrack, + long long time_ns) const { + assert(pTrack); - if (m_pSegment == NULL) //this is the special EOS cluster - return pTrack->GetEOS(); + if (m_pSegment == NULL) // this is the special EOS cluster + return pTrack->GetEOS(); #if 0 @@ -8483,76 +7586,66 @@ const BlockEntry* Cluster::GetEntry( #else - const BlockEntry* pResult = pTrack->GetEOS(); - - long index = 0; + const BlockEntry* pResult = pTrack->GetEOS(); - for (;;) - { - if (index >= m_entries_count) - { - long long pos; - long len; + long index = 0; - const long status = Parse(pos, len); - assert(status >= 0); + for (;;) { + if (index >= m_entries_count) { + long long pos; + long len; - if (status > 0) //completely parsed, and no more entries - return pResult; + const long status = Parse(pos, len); + assert(status >= 0); - if (status < 0) //should never happen - return 0; + if (status > 0) // completely parsed, and no more entries + return pResult; - assert(m_entries); - assert(index < m_entries_count); - } + if (status < 0) // should never happen + return 0; - const BlockEntry* const pEntry = m_entries[index]; - assert(pEntry); - assert(!pEntry->EOS()); + assert(m_entries); + assert(index < m_entries_count); + } - const Block* const pBlock = pEntry->GetBlock(); - assert(pBlock); + const BlockEntry* const pEntry = m_entries[index]; + assert(pEntry); + assert(!pEntry->EOS()); - if (pBlock->GetTrackNumber() != pTrack->GetNumber()) - { - ++index; - continue; - } + const Block* const pBlock = pEntry->GetBlock(); + assert(pBlock); - if (pTrack->VetEntry(pEntry)) - { - if (time_ns < 0) //just want first candidate block - return pEntry; + if (pBlock->GetTrackNumber() != pTrack->GetNumber()) { + ++index; + continue; + } - const long long ns = pBlock->GetTime(this); + if (pTrack->VetEntry(pEntry)) { + if (time_ns < 0) // just want first candidate block + return pEntry; - if (ns > time_ns) - return pResult; + const long long ns = pBlock->GetTime(this); - pResult = pEntry; //have a candidate - } - else if (time_ns >= 0) - { - const long long ns = pBlock->GetTime(this); + if (ns > time_ns) + return pResult; - if (ns > time_ns) - return pResult; - } + pResult = pEntry; // have a candidate + } else if (time_ns >= 0) { + const long long ns = pBlock->GetTime(this); - ++index; + if (ns > time_ns) + return pResult; } + ++index; + } + #endif } - -const BlockEntry* -Cluster::GetEntry( - const CuePoint& cp, - const CuePoint::TrackPosition& tp) const -{ - assert(m_pSegment); +const BlockEntry* Cluster::GetEntry(const CuePoint& cp, + const CuePoint::TrackPosition& tp) const { + assert(m_pSegment); #if 0 @@ -8643,114 +7736,105 @@ Cluster::GetEntry( #else - const long long tc = cp.GetTimeCode(); + const long long tc = cp.GetTimeCode(); - if (tp.m_block > 0) - { - const long block = static_cast(tp.m_block); - const long index = block - 1; + if (tp.m_block > 0) { + const long block = static_cast(tp.m_block); + const long index = block - 1; - while (index >= m_entries_count) - { - long long pos; - long len; + while (index >= m_entries_count) { + long long pos; + long len; - const long status = Parse(pos, len); + const long status = Parse(pos, len); - if (status < 0) //TODO: can this happen? - return NULL; + if (status < 0) // TODO: can this happen? + return NULL; - if (status > 0) //nothing remains to be parsed - return NULL; - } + if (status > 0) // nothing remains to be parsed + return NULL; + } - const BlockEntry* const pEntry = m_entries[index]; - assert(pEntry); - assert(!pEntry->EOS()); + const BlockEntry* const pEntry = m_entries[index]; + assert(pEntry); + assert(!pEntry->EOS()); - const Block* const pBlock = pEntry->GetBlock(); - assert(pBlock); + const Block* const pBlock = pEntry->GetBlock(); + assert(pBlock); - if ((pBlock->GetTrackNumber() == tp.m_track) && - (pBlock->GetTimeCode(this) == tc)) - { - return pEntry; - } + if ((pBlock->GetTrackNumber() == tp.m_track) && + (pBlock->GetTimeCode(this) == tc)) { + return pEntry; } + } - long index = 0; + long index = 0; - for (;;) - { - if (index >= m_entries_count) - { - long long pos; - long len; + for (;;) { + if (index >= m_entries_count) { + long long pos; + long len; - const long status = Parse(pos, len); + const long status = Parse(pos, len); - if (status < 0) //TODO: can this happen? - return NULL; + if (status < 0) // TODO: can this happen? + return NULL; - if (status > 0) //nothing remains to be parsed - return NULL; + if (status > 0) // nothing remains to be parsed + return NULL; - assert(m_entries); - assert(index < m_entries_count); - } + assert(m_entries); + assert(index < m_entries_count); + } - const BlockEntry* const pEntry = m_entries[index]; - assert(pEntry); - assert(!pEntry->EOS()); + const BlockEntry* const pEntry = m_entries[index]; + assert(pEntry); + assert(!pEntry->EOS()); - const Block* const pBlock = pEntry->GetBlock(); - assert(pBlock); + const Block* const pBlock = pEntry->GetBlock(); + assert(pBlock); - if (pBlock->GetTrackNumber() != tp.m_track) - { - ++index; - continue; - } + if (pBlock->GetTrackNumber() != tp.m_track) { + ++index; + continue; + } - const long long tc_ = pBlock->GetTimeCode(this); + const long long tc_ = pBlock->GetTimeCode(this); - if (tc_ < tc) - { - ++index; - continue; - } + if (tc_ < tc) { + ++index; + continue; + } - if (tc_ > tc) - return NULL; + if (tc_ > tc) + return NULL; - const Tracks* const pTracks = m_pSegment->GetTracks(); - assert(pTracks); + const Tracks* const pTracks = m_pSegment->GetTracks(); + assert(pTracks); - const long tn = static_cast(tp.m_track); - const Track* const pTrack = pTracks->GetTrackByNumber(tn); + const long tn = static_cast(tp.m_track); + const Track* const pTrack = pTracks->GetTrackByNumber(tn); - if (pTrack == NULL) - return NULL; + if (pTrack == NULL) + return NULL; - const long long type = pTrack->GetType(); + const long long type = pTrack->GetType(); - if (type == 2) //audio - return pEntry; + if (type == 2) // audio + return pEntry; - if (type != 1) //not video - return NULL; + if (type != 1) // not video + return NULL; - if (!pBlock->IsKey()) - return NULL; + if (!pBlock->IsKey()) + return NULL; - return pEntry; - } + return pEntry; + } #endif - } - #if 0 const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const { @@ -8787,96 +7871,46 @@ const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const } #endif +BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {} -BlockEntry::BlockEntry(Cluster* p, long idx) : - m_pCluster(p), - m_index(idx) -{ -} - - -BlockEntry::~BlockEntry() -{ -} - - -bool BlockEntry::EOS() const -{ - return (GetKind() == kBlockEOS); -} - - -const Cluster* BlockEntry::GetCluster() const -{ - return m_pCluster; -} - - -long BlockEntry::GetIndex() const -{ - return m_index; -} +BlockEntry::~BlockEntry() {} +bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); } -SimpleBlock::SimpleBlock( - Cluster* pCluster, - long idx, - long long start, - long long size) : - BlockEntry(pCluster, idx), - m_block(start, size) -{ -} - +const Cluster* BlockEntry::GetCluster() const { return m_pCluster; } -long SimpleBlock::Parse() -{ - return m_block.Parse(m_pCluster); -} +long BlockEntry::GetIndex() const { return m_index; } +SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start, + long long size) + : BlockEntry(pCluster, idx), m_block(start, size, 0) {} -BlockEntry::Kind SimpleBlock::GetKind() const -{ - return kBlockSimple; -} +long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); } +BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; } -const Block* SimpleBlock::GetBlock() const -{ - return &m_block; -} - - -BlockGroup::BlockGroup( - Cluster* pCluster, - long idx, - long long block_start, - long long block_size, - long long prev, - long long next, - long long duration) : - BlockEntry(pCluster, idx), - m_block(block_start, block_size), - m_prev(prev), - m_next(next), - m_duration(duration) -{ -} +const Block* SimpleBlock::GetBlock() const { return &m_block; } +BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start, + long long block_size, long long prev, long long next, + long long duration, long long discard_padding) + : BlockEntry(pCluster, idx), + m_block(block_start, block_size, discard_padding), + m_prev(prev), + m_next(next), + m_duration(duration) {} -long BlockGroup::Parse() -{ - const long status = m_block.Parse(m_pCluster); +long BlockGroup::Parse() { + const long status = m_block.Parse(m_pCluster); - if (status) - return status; + if (status) + return status; - m_block.SetKey((m_prev > 0) && (m_next <= 0)); + m_block.SetKey((m_prev > 0) && (m_next <= 0)); - return 0; + return 0; } - #if 0 void BlockGroup::ParseBlock(long long start, long long size) { @@ -8893,477 +7927,428 @@ void BlockGroup::ParseBlock(long long start, long long size) } #endif +BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; } -BlockEntry::Kind BlockGroup::GetKind() const -{ - return kBlockGroup; -} - - -const Block* BlockGroup::GetBlock() const -{ - return &m_block; -} - - -long long BlockGroup::GetPrevTimeCode() const -{ - return m_prev; -} - - -long long BlockGroup::GetNextTimeCode() const -{ - return m_next; -} - -long long BlockGroup::GetDurationTimeCode() const -{ - return m_duration; -} +const Block* BlockGroup::GetBlock() const { return &m_block; } -Block::Block(long long start, long long size_) : - m_start(start), - m_size(size_), - m_track(0), - m_timecode(-1), - m_flags(0), - m_frames(NULL), - m_frame_count(-1) -{ -} +long long BlockGroup::GetPrevTimeCode() const { return m_prev; } +long long BlockGroup::GetNextTimeCode() const { return m_next; } -Block::~Block() -{ - delete[] m_frames; -} +long long BlockGroup::GetDurationTimeCode() const { return m_duration; } +Block::Block(long long start, long long size_, long long discard_padding) + : m_start(start), + m_size(size_), + m_track(0), + m_timecode(-1), + m_flags(0), + m_frames(NULL), + m_frame_count(-1), + m_discard_padding(discard_padding) {} -long Block::Parse(const Cluster* pCluster) -{ - if (pCluster == NULL) - return -1; +Block::~Block() { delete[] m_frames; } - if (pCluster->m_pSegment == NULL) - return -1; +long Block::Parse(const Cluster* pCluster) { + if (pCluster == NULL) + return -1; - assert(m_start >= 0); - assert(m_size >= 0); - assert(m_track <= 0); - assert(m_frames == NULL); - assert(m_frame_count <= 0); + if (pCluster->m_pSegment == NULL) + return -1; - long long pos = m_start; - const long long stop = m_start + m_size; + assert(m_start >= 0); + assert(m_size >= 0); + assert(m_track <= 0); + assert(m_frames == NULL); + assert(m_frame_count <= 0); - long len; + long long pos = m_start; + const long long stop = m_start + m_size; - IMkvReader* const pReader = pCluster->m_pSegment->m_pReader; + long len; - m_track = ReadUInt(pReader, pos, len); + IMkvReader* const pReader = pCluster->m_pSegment->m_pReader; - if (m_track <= 0) - return E_FILE_FORMAT_INVALID; + m_track = ReadUInt(pReader, pos, len); - if ((pos + len) > stop) - return E_FILE_FORMAT_INVALID; + if (m_track <= 0) + return E_FILE_FORMAT_INVALID; - pos += len; //consume track number + if ((pos + len) > stop) + return E_FILE_FORMAT_INVALID; - if ((stop - pos) < 2) - return E_FILE_FORMAT_INVALID; + pos += len; // consume track number - long status; - long long value; + if ((stop - pos) < 2) + return E_FILE_FORMAT_INVALID; - status = UnserializeInt(pReader, pos, 2, value); + long status; + long long value; - if (status) - return E_FILE_FORMAT_INVALID; + status = UnserializeInt(pReader, pos, 2, value); - if (value < SHRT_MIN) - return E_FILE_FORMAT_INVALID; + if (status) + return E_FILE_FORMAT_INVALID; - if (value > SHRT_MAX) - return E_FILE_FORMAT_INVALID; + if (value < SHRT_MIN) + return E_FILE_FORMAT_INVALID; - m_timecode = static_cast(value); + if (value > SHRT_MAX) + return E_FILE_FORMAT_INVALID; - pos += 2; + m_timecode = static_cast(value); - if ((stop - pos) <= 0) - return E_FILE_FORMAT_INVALID; + pos += 2; - status = pReader->Read(pos, 1, &m_flags); + if ((stop - pos) <= 0) + return E_FILE_FORMAT_INVALID; - if (status) - return E_FILE_FORMAT_INVALID; + status = pReader->Read(pos, 1, &m_flags); - const int lacing = int(m_flags & 0x06) >> 1; + if (status) + return E_FILE_FORMAT_INVALID; - ++pos; //consume flags byte + const int lacing = int(m_flags & 0x06) >> 1; - if (lacing == 0) //no lacing - { - if (pos > stop) - return E_FILE_FORMAT_INVALID; + ++pos; // consume flags byte - m_frame_count = 1; - m_frames = new Frame[m_frame_count]; + if (lacing == 0) { // no lacing + if (pos > stop) + return E_FILE_FORMAT_INVALID; - Frame& f = m_frames[0]; - f.pos = pos; + m_frame_count = 1; + m_frames = new Frame[m_frame_count]; - const long long frame_size = stop - pos; + Frame& f = m_frames[0]; + f.pos = pos; - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + const long long frame_size = stop - pos; - f.len = static_cast(frame_size); + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - return 0; //success - } + f.len = static_cast(frame_size); - if (pos >= stop) - return E_FILE_FORMAT_INVALID; + return 0; // success + } - unsigned char biased_count; + if (pos >= stop) + return E_FILE_FORMAT_INVALID; - status = pReader->Read(pos, 1, &biased_count); + unsigned char biased_count; - if (status) - return E_FILE_FORMAT_INVALID; + status = pReader->Read(pos, 1, &biased_count); - ++pos; //consume frame count - assert(pos <= stop); + if (status) + return E_FILE_FORMAT_INVALID; - m_frame_count = int(biased_count) + 1; + ++pos; // consume frame count + assert(pos <= stop); - m_frames = new Frame[m_frame_count]; - assert(m_frames); + m_frame_count = int(biased_count) + 1; - if (lacing == 1) //Xiph - { - Frame* pf = m_frames; - Frame* const pf_end = pf + m_frame_count; + m_frames = new Frame[m_frame_count]; + assert(m_frames); - long size = 0; - int frame_count = m_frame_count; + if (lacing == 1) { // Xiph + Frame* pf = m_frames; + Frame* const pf_end = pf + m_frame_count; - while (frame_count > 1) - { - long frame_size = 0; + long size = 0; + int frame_count = m_frame_count; - for (;;) - { - unsigned char val; + while (frame_count > 1) { + long frame_size = 0; - if (pos >= stop) - return E_FILE_FORMAT_INVALID; + for (;;) { + unsigned char val; - status = pReader->Read(pos, 1, &val); + if (pos >= stop) + return E_FILE_FORMAT_INVALID; - if (status) - return E_FILE_FORMAT_INVALID; + status = pReader->Read(pos, 1, &val); - ++pos; //consume xiph size byte + if (status) + return E_FILE_FORMAT_INVALID; - frame_size += val; + ++pos; // consume xiph size byte - if (val < 255) - break; - } + frame_size += val; - Frame& f = *pf++; - assert(pf < pf_end); + if (val < 255) + break; + } - f.pos = 0; //patch later + Frame& f = *pf++; + assert(pf < pf_end); - f.len = frame_size; - size += frame_size; //contribution of this frame + f.pos = 0; // patch later - --frame_count; - } + f.len = frame_size; + size += frame_size; // contribution of this frame - assert(pf < pf_end); - assert(pos <= stop); + --frame_count; + } - { - Frame& f = *pf++; + assert(pf < pf_end); + assert(pos <= stop); - if (pf != pf_end) - return E_FILE_FORMAT_INVALID; + { + Frame& f = *pf++; - f.pos = 0; //patch later + if (pf != pf_end) + return E_FILE_FORMAT_INVALID; - const long long total_size = stop - pos; + f.pos = 0; // patch later - if (total_size < size) - return E_FILE_FORMAT_INVALID; + const long long total_size = stop - pos; - const long long frame_size = total_size - size; + if (total_size < size) + return E_FILE_FORMAT_INVALID; - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + const long long frame_size = total_size - size; - f.len = static_cast(frame_size); - } + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - pf = m_frames; - while (pf != pf_end) - { - Frame& f = *pf++; - assert((pos + f.len) <= stop); + f.len = static_cast(frame_size); + } - f.pos = pos; - pos += f.len; - } + pf = m_frames; + while (pf != pf_end) { + Frame& f = *pf++; + assert((pos + f.len) <= stop); - assert(pos == stop); + f.pos = pos; + pos += f.len; } - else if (lacing == 2) //fixed-size lacing - { - const long long total_size = stop - pos; - if ((total_size % m_frame_count) != 0) - return E_FILE_FORMAT_INVALID; + assert(pos == stop); + } else if (lacing == 2) { // fixed-size lacing + const long long total_size = stop - pos; - const long long frame_size = total_size / m_frame_count; + if ((total_size % m_frame_count) != 0) + return E_FILE_FORMAT_INVALID; - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + const long long frame_size = total_size / m_frame_count; - Frame* pf = m_frames; - Frame* const pf_end = pf + m_frame_count; + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - while (pf != pf_end) - { - assert((pos + frame_size) <= stop); + Frame* pf = m_frames; + Frame* const pf_end = pf + m_frame_count; - Frame& f = *pf++; + while (pf != pf_end) { + assert((pos + frame_size) <= stop); - f.pos = pos; - f.len = static_cast(frame_size); + Frame& f = *pf++; - pos += frame_size; - } + f.pos = pos; + f.len = static_cast(frame_size); - assert(pos == stop); + pos += frame_size; } - else - { - assert(lacing == 3); //EBML lacing - - if (pos >= stop) - return E_FILE_FORMAT_INVALID; - long size = 0; - int frame_count = m_frame_count; - - long long frame_size = ReadUInt(pReader, pos, len); + assert(pos == stop); + } else { + assert(lacing == 3); // EBML lacing - if (frame_size < 0) - return E_FILE_FORMAT_INVALID; + if (pos >= stop) + return E_FILE_FORMAT_INVALID; - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + long size = 0; + int frame_count = m_frame_count; - if ((pos + len) > stop) - return E_FILE_FORMAT_INVALID; + long long frame_size = ReadUInt(pReader, pos, len); - pos += len; //consume length of size of first frame + if (frame_size < 0) + return E_FILE_FORMAT_INVALID; - if ((pos + frame_size) > stop) - return E_FILE_FORMAT_INVALID; + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - Frame* pf = m_frames; - Frame* const pf_end = pf + m_frame_count; + if ((pos + len) > stop) + return E_FILE_FORMAT_INVALID; - { - Frame& curr = *pf; + pos += len; // consume length of size of first frame - curr.pos = 0; //patch later + if ((pos + frame_size) > stop) + return E_FILE_FORMAT_INVALID; - curr.len = static_cast(frame_size); - size += curr.len; //contribution of this frame - } + Frame* pf = m_frames; + Frame* const pf_end = pf + m_frame_count; - --frame_count; + { + Frame& curr = *pf; - while (frame_count > 1) - { - if (pos >= stop) - return E_FILE_FORMAT_INVALID; + curr.pos = 0; // patch later - assert(pf < pf_end); + curr.len = static_cast(frame_size); + size += curr.len; // contribution of this frame + } - const Frame& prev = *pf++; - assert(prev.len == frame_size); + --frame_count; - assert(pf < pf_end); + while (frame_count > 1) { + if (pos >= stop) + return E_FILE_FORMAT_INVALID; - Frame& curr = *pf; + assert(pf < pf_end); - curr.pos = 0; //patch later + const Frame& prev = *pf++; + assert(prev.len == frame_size); + if (prev.len != frame_size) + return E_FILE_FORMAT_INVALID; - const long long delta_size_ = ReadUInt(pReader, pos, len); + assert(pf < pf_end); - if (delta_size_ < 0) - return E_FILE_FORMAT_INVALID; + Frame& curr = *pf; - if ((pos + len) > stop) - return E_FILE_FORMAT_INVALID; + curr.pos = 0; // patch later - pos += len; //consume length of (delta) size - assert(pos <= stop); + const long long delta_size_ = ReadUInt(pReader, pos, len); - const int exp = 7*len - 1; - const long long bias = (1LL << exp) - 1LL; - const long long delta_size = delta_size_ - bias; + if (delta_size_ < 0) + return E_FILE_FORMAT_INVALID; - frame_size += delta_size; + if ((pos + len) > stop) + return E_FILE_FORMAT_INVALID; - if (frame_size < 0) - return E_FILE_FORMAT_INVALID; + pos += len; // consume length of (delta) size + assert(pos <= stop); - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + const int exp = 7 * len - 1; + const long long bias = (1LL << exp) - 1LL; + const long long delta_size = delta_size_ - bias; - curr.len = static_cast(frame_size); - size += curr.len; //contribution of this frame + frame_size += delta_size; - --frame_count; - } + if (frame_size < 0) + return E_FILE_FORMAT_INVALID; - { - assert(pos <= stop); - assert(pf < pf_end); + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - const Frame& prev = *pf++; - assert(prev.len == frame_size); + curr.len = static_cast(frame_size); + size += curr.len; // contribution of this frame - assert(pf < pf_end); + --frame_count; + } - Frame& curr = *pf++; - assert(pf == pf_end); + { + assert(pos <= stop); + assert(pf < pf_end); - curr.pos = 0; //patch later + const Frame& prev = *pf++; + assert(prev.len == frame_size); + if (prev.len != frame_size) + return E_FILE_FORMAT_INVALID; - const long long total_size = stop - pos; + assert(pf < pf_end); - if (total_size < size) - return E_FILE_FORMAT_INVALID; + Frame& curr = *pf++; + assert(pf == pf_end); - frame_size = total_size - size; + curr.pos = 0; // patch later - if (frame_size > LONG_MAX) - return E_FILE_FORMAT_INVALID; + const long long total_size = stop - pos; - curr.len = static_cast(frame_size); - } + if (total_size < size) + return E_FILE_FORMAT_INVALID; - pf = m_frames; - while (pf != pf_end) - { - Frame& f = *pf++; - assert((pos + f.len) <= stop); + frame_size = total_size - size; - f.pos = pos; - pos += f.len; - } + if (frame_size > LONG_MAX) + return E_FILE_FORMAT_INVALID; - assert(pos == stop); + curr.len = static_cast(frame_size); } - return 0; //success -} - + pf = m_frames; + while (pf != pf_end) { + Frame& f = *pf++; + assert((pos + f.len) <= stop); -long long Block::GetTimeCode(const Cluster* pCluster) const -{ - if (pCluster == 0) - return m_timecode; - - const long long tc0 = pCluster->GetTimeCode(); - assert(tc0 >= 0); + f.pos = pos; + pos += f.len; + } - const long long tc = tc0 + m_timecode; + assert(pos == stop); + } - return tc; //unscaled timecode units + return 0; // success } +long long Block::GetTimeCode(const Cluster* pCluster) const { + if (pCluster == 0) + return m_timecode; -long long Block::GetTime(const Cluster* pCluster) const -{ - assert(pCluster); + const long long tc0 = pCluster->GetTimeCode(); + assert(tc0 >= 0); - const long long tc = GetTimeCode(pCluster); - return tc; //tc is in milliseconds + const long long tc = tc0 + m_timecode; + + return tc; // unscaled timecode units } +long long Block::GetTime(const Cluster* pCluster) const { + assert(pCluster); -long long Block::GetTrackNumber() const -{ - return m_track; -} + const long long tc = GetTimeCode(pCluster); + const Segment* const pSegment = pCluster->m_pSegment; + const SegmentInfo* const pInfo = pSegment->GetInfo(); + assert(pInfo); -bool Block::IsKey() const -{ - return ((m_flags & static_cast(1 << 7)) != 0); -} + const long long scale = pInfo->GetTimeCodeScale(); + assert(scale >= 1); + const long long ns = tc * scale; -void Block::SetKey(bool bKey) -{ - if (bKey) - m_flags |= static_cast(1 << 7); - else - m_flags &= 0x7F; + return ns; } +long long Block::GetTrackNumber() const { return m_track; } -bool Block::IsInvisible() const -{ - return bool(int(m_flags & 0x08) != 0); +bool Block::IsKey() const { + return ((m_flags & static_cast(1 << 7)) != 0); } - -Block::Lacing Block::GetLacing() const -{ - const int value = int(m_flags & 0x06) >> 1; - return static_cast(value); +void Block::SetKey(bool bKey) { + if (bKey) + m_flags |= static_cast(1 << 7); + else + m_flags &= 0x7F; } +bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); } -int Block::GetFrameCount() const -{ - return m_frame_count; +Block::Lacing Block::GetLacing() const { + const int value = int(m_flags & 0x06) >> 1; + return static_cast(value); } +int Block::GetFrameCount() const { return m_frame_count; } -const Block::Frame& Block::GetFrame(int idx) const -{ - assert(idx >= 0); - assert(idx < m_frame_count); +const Block::Frame& Block::GetFrame(int idx) const { + assert(idx >= 0); + assert(idx < m_frame_count); - const Frame& f = m_frames[idx]; - assert(f.pos > 0); - assert(f.len > 0); + const Frame& f = m_frames[idx]; + assert(f.pos > 0); + assert(f.len > 0); - return f; + return f; } +long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const { + assert(pReader); + assert(buf); -long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const -{ - assert(pReader); - assert(buf); - - const long status = pReader->Read(pos, len, buf); - return status; + const long status = pReader->Read(pos, len, buf); + return status; } +long long Block::GetDiscardPadding() const { return m_discard_padding; } -} //end namespace mkvparser +} // end namespace mkvparser diff --git a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp index ab2552ec..3e17d07c 100644 --- a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp +++ b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvparser.hpp @@ -13,19 +13,18 @@ #include #include -namespace mkvparser -{ +namespace mkvparser { const int E_FILE_FORMAT_INVALID = -2; const int E_BUFFER_NOT_FULL = -3; -class IMkvReader -{ -public: - virtual int Read(long long pos, long len, unsigned char* buf) = 0; - virtual int Length(long long* total, long long* available) = 0; -protected: - virtual ~IMkvReader(); +class IMkvReader { + public: + virtual int Read(long long pos, long len, unsigned char* buf) = 0; + virtual int Length(long long* total, long long* available) = 0; + + protected: + virtual ~IMkvReader(); }; long long GetUIntLength(IMkvReader*, long long, long&); @@ -35,166 +34,148 @@ long long UnserializeUInt(IMkvReader*, long long pos, long long size); long UnserializeFloat(IMkvReader*, long long pos, long long size, double&); long UnserializeInt(IMkvReader*, long long pos, long len, long long& result); -long UnserializeString( - IMkvReader*, - long long pos, - long long size, - char*& str); +long UnserializeString(IMkvReader*, long long pos, long long size, char*& str); -long ParseElementHeader( - IMkvReader* pReader, - long long& pos, //consume id and size fields - long long stop, //if you know size of element's parent - long long& id, - long long& size); +long ParseElementHeader(IMkvReader* pReader, + long long& pos, // consume id and size fields + long long stop, // if you know size of element's parent + long long& id, long long& size); bool Match(IMkvReader*, long long&, unsigned long, long long&); bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&); void GetVersion(int& major, int& minor, int& build, int& revision); -struct EBMLHeader -{ - EBMLHeader(); - ~EBMLHeader(); - long long m_version; - long long m_readVersion; - long long m_maxIdLength; - long long m_maxSizeLength; - char* m_docType; - long long m_docTypeVersion; - long long m_docTypeReadVersion; - - long long Parse(IMkvReader*, long long&); - void Init(); +struct EBMLHeader { + EBMLHeader(); + ~EBMLHeader(); + long long m_version; + long long m_readVersion; + long long m_maxIdLength; + long long m_maxSizeLength; + char* m_docType; + long long m_docTypeVersion; + long long m_docTypeReadVersion; + + long long Parse(IMkvReader*, long long&); + void Init(); }; - class Segment; class Track; class Cluster; -class Block -{ - Block(const Block&); - Block& operator=(const Block&); - -public: - const long long m_start; - const long long m_size; +class Block { + Block(const Block&); + Block& operator=(const Block&); - Block(long long start, long long size); - ~Block(); + public: + const long long m_start; + const long long m_size; - long Parse(const Cluster*); + Block(long long start, long long size, long long discard_padding); + ~Block(); - long long GetTrackNumber() const; - long long GetTimeCode(const Cluster*) const; //absolute, but not scaled - long long GetTime(const Cluster*) const; //absolute, and scaled (ns) - bool IsKey() const; - void SetKey(bool); - bool IsInvisible() const; + long Parse(const Cluster*); - enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml }; - Lacing GetLacing() const; + long long GetTrackNumber() const; + long long GetTimeCode(const Cluster*) const; // absolute, but not scaled + long long GetTime(const Cluster*) const; // absolute, and scaled (ns) + bool IsKey() const; + void SetKey(bool); + bool IsInvisible() const; - int GetFrameCount() const; //to index frames: [0, count) + enum Lacing { kLacingNone, kLacingXiph, kLacingFixed, kLacingEbml }; + Lacing GetLacing() const; - struct Frame - { - long long pos; //absolute offset - long len; + int GetFrameCount() const; // to index frames: [0, count) - long Read(IMkvReader*, unsigned char*) const; - }; + struct Frame { + long long pos; // absolute offset + long len; - const Frame& GetFrame(int frame_index) const; + long Read(IMkvReader*, unsigned char*) const; + }; -private: - long long m_track; //Track::Number() - short m_timecode; //relative to cluster - unsigned char m_flags; + const Frame& GetFrame(int frame_index) const; - Frame* m_frames; - int m_frame_count; + long long GetDiscardPadding() const; -}; + private: + long long m_track; // Track::Number() + short m_timecode; // relative to cluster + unsigned char m_flags; + Frame* m_frames; + int m_frame_count; -class BlockEntry -{ - BlockEntry(const BlockEntry&); - BlockEntry& operator=(const BlockEntry&); + protected: + const long long m_discard_padding; +}; -protected: - BlockEntry(Cluster*, long index); +class BlockEntry { + BlockEntry(const BlockEntry&); + BlockEntry& operator=(const BlockEntry&); -public: - virtual ~BlockEntry(); + protected: + BlockEntry(Cluster*, long index); - bool EOS() const; - const Cluster* GetCluster() const; - long GetIndex() const; - virtual const Block* GetBlock() const = 0; + public: + virtual ~BlockEntry(); - enum Kind { kBlockEOS, kBlockSimple, kBlockGroup }; - virtual Kind GetKind() const = 0; + bool EOS() const; + const Cluster* GetCluster() const; + long GetIndex() const; + virtual const Block* GetBlock() const = 0; -protected: - Cluster* const m_pCluster; - const long m_index; + enum Kind { kBlockEOS, kBlockSimple, kBlockGroup }; + virtual Kind GetKind() const = 0; + protected: + Cluster* const m_pCluster; + const long m_index; }; +class SimpleBlock : public BlockEntry { + SimpleBlock(const SimpleBlock&); + SimpleBlock& operator=(const SimpleBlock&); -class SimpleBlock : public BlockEntry -{ - SimpleBlock(const SimpleBlock&); - SimpleBlock& operator=(const SimpleBlock&); - -public: - SimpleBlock(Cluster*, long index, long long start, long long size); - long Parse(); - - Kind GetKind() const; - const Block* GetBlock() const; + public: + SimpleBlock(Cluster*, long index, long long start, long long size); + long Parse(); -protected: - Block m_block; + Kind GetKind() const; + const Block* GetBlock() const; + protected: + Block m_block; }; +class BlockGroup : public BlockEntry { + BlockGroup(const BlockGroup&); + BlockGroup& operator=(const BlockGroup&); -class BlockGroup : public BlockEntry -{ - BlockGroup(const BlockGroup&); - BlockGroup& operator=(const BlockGroup&); - -public: - BlockGroup( - Cluster*, - long index, - long long block_start, //absolute pos of block's payload - long long block_size, //size of block's payload - long long prev, - long long next, - long long duration); - - long Parse(); + public: + BlockGroup(Cluster*, long index, + long long block_start, // absolute pos of block's payload + long long block_size, // size of block's payload + long long prev, long long next, long long duration, + long long discard_padding); - Kind GetKind() const; - const Block* GetBlock() const; + long Parse(); - long long GetPrevTimeCode() const; //relative to block's time - long long GetNextTimeCode() const; //as above - long long GetDurationTimeCode() const; + Kind GetKind() const; + const Block* GetBlock() const; -private: - Block m_block; - const long long m_prev; - const long long m_next; - const long long m_duration; + long long GetPrevTimeCode() const; // relative to block's time + long long GetNextTimeCode() const; // as above + long long GetDurationTimeCode() const; + private: + Block m_block; + const long long m_prev; + const long long m_next; + const long long m_duration; }; /////////////////////////////////////////////////////////////// @@ -202,606 +183,552 @@ private: // Elements used to describe if the track data has been encrypted or // compressed with zlib or header stripping. class ContentEncoding { -public: - enum { - kCTR = 1 - }; - - ContentEncoding(); - ~ContentEncoding(); - - // ContentCompression element names - struct ContentCompression { - ContentCompression(); - ~ContentCompression(); - - unsigned long long algo; - unsigned char* settings; - }; - - // ContentEncAESSettings element names - struct ContentEncAESSettings { - ContentEncAESSettings() : cipher_mode(kCTR) {} - ~ContentEncAESSettings() {} - - unsigned long long cipher_mode; - }; - - // ContentEncryption element names - struct ContentEncryption { - ContentEncryption(); - ~ContentEncryption(); - - unsigned long long algo; - unsigned char* key_id; - long long key_id_len; - unsigned char* signature; - long long signature_len; - unsigned char* sig_key_id; - long long sig_key_id_len; - unsigned long long sig_algo; - unsigned long long sig_hash_algo; - - ContentEncAESSettings aes_settings; - }; - - // Returns ContentCompression represented by |idx|. Returns NULL if |idx| - // is out of bounds. - const ContentCompression* GetCompressionByIndex(unsigned long idx) const; - - // Returns number of ContentCompression elements in this ContentEncoding - // element. - unsigned long GetCompressionCount() const; - - // Returns ContentEncryption represented by |idx|. Returns NULL if |idx| - // is out of bounds. - const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const; - - // Returns number of ContentEncryption elements in this ContentEncoding - // element. - unsigned long GetEncryptionCount() const; - - // Parses the ContentEncAESSettings element from |pReader|. |start| is the - // starting offset of the ContentEncAESSettings payload. |size| is the - // size in bytes of the ContentEncAESSettings payload. |encryption| is - // where the parsed values will be stored. - long ParseContentEncAESSettingsEntry(long long start, - long long size, - IMkvReader* pReader, - ContentEncAESSettings* aes); - - // Parses the ContentEncoding element from |pReader|. |start| is the - // starting offset of the ContentEncoding payload. |size| is the size in - // bytes of the ContentEncoding payload. Returns true on success. - long ParseContentEncodingEntry(long long start, - long long size, - IMkvReader* pReader); - - // Parses the ContentEncryption element from |pReader|. |start| is the - // starting offset of the ContentEncryption payload. |size| is the size in - // bytes of the ContentEncryption payload. |encryption| is where the parsed - // values will be stored. - long ParseEncryptionEntry(long long start, - long long size, - IMkvReader* pReader, - ContentEncryption* encryption); - - unsigned long long encoding_order() const { return encoding_order_; } - unsigned long long encoding_scope() const { return encoding_scope_; } - unsigned long long encoding_type() const { return encoding_type_; } - -private: - // Member variables for list of ContentCompression elements. - ContentCompression** compression_entries_; - ContentCompression** compression_entries_end_; - - // Member variables for list of ContentEncryption elements. - ContentEncryption** encryption_entries_; - ContentEncryption** encryption_entries_end_; - - // ContentEncoding element names - unsigned long long encoding_order_; - unsigned long long encoding_scope_; - unsigned long long encoding_type_; - - // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding); - ContentEncoding(const ContentEncoding&); - ContentEncoding& operator=(const ContentEncoding&); + public: + enum { kCTR = 1 }; + + ContentEncoding(); + ~ContentEncoding(); + + // ContentCompression element names + struct ContentCompression { + ContentCompression(); + ~ContentCompression(); + + unsigned long long algo; + unsigned char* settings; + long long settings_len; + }; + + // ContentEncAESSettings element names + struct ContentEncAESSettings { + ContentEncAESSettings() : cipher_mode(kCTR) {} + ~ContentEncAESSettings() {} + + unsigned long long cipher_mode; + }; + + // ContentEncryption element names + struct ContentEncryption { + ContentEncryption(); + ~ContentEncryption(); + + unsigned long long algo; + unsigned char* key_id; + long long key_id_len; + unsigned char* signature; + long long signature_len; + unsigned char* sig_key_id; + long long sig_key_id_len; + unsigned long long sig_algo; + unsigned long long sig_hash_algo; + + ContentEncAESSettings aes_settings; + }; + + // Returns ContentCompression represented by |idx|. Returns NULL if |idx| + // is out of bounds. + const ContentCompression* GetCompressionByIndex(unsigned long idx) const; + + // Returns number of ContentCompression elements in this ContentEncoding + // element. + unsigned long GetCompressionCount() const; + + // Parses the ContentCompression element from |pReader|. |start| is the + // starting offset of the ContentCompression payload. |size| is the size in + // bytes of the ContentCompression payload. |compression| is where the parsed + // values will be stored. + long ParseCompressionEntry(long long start, long long size, + IMkvReader* pReader, + ContentCompression* compression); + + // Returns ContentEncryption represented by |idx|. Returns NULL if |idx| + // is out of bounds. + const ContentEncryption* GetEncryptionByIndex(unsigned long idx) const; + + // Returns number of ContentEncryption elements in this ContentEncoding + // element. + unsigned long GetEncryptionCount() const; + + // Parses the ContentEncAESSettings element from |pReader|. |start| is the + // starting offset of the ContentEncAESSettings payload. |size| is the + // size in bytes of the ContentEncAESSettings payload. |encryption| is + // where the parsed values will be stored. + long ParseContentEncAESSettingsEntry(long long start, long long size, + IMkvReader* pReader, + ContentEncAESSettings* aes); + + // Parses the ContentEncoding element from |pReader|. |start| is the + // starting offset of the ContentEncoding payload. |size| is the size in + // bytes of the ContentEncoding payload. Returns true on success. + long ParseContentEncodingEntry(long long start, long long size, + IMkvReader* pReader); + + // Parses the ContentEncryption element from |pReader|. |start| is the + // starting offset of the ContentEncryption payload. |size| is the size in + // bytes of the ContentEncryption payload. |encryption| is where the parsed + // values will be stored. + long ParseEncryptionEntry(long long start, long long size, + IMkvReader* pReader, ContentEncryption* encryption); + + unsigned long long encoding_order() const { return encoding_order_; } + unsigned long long encoding_scope() const { return encoding_scope_; } + unsigned long long encoding_type() const { return encoding_type_; } + + private: + // Member variables for list of ContentCompression elements. + ContentCompression** compression_entries_; + ContentCompression** compression_entries_end_; + + // Member variables for list of ContentEncryption elements. + ContentEncryption** encryption_entries_; + ContentEncryption** encryption_entries_end_; + + // ContentEncoding element names + unsigned long long encoding_order_; + unsigned long long encoding_scope_; + unsigned long long encoding_type_; + + // LIBWEBM_DISALLOW_COPY_AND_ASSIGN(ContentEncoding); + ContentEncoding(const ContentEncoding&); + ContentEncoding& operator=(const ContentEncoding&); }; -class Track -{ - Track(const Track&); - Track& operator=(const Track&); - -public: - class Info; - static long Create( - Segment*, - const Info&, - long long element_start, - long long element_size, - Track*&); - - enum Type { kVideo = 1, kAudio = 2 }; - - Segment* const m_pSegment; - const long long m_element_start; - const long long m_element_size; - virtual ~Track(); - - long GetType() const; - long GetNumber() const; - unsigned long long GetUid() const; - const char* GetNameAsUTF8() const; - const char* GetCodecNameAsUTF8() const; - const char* GetCodecId() const; - const unsigned char* GetCodecPrivate(size_t&) const; - bool GetLacing() const; - - const BlockEntry* GetEOS() const; - - struct Settings - { - long long start; - long long size; - }; - - class Info - { - public: - Info(); - ~Info(); - int Copy(Info&) const; - void Clear(); - private: - Info(const Info&); - Info& operator=(const Info&); - public: - long type; - long number; - unsigned long long uid; - char* nameAsUTF8; - char* codecId; - char* codecNameAsUTF8; - unsigned char* codecPrivate; - size_t codecPrivateSize; - bool lacing; - Settings settings; - private: - int CopyStr(char* Info::*str, Info&) const; - }; - - long GetFirst(const BlockEntry*&) const; - long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; - virtual bool VetEntry(const BlockEntry*) const; - virtual long Seek(long long time_ns, const BlockEntry*&) const; - - const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const; - unsigned long GetContentEncodingCount() const; - - long ParseContentEncodingsEntry(long long start, long long size); - -protected: - Track( - Segment*, - long long element_start, - long long element_size); - - Info m_info; - - class EOSBlock : public BlockEntry - { - public: - EOSBlock(); - - Kind GetKind() const; - const Block* GetBlock() const; - }; - - EOSBlock m_eos; - -private: - ContentEncoding** content_encoding_entries_; - ContentEncoding** content_encoding_entries_end_; +class Track { + Track(const Track&); + Track& operator=(const Track&); + + public: + class Info; + static long Create(Segment*, const Info&, long long element_start, + long long element_size, Track*&); + + enum Type { kVideo = 1, kAudio = 2, kSubtitle = 0x11, kMetadata = 0x21 }; + + Segment* const m_pSegment; + const long long m_element_start; + const long long m_element_size; + virtual ~Track(); + + long GetType() const; + long GetNumber() const; + unsigned long long GetUid() const; + const char* GetNameAsUTF8() const; + const char* GetLanguage() const; + const char* GetCodecNameAsUTF8() const; + const char* GetCodecId() const; + const unsigned char* GetCodecPrivate(size_t&) const; + bool GetLacing() const; + unsigned long long GetDefaultDuration() const; + unsigned long long GetCodecDelay() const; + unsigned long long GetSeekPreRoll() const; + + const BlockEntry* GetEOS() const; + + struct Settings { + long long start; + long long size; + }; + + class Info { + public: + Info(); + ~Info(); + int Copy(Info&) const; + void Clear(); + long type; + long number; + unsigned long long uid; + unsigned long long defaultDuration; + unsigned long long codecDelay; + unsigned long long seekPreRoll; + char* nameAsUTF8; + char* language; + char* codecId; + char* codecNameAsUTF8; + unsigned char* codecPrivate; + size_t codecPrivateSize; + bool lacing; + Settings settings; + + private: + Info(const Info&); + Info& operator=(const Info&); + int CopyStr(char* Info::*str, Info&) const; + }; + + long GetFirst(const BlockEntry*&) const; + long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; + virtual bool VetEntry(const BlockEntry*) const; + virtual long Seek(long long time_ns, const BlockEntry*&) const; + + const ContentEncoding* GetContentEncodingByIndex(unsigned long idx) const; + unsigned long GetContentEncodingCount() const; + + long ParseContentEncodingsEntry(long long start, long long size); + + protected: + Track(Segment*, long long element_start, long long element_size); + + Info m_info; + + class EOSBlock : public BlockEntry { + public: + EOSBlock(); + + Kind GetKind() const; + const Block* GetBlock() const; + }; + + EOSBlock m_eos; + + private: + ContentEncoding** content_encoding_entries_; + ContentEncoding** content_encoding_entries_end_; }; +class VideoTrack : public Track { + VideoTrack(const VideoTrack&); + VideoTrack& operator=(const VideoTrack&); + + VideoTrack(Segment*, long long element_start, long long element_size); -class VideoTrack : public Track -{ - VideoTrack(const VideoTrack&); - VideoTrack& operator=(const VideoTrack&); + public: + static long Parse(Segment*, const Info&, long long element_start, + long long element_size, VideoTrack*&); - VideoTrack( - Segment*, - long long element_start, - long long element_size); + long long GetWidth() const; + long long GetHeight() const; + double GetFrameRate() const; -public: - static long Parse( - Segment*, - const Info&, - long long element_start, - long long element_size, - VideoTrack*&); + bool VetEntry(const BlockEntry*) const; + long Seek(long long time_ns, const BlockEntry*&) const; - long long GetWidth() const; - long long GetHeight() const; - double GetFrameRate() const; + private: + long long m_width; + long long m_height; + double m_rate; +}; + +class AudioTrack : public Track { + AudioTrack(const AudioTrack&); + AudioTrack& operator=(const AudioTrack&); - bool VetEntry(const BlockEntry*) const; - long Seek(long long time_ns, const BlockEntry*&) const; + AudioTrack(Segment*, long long element_start, long long element_size); -private: - long long m_width; - long long m_height; - double m_rate; + public: + static long Parse(Segment*, const Info&, long long element_start, + long long element_size, AudioTrack*&); + double GetSamplingRate() const; + long long GetChannels() const; + long long GetBitDepth() const; + + private: + double m_rate; + long long m_channels; + long long m_bitDepth; }; +class Tracks { + Tracks(const Tracks&); + Tracks& operator=(const Tracks&); + + public: + Segment* const m_pSegment; + const long long m_start; + const long long m_size; + const long long m_element_start; + const long long m_element_size; -class AudioTrack : public Track -{ - AudioTrack(const AudioTrack&); - AudioTrack& operator=(const AudioTrack&); - - AudioTrack( - Segment*, - long long element_start, - long long element_size); -public: - static long Parse( - Segment*, - const Info&, - long long element_start, - long long element_size, - AudioTrack*&); - - double GetSamplingRate() const; - long long GetChannels() const; - long long GetBitDepth() const; - long Seek(long long time_ns, const BlockEntry*&) const; - -private: - double m_rate; - long long m_channels; - long long m_bitDepth; + Tracks(Segment*, long long start, long long size, long long element_start, + long long element_size); + + ~Tracks(); + + long Parse(); + + unsigned long GetTracksCount() const; + + const Track* GetTrackByNumber(long tn) const; + const Track* GetTrackByIndex(unsigned long idx) const; + + private: + Track** m_trackEntries; + Track** m_trackEntriesEnd; + + long ParseTrackEntry(long long payload_start, long long payload_size, + long long element_start, long long element_size, + Track*&) const; }; +class Chapters { + Chapters(const Chapters&); + Chapters& operator=(const Chapters&); -class Tracks -{ - Tracks(const Tracks&); - Tracks& operator=(const Tracks&); + public: + Segment* const m_pSegment; + const long long m_start; + const long long m_size; + const long long m_element_start; + const long long m_element_size; -public: - Segment* const m_pSegment; - const long long m_start; - const long long m_size; - const long long m_element_start; - const long long m_element_size; + Chapters(Segment*, long long payload_start, long long payload_size, + long long element_start, long long element_size); - Tracks( - Segment*, - long long start, - long long size, - long long element_start, - long long element_size); + ~Chapters(); - ~Tracks(); + long Parse(); - long Parse(); + class Atom; + class Edition; - unsigned long GetTracksCount() const; + class Display { + friend class Atom; + Display(); + Display(const Display&); + ~Display(); + Display& operator=(const Display&); - const Track* GetTrackByNumber(long tn) const; - const Track* GetTrackByIndex(unsigned long idx) const; + public: + const char* GetString() const; + const char* GetLanguage() const; + const char* GetCountry() const; -private: - Track** m_trackEntries; - Track** m_trackEntriesEnd; + private: + void Init(); + void ShallowCopy(Display&) const; + void Clear(); + long Parse(IMkvReader*, long long pos, long long size); - long ParseTrackEntry( - long long payload_start, - long long payload_size, - long long element_start, - long long element_size, - Track*&) const; + char* m_string; + char* m_language; + char* m_country; + }; -}; + class Atom { + friend class Edition; + Atom(); + Atom(const Atom&); + ~Atom(); + Atom& operator=(const Atom&); + public: + unsigned long long GetUID() const; + const char* GetStringUID() const; -class Chapters -{ - Chapters(const Chapters&); - Chapters& operator=(const Chapters&); - -public: - Segment* const m_pSegment; - const long long m_start; - const long long m_size; - const long long m_element_start; - const long long m_element_size; - - Chapters( - Segment*, - long long payload_start, - long long payload_size, - long long element_start, - long long element_size); - - ~Chapters(); - - long Parse(); - - class Atom; - class Edition; - - class Display - { - friend class Atom; - Display(); - Display(const Display&); - ~Display(); - Display& operator=(const Display&); - public: - const char* GetString() const; - const char* GetLanguage() const; - const char* GetCountry() const; - private: - void Init(); - void ShallowCopy(Display&) const; - void Clear(); - long Parse(IMkvReader*, long long pos, long long size); - - char* m_string; - char* m_language; - char* m_country; - }; - - class Atom - { - friend class Edition; - Atom(); - Atom(const Atom&); - ~Atom(); - Atom& operator=(const Atom&); - public: - long long GetStartTimecode() const; - long long GetStopTimecode() const; - int GetDisplayCount() const; - const Display* GetDisplay(int index) const; - private: - void Init(); - void ShallowCopy(Atom&) const; - void Clear(); - long Parse(IMkvReader*, long long pos, long long size); - - long ParseDisplay(IMkvReader*, long long pos, long long size); - bool ExpandDisplaysArray(); - - unsigned long long m_uid; - // TODO(matthewjheaney): Cue Identifier (string) - long long m_start_timecode; - long long m_stop_timecode; - - Display* m_displays; - int m_displays_size; - int m_displays_count; - }; - - class Edition - { - friend class Chapters; - Edition(); - Edition(const Edition&); - ~Edition(); - Edition& operator=(const Edition&); - public: - int GetAtomCount() const; - const Atom* GetAtom(int index) const; - private: - void Init(); - void ShallowCopy(Edition&) const; - void Clear(); - long Parse(IMkvReader*, long long pos, long long size); - - long ParseAtom(IMkvReader*, long long pos, long long size); - bool ExpandAtomsArray(); - - Atom* m_atoms; - int m_atoms_size; - int m_atoms_count; - }; - - int GetEditionCount() const; - const Edition* GetEdition(int index) const; - -private: - long ParseEdition(long long pos, long long size); - bool ExpandEditionsArray(); - - Edition* m_editions; - int m_editions_size; - int m_editions_count; + long long GetStartTimecode() const; + long long GetStopTimecode() const; -}; + long long GetStartTime(const Chapters*) const; + long long GetStopTime(const Chapters*) const; + + int GetDisplayCount() const; + const Display* GetDisplay(int index) const; + + private: + void Init(); + void ShallowCopy(Atom&) const; + void Clear(); + long Parse(IMkvReader*, long long pos, long long size); + static long long GetTime(const Chapters*, long long timecode); + + long ParseDisplay(IMkvReader*, long long pos, long long size); + bool ExpandDisplaysArray(); + + char* m_string_uid; + unsigned long long m_uid; + long long m_start_timecode; + long long m_stop_timecode; + + Display* m_displays; + int m_displays_size; + int m_displays_count; + }; + + class Edition { + friend class Chapters; + Edition(); + Edition(const Edition&); + ~Edition(); + Edition& operator=(const Edition&); + + public: + int GetAtomCount() const; + const Atom* GetAtom(int index) const; + + private: + void Init(); + void ShallowCopy(Edition&) const; + void Clear(); + long Parse(IMkvReader*, long long pos, long long size); + + long ParseAtom(IMkvReader*, long long pos, long long size); + bool ExpandAtomsArray(); + + Atom* m_atoms; + int m_atoms_size; + int m_atoms_count; + }; + + int GetEditionCount() const; + const Edition* GetEdition(int index) const; + private: + long ParseEdition(long long pos, long long size); + bool ExpandEditionsArray(); -class SegmentInfo -{ - SegmentInfo(const SegmentInfo&); - SegmentInfo& operator=(const SegmentInfo&); - -public: - Segment* const m_pSegment; - const long long m_start; - const long long m_size; - const long long m_element_start; - const long long m_element_size; - - SegmentInfo( - Segment*, - long long start, - long long size, - long long element_start, - long long element_size); - - ~SegmentInfo(); - - long Parse(); - - long long GetTimeCodeScale() const; - long long GetDuration() const; //scaled - const char* GetMuxingAppAsUTF8() const; - const char* GetWritingAppAsUTF8() const; - const char* GetTitleAsUTF8() const; - -private: - long long m_timecodeScale; - double m_duration; - char* m_pMuxingAppAsUTF8; - char* m_pWritingAppAsUTF8; - char* m_pTitleAsUTF8; + Edition* m_editions; + int m_editions_size; + int m_editions_count; }; +class SegmentInfo { + SegmentInfo(const SegmentInfo&); + SegmentInfo& operator=(const SegmentInfo&); -class SeekHead -{ - SeekHead(const SeekHead&); - SeekHead& operator=(const SeekHead&); + public: + Segment* const m_pSegment; + const long long m_start; + const long long m_size; + const long long m_element_start; + const long long m_element_size; -public: - Segment* const m_pSegment; - const long long m_start; - const long long m_size; - const long long m_element_start; - const long long m_element_size; + SegmentInfo(Segment*, long long start, long long size, + long long element_start, long long element_size); - SeekHead( - Segment*, - long long start, - long long size, - long long element_start, - long long element_size); + ~SegmentInfo(); - ~SeekHead(); + long Parse(); - long Parse(); + long long GetTimeCodeScale() const; + long long GetDuration() const; // scaled + const char* GetMuxingAppAsUTF8() const; + const char* GetWritingAppAsUTF8() const; + const char* GetTitleAsUTF8() const; - struct Entry - { - //the SeekHead entry payload - long long id; - long long pos; + private: + long long m_timecodeScale; + double m_duration; + char* m_pMuxingAppAsUTF8; + char* m_pWritingAppAsUTF8; + char* m_pTitleAsUTF8; +}; + +class SeekHead { + SeekHead(const SeekHead&); + SeekHead& operator=(const SeekHead&); + + public: + Segment* const m_pSegment; + const long long m_start; + const long long m_size; + const long long m_element_start; + const long long m_element_size; + + SeekHead(Segment*, long long start, long long size, long long element_start, + long long element_size); - //absolute pos of SeekEntry ID - long long element_start; + ~SeekHead(); - //SeekEntry ID size + size size + payload - long long element_size; - }; + long Parse(); - int GetCount() const; - const Entry* GetEntry(int idx) const; + struct Entry { + // the SeekHead entry payload + long long id; + long long pos; + + // absolute pos of SeekEntry ID + long long element_start; - struct VoidElement - { - //absolute pos of Void ID - long long element_start; + // SeekEntry ID size + size size + payload + long long element_size; + }; - //ID size + size size + payload size - long long element_size; - }; + int GetCount() const; + const Entry* GetEntry(int idx) const; - int GetVoidElementCount() const; - const VoidElement* GetVoidElement(int idx) const; + struct VoidElement { + // absolute pos of Void ID + long long element_start; -private: - Entry* m_entries; - int m_entry_count; + // ID size + size size + payload size + long long element_size; + }; - VoidElement* m_void_elements; - int m_void_element_count; + int GetVoidElementCount() const; + const VoidElement* GetVoidElement(int idx) const; - static bool ParseEntry( - IMkvReader*, - long long pos, //payload - long long size, - Entry*); + private: + Entry* m_entries; + int m_entry_count; + VoidElement* m_void_elements; + int m_void_element_count; + + static bool ParseEntry(IMkvReader*, + long long pos, // payload + long long size, Entry*); }; class Cues; -class CuePoint -{ - friend class Cues; - - CuePoint(long, long long); - ~CuePoint(); +class CuePoint { + friend class Cues; - CuePoint(const CuePoint&); - CuePoint& operator=(const CuePoint&); + CuePoint(long, long long); + ~CuePoint(); -public: - long long m_element_start; - long long m_element_size; + CuePoint(const CuePoint&); + CuePoint& operator=(const CuePoint&); - void Load(IMkvReader*); + public: + long long m_element_start; + long long m_element_size; - long long GetTimeCode() const; //absolute but unscaled - long long GetTime(const Segment*) const; //absolute and scaled (ns units) + void Load(IMkvReader*); - struct TrackPosition - { - long long m_track; - long long m_pos; //of cluster - long long m_block; - //codec_state //defaults to 0 - //reference = clusters containing req'd referenced blocks - // reftime = timecode of the referenced block + long long GetTimeCode() const; // absolute but unscaled + long long GetTime(const Segment*) const; // absolute and scaled (ns units) - void Parse(IMkvReader*, long long, long long); - }; + struct TrackPosition { + long long m_track; + long long m_pos; // of cluster + long long m_block; + // codec_state //defaults to 0 + // reference = clusters containing req'd referenced blocks + // reftime = timecode of the referenced block - const TrackPosition* Find(const Track*) const; + void Parse(IMkvReader*, long long, long long); + }; -private: - const long m_index; - long long m_timecode; - TrackPosition* m_track_positions; - size_t m_track_positions_count; + const TrackPosition* Find(const Track*) const; + private: + const long m_index; + long long m_timecode; + TrackPosition* m_track_positions; + size_t m_track_positions_count; }; +class Cues { + friend class Segment; -class Cues -{ - friend class Segment; + Cues(Segment*, long long start, long long size, long long element_start, + long long element_size); + ~Cues(); - Cues( - Segment*, - long long start, - long long size, - long long element_start, - long long element_size); - ~Cues(); + Cues(const Cues&); + Cues& operator=(const Cues&); - Cues(const Cues&); - Cues& operator=(const Cues&); + public: + Segment* const m_pSegment; + const long long m_start; + const long long m_size; + const long long m_element_start; + const long long m_element_size; -public: - Segment* const m_pSegment; - const long long m_start; - const long long m_size; - const long long m_element_start; - const long long m_element_size; - - bool Find( //lower bound of time_ns - long long time_ns, - const Track*, - const CuePoint*&, - const CuePoint::TrackPosition*&) const; + bool Find( // lower bound of time_ns + long long time_ns, const Track*, const CuePoint*&, + const CuePoint::TrackPosition*&) const; #if 0 bool FindNext( //upper_bound of time_ns @@ -811,163 +738,144 @@ public: const CuePoint::TrackPosition*&) const; #endif - const CuePoint* GetFirst() const; - const CuePoint* GetLast() const; - const CuePoint* GetNext(const CuePoint*) const; - - const BlockEntry* GetBlock( - const CuePoint*, - const CuePoint::TrackPosition*) const; + const CuePoint* GetFirst() const; + const CuePoint* GetLast() const; + const CuePoint* GetNext(const CuePoint*) const; - bool LoadCuePoint() const; - long GetCount() const; //loaded only - //long GetTotal() const; //loaded + preloaded - bool DoneParsing() const; + const BlockEntry* GetBlock(const CuePoint*, + const CuePoint::TrackPosition*) const; -private: - void Init() const; - void PreloadCuePoint(long&, long long) const; + bool LoadCuePoint() const; + long GetCount() const; // loaded only + // long GetTotal() const; //loaded + preloaded + bool DoneParsing() const; - mutable CuePoint** m_cue_points; - mutable long m_count; - mutable long m_preload_count; - mutable long long m_pos; + private: + void Init() const; + void PreloadCuePoint(long&, long long) const; + mutable CuePoint** m_cue_points; + mutable long m_count; + mutable long m_preload_count; + mutable long long m_pos; }; +class Cluster { + friend class Segment; -class Cluster -{ - friend class Segment; + Cluster(const Cluster&); + Cluster& operator=(const Cluster&); - Cluster(const Cluster&); - Cluster& operator=(const Cluster&); + public: + Segment* const m_pSegment; -public: - Segment* const m_pSegment; + public: + static Cluster* Create(Segment*, + long index, // index in segment + long long off); // offset relative to segment + // long long element_size); -public: - static Cluster* Create( - Segment*, - long index, //index in segment - long long off); //offset relative to segment - //long long element_size); + Cluster(); // EndOfStream + ~Cluster(); - Cluster(); //EndOfStream - ~Cluster(); + bool EOS() const; - bool EOS() const; + long long GetTimeCode() const; // absolute, but not scaled + long long GetTime() const; // absolute, and scaled (nanosecond units) + long long GetFirstTime() const; // time (ns) of first (earliest) block + long long GetLastTime() const; // time (ns) of last (latest) block - long long GetTimeCode() const; //absolute, but not scaled - long long GetTime() const; //absolute, and scaled (nanosecond units) - long long GetFirstTime() const; //time (ns) of first (earliest) block - long long GetLastTime() const; //time (ns) of last (latest) block + long GetFirst(const BlockEntry*&) const; + long GetLast(const BlockEntry*&) const; + long GetNext(const BlockEntry* curr, const BlockEntry*& next) const; - long GetFirst(const BlockEntry*&) const; - long GetLast(const BlockEntry*&) const; - long GetNext(const BlockEntry* curr, const BlockEntry*& next) const; + const BlockEntry* GetEntry(const Track*, long long ns = -1) const; + const BlockEntry* GetEntry(const CuePoint&, + const CuePoint::TrackPosition&) const; + // const BlockEntry* GetMaxKey(const VideoTrack*) const; - const BlockEntry* GetEntry(const Track*, long long ns = -1) const; - const BlockEntry* GetEntry( - const CuePoint&, - const CuePoint::TrackPosition&) const; - //const BlockEntry* GetMaxKey(const VideoTrack*) const; + // static bool HasBlockEntries(const Segment*, long long); -// static bool HasBlockEntries(const Segment*, long long); + static long HasBlockEntries(const Segment*, long long idoff, long long& pos, + long& size); - static long HasBlockEntries( - const Segment*, - long long idoff, - long long& pos, - long& size); + long GetEntryCount() const; - long GetEntryCount() const; + long Load(long long& pos, long& size) const; - long Load(long long& pos, long& size) const; + long Parse(long long& pos, long& size) const; + long GetEntry(long index, const mkvparser::BlockEntry*&) const; - long Parse(long long& pos, long& size) const; - long GetEntry(long index, const mkvparser::BlockEntry*&) const; + protected: + Cluster(Segment*, long index, long long element_start); + // long long element_size); -protected: - Cluster( - Segment*, - long index, - long long element_start); - //long long element_size); + public: + const long long m_element_start; + long long GetPosition() const; // offset relative to segment -public: - const long long m_element_start; - long long GetPosition() const; //offset relative to segment + long GetIndex() const; + long long GetElementSize() const; + // long long GetPayloadSize() const; - long GetIndex() const; - long long GetElementSize() const; - //long long GetPayloadSize() const; + // long long Unparsed() const; - //long long Unparsed() const; + private: + long m_index; + mutable long long m_pos; + // mutable long long m_size; + mutable long long m_element_size; + mutable long long m_timecode; + mutable BlockEntry** m_entries; + mutable long m_entries_size; + mutable long m_entries_count; -private: - long m_index; - mutable long long m_pos; - //mutable long long m_size; - mutable long long m_element_size; - mutable long long m_timecode; - mutable BlockEntry** m_entries; - mutable long m_entries_size; - mutable long m_entries_count; + long ParseSimpleBlock(long long, long long&, long&); + long ParseBlockGroup(long long, long long&, long&); - long ParseSimpleBlock(long long, long long&, long&); - long ParseBlockGroup(long long, long long&, long&); + long CreateBlock(long long id, long long pos, long long size, + long long discard_padding); + long CreateBlockGroup(long long start_offset, long long size, + long long discard_padding); + long CreateSimpleBlock(long long, long long); +}; - long CreateBlock(long long id, long long pos, long long size); - long CreateBlockGroup(long long, long long); - long CreateSimpleBlock(long long, long long); +class Segment { + friend class Cues; + friend class Track; + friend class VideoTrack; -}; + Segment(const Segment&); + Segment& operator=(const Segment&); + private: + Segment(IMkvReader*, long long elem_start, + // long long elem_size, + long long pos, long long size); -class Segment -{ - friend class Cues; - friend class VideoTrack; - friend class AudioTrack; - - Segment(const Segment&); - Segment& operator=(const Segment&); - -private: - Segment( - IMkvReader*, - long long elem_start, - //long long elem_size, - long long pos, - long long size); - -public: - IMkvReader* const m_pReader; - const long long m_element_start; - //const long long m_element_size; - const long long m_start; //posn of segment payload - const long long m_size; //size of segment payload - Cluster m_eos; //TODO: make private? - - static long long CreateInstance(IMkvReader*, long long, Segment*&); - ~Segment(); - - long Load(); //loads headers and all clusters - - //for incremental loading - //long long Unparsed() const; - bool DoneParsing() const; - long long ParseHeaders(); //stops when first cluster is found - //long FindNextCluster(long long& pos, long& size) const; - long LoadCluster(long long& pos, long& size); //load one cluster - long LoadCluster(); - - long ParseNext( - const Cluster* pCurr, - const Cluster*& pNext, - long long& pos, - long& size); + public: + IMkvReader* const m_pReader; + const long long m_element_start; + // const long long m_element_size; + const long long m_start; // posn of segment payload + const long long m_size; // size of segment payload + Cluster m_eos; // TODO: make private? + + static long long CreateInstance(IMkvReader*, long long, Segment*&); + ~Segment(); + + long Load(); // loads headers and all clusters + + // for incremental loading + // long long Unparsed() const; + bool DoneParsing() const; + long long ParseHeaders(); // stops when first cluster is found + // long FindNextCluster(long long& pos, long& size) const; + long LoadCluster(long long& pos, long& size); // load one cluster + long LoadCluster(); + + long ParseNext(const Cluster* pCurr, const Cluster*& pNext, long long& pos, + long& size); #if 0 //This pair parses one cluster, but only changes the state of the @@ -976,69 +884,62 @@ public: bool AddCluster(long long cluster_pos, long long new_pos); #endif - const SeekHead* GetSeekHead() const; - const Tracks* GetTracks() const; - const SegmentInfo* GetInfo() const; - const Cues* GetCues() const; - const Chapters* GetChapters() const; + const SeekHead* GetSeekHead() const; + const Tracks* GetTracks() const; + const SegmentInfo* GetInfo() const; + const Cues* GetCues() const; + const Chapters* GetChapters() const; - long long GetDuration() const; + long long GetDuration() const; - unsigned long GetCount() const; - const Cluster* GetFirst() const; - const Cluster* GetLast() const; - const Cluster* GetNext(const Cluster*); + unsigned long GetCount() const; + const Cluster* GetFirst() const; + const Cluster* GetLast() const; + const Cluster* GetNext(const Cluster*); - const Cluster* FindCluster(long long time_nanoseconds) const; - //const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; + const Cluster* FindCluster(long long time_nanoseconds) const; + // const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; - const Cluster* FindOrPreloadCluster(long long pos); + const Cluster* FindOrPreloadCluster(long long pos); - long ParseCues( - long long cues_off, //offset relative to start of segment - long long& parse_pos, - long& parse_len); + long ParseCues(long long cues_off, // offset relative to start of segment + long long& parse_pos, long& parse_len); -private: + private: + long long m_pos; // absolute file posn; what has been consumed so far + Cluster* m_pUnknownSize; - long long m_pos; //absolute file posn; what has been consumed so far - Cluster* m_pUnknownSize; + SeekHead* m_pSeekHead; + SegmentInfo* m_pInfo; + Tracks* m_pTracks; + Cues* m_pCues; + Chapters* m_pChapters; + 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 + long m_clusterSize; // array size - SeekHead* m_pSeekHead; - SegmentInfo* m_pInfo; - Tracks* m_pTracks; - Cues* m_pCues; - Chapters* m_pChapters; - 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 - long m_clusterSize; //array size + long DoLoadCluster(long long&, long&); + long DoLoadClusterUnknownSize(long long&, long&); + long DoParseNext(const Cluster*&, long long&, long&); - long DoLoadCluster(long long&, long&); - long DoLoadClusterUnknownSize(long long&, long&); - long DoParseNext(const Cluster*&, long long&, long&); + void AppendCluster(Cluster*); + void PreloadCluster(Cluster*, ptrdiff_t); - void AppendCluster(Cluster*); - void PreloadCluster(Cluster*, ptrdiff_t); - - //void ParseSeekHead(long long pos, long long size); - //void ParseSeekEntry(long long pos, long long size); - //void ParseCues(long long); - - const BlockEntry* GetBlock( - const CuePoint&, - const CuePoint::TrackPosition&); + // void ParseSeekHead(long long pos, long long size); + // void ParseSeekEntry(long long pos, long long size); + // void ParseCues(long long); + const BlockEntry* GetBlock(const CuePoint&, const CuePoint::TrackPosition&); }; -} //end namespace mkvparser +} // end namespace mkvparser -inline long mkvparser::Segment::LoadCluster() -{ - long long pos; - long size; +inline long mkvparser::Segment::LoadCluster() { + long long pos; + long size; - return LoadCluster(pos, size); + return LoadCluster(pos, size); } -#endif //MKVPARSER_HPP +#endif // MKVPARSER_HPP diff --git a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp index 12c5c208..eaf9e0a7 100644 --- a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp +++ b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.cpp @@ -10,119 +10,123 @@ #include -namespace mkvparser -{ +namespace mkvparser { -MkvReader::MkvReader() : - m_file(NULL) -{ +MkvReader::MkvReader() : m_file(NULL), reader_owns_file_(true) {} + +MkvReader::MkvReader(FILE* fp) : m_file(fp), reader_owns_file_(false) { + GetFileSize(); } -MkvReader::~MkvReader() -{ +MkvReader::~MkvReader() { + if (reader_owns_file_) Close(); + m_file = NULL; } -int MkvReader::Open(const char* fileName) -{ - if (fileName == NULL) - return -1; +int MkvReader::Open(const char* fileName) { + if (fileName == NULL) + return -1; - if (m_file) - return -1; + if (m_file) + return -1; -#ifdef WIN32 - const errno_t e = fopen_s(&m_file, fileName, "rb"); +#ifdef _MSC_VER + const errno_t e = fopen_s(&m_file, fileName, "rb"); - if (e) - return -1; //error + if (e) + return -1; // error #else - m_file = fopen(fileName, "rb"); + m_file = fopen(fileName, "rb"); - if (m_file == NULL) - return -1; + if (m_file == NULL) + return -1; #endif + return !GetFileSize(); +} -#ifdef WIN32 - int status = _fseeki64(m_file, 0L, SEEK_END); +bool MkvReader::GetFileSize() { + if (m_file == NULL) + return false; +#ifdef _MSC_VER + int status = _fseeki64(m_file, 0L, SEEK_END); - if (status) - return -1; //error + if (status) + return false; // error - m_length = _ftelli64(m_file); + m_length = _ftelli64(m_file); #else - fseek(m_file, 0L, SEEK_END); - m_length = ftell(m_file); + fseek(m_file, 0L, SEEK_END); + m_length = ftell(m_file); #endif - assert(m_length >= 0); + assert(m_length >= 0); + + if (m_length < 0) + return false; -#ifdef WIN32 - status = _fseeki64(m_file, 0L, SEEK_SET); +#ifdef _MSC_VER + status = _fseeki64(m_file, 0L, SEEK_SET); - if (status) - return -1; //error + if (status) + return false; // error #else - fseek(m_file, 0L, SEEK_SET); + fseek(m_file, 0L, SEEK_SET); #endif - return 0; + return true; } -void MkvReader::Close() -{ - if (m_file != NULL) - { - fclose(m_file); - m_file = NULL; - } +void MkvReader::Close() { + if (m_file != NULL) { + fclose(m_file); + m_file = NULL; + } } -int MkvReader::Length(long long* total, long long* available) -{ - if (m_file == NULL) - return -1; +int MkvReader::Length(long long* total, long long* available) { + if (m_file == NULL) + return -1; - if (total) - *total = m_length; + if (total) + *total = m_length; - if (available) - *available = m_length; + if (available) + *available = m_length; - return 0; + return 0; } -int MkvReader::Read(long long offset, long len, unsigned char* buffer) -{ - if (m_file == NULL) - return -1; +int MkvReader::Read(long long offset, long len, unsigned char* buffer) { + if (m_file == NULL) + return -1; - if (offset < 0) - return -1; + if (offset < 0) + return -1; - if (len < 0) - return -1; + if (len < 0) + return -1; - if (len == 0) - return 0; + if (len == 0) + return 0; - if (offset >= m_length) - return -1; + if (offset >= m_length) + return -1; -#ifdef WIN32 - const int status = _fseeki64(m_file, offset, SEEK_SET); +#ifdef _MSC_VER + const int status = _fseeki64(m_file, offset, SEEK_SET); - if (status) - return -1; //error + if (status) + return -1; // error #else - fseek(m_file, offset, SEEK_SET); + fseek(m_file, offset, SEEK_SET); #endif - const size_t size = fread(buffer, 1, len, m_file); + const size_t size = fread(buffer, 1, len, m_file); - if (size < size_t(len)) - return -1; //error + if (size < size_t(len)) + return -1; // error - return 0; //success + return 0; // success } -} //end namespace mkvparser +} // end namespace mkvparser diff --git a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp index 7f8c3bc1..82ebad54 100644 --- a/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp +++ b/Sources/Plasma/FeatureLib/pfMoviePlayer/webm/mkvreader.hpp @@ -12,28 +12,34 @@ #include "mkvparser.hpp" #include -namespace mkvparser -{ - -class MkvReader : public IMkvReader -{ - MkvReader(const MkvReader&); - MkvReader& operator=(const MkvReader&); -public: - MkvReader(); - virtual ~MkvReader(); - - int Open(const char*); - void Close(); - bool IsOpen() const; - - virtual int Read(long long position, long length, unsigned char* buffer); - virtual int Length(long long* total, long long* available); -private: - long long m_length; - FILE* m_file; +namespace mkvparser { + +class MkvReader : public IMkvReader { + public: + MkvReader(); + explicit MkvReader(FILE* fp); + virtual ~MkvReader(); + + int Open(const char*); + void Close(); + + virtual int Read(long long position, long length, unsigned char* buffer); + virtual int Length(long long* total, long long* available); + + private: + MkvReader(const MkvReader&); + MkvReader& operator=(const MkvReader&); + + // Determines the size of the file. This is called either by the constructor + // or by the Open function depending on file ownership. Returns true on + // success. + bool GetFileSize(); + + long long m_length; + FILE* m_file; + bool reader_owns_file_; }; -} //end namespace mkvparser +} // end namespace mkvparser -#endif //MKVREADER_HPP +#endif // MKVREADER_HPP