Compare commits

...

4 Commits

Author SHA1 Message Date
matthewjheaney
379839bedc simplified segment::load()
Change-Id: I92793d405ee24f2d94a6a6a251a5bada4f0d40a8
2012-03-07 10:47:26 -05:00
matthewjheaney
484c71d875 parse seek head outside of ctor
Change-Id: I44bab1d7d6d7c08e11c3a73f72598426e92e4f89
2012-03-07 09:16:37 -05:00
matthewjheaney
a45b72d731 Parse headers outside of constructor
In several cases, the parser would parse a header
(say, a track header, or the segment info header)
in the constructor for the type.  The parser had
assumed (incorrectly) that the file was well-formed,
but this turned out to be an incorrect assumption.

The parse errors triggered some assertion failures,
but this is not acceptable in a production system.

The parser solved that problem by separating the
construction of the header object from the parsing
of the file.  There is now a separate parse method
to be called after construction of the object,
which returns a status whether the parse was
successful.

This change fixes the bugs from the following
tracker issues:

http://code.google.com/p/webm/issues/detail?id=399
http://code.google.com/p/webm/issues/detail?id=400

Change-Id: Idb09154ae7008429d8613ce3b3e8294f5a12de86
2012-03-06 17:58:45 -05:00
matthewjheaney
6fa7c7611c Block parsing is now robust
Previously, parsing of a Block element was done inside its
constructor.  Parsing errors were handled via assertion checks,
but this only works in practice if there are no actual errors
in the file.

We did come across a file, however, that used EMBL-style lacing,
but the lacing was done incorrectly and so the parse asserted.
This isn't acceptable for a production system, and more a graceful
handling of parse errors was needed.

The code was restructured such that the Block object's ctor does
only trivial initialization of member variables.  A separate Parse
method was added, that is called after the object is constructed.
If the parse succeeds all is well, otherwise the object is destroyed
and the error is reported to the caller.

This commit fixes bug tracker issue #398, described here:

http://code.google.com/p/webm/issues/detail?id=398

Change-Id: Ib95ca95d0eec08cf670b308c461e42ed8345e890
2012-02-28 14:03:21 -05:00
4 changed files with 1360 additions and 615 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,15 @@ signed char Unserialize1SInt(IMkvReader*, long long);
long UnserializeInt(IMkvReader*, long long pos, long len, long long& result);
#endif
long UnserializeString(IMkvReader*, long long pos, long long size, char*&);
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, char*&);
bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
@@ -80,9 +89,11 @@ public:
const long long m_start;
const long long m_size;
Block(long long start, long long size, IMkvReader*);
Block(long long start, long long size);
~Block();
long Parse(IMkvReader*);
long long GetTrackNumber() const;
long long GetTimeCode(const Cluster*) const; //absolute, but not scaled
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
@@ -126,6 +137,7 @@ protected:
public:
virtual ~BlockEntry();
bool EOS() const;
const Cluster* GetCluster() const;
long GetIndex() const;
@@ -148,6 +160,7 @@ class SimpleBlock : public BlockEntry
public:
SimpleBlock(Cluster*, long index, long long start, long long size);
long Parse();
Kind GetKind() const;
const Block* GetBlock() const;
@@ -173,6 +186,8 @@ public:
long long next,
long long duration);
long Parse();
Kind GetKind() const;
const Block* GetBlock() const;
@@ -283,6 +298,8 @@ class Track
Track& operator=(const Track&);
public:
enum Type { kVideo = 1, kAudio = 2 };
Segment* const m_pSegment;
const long long m_element_start;
const long long m_element_size;
@@ -338,6 +355,7 @@ protected:
const Info&,
long long element_start,
long long element_size);
const Info m_info;
class EOSBlock : public BlockEntry
@@ -345,9 +363,6 @@ protected:
public:
EOSBlock();
//bool EOS() const;
//const Cluster* GetCluster() const;
//long GetIndex() const;
Kind GetKind() const;
const Block* GetBlock() const;
};
@@ -365,12 +380,20 @@ class VideoTrack : public Track
VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
public:
VideoTrack(
Segment*,
const Info&,
long long element_start,
long long element_size);
public:
static long Parse(
Segment*,
const Info&,
long long element_start,
long long element_size,
VideoTrack*&);
long long GetWidth() const;
long long GetHeight() const;
double GetFrameRate() const;
@@ -391,12 +414,19 @@ class AudioTrack : public Track
AudioTrack(const AudioTrack&);
AudioTrack& operator=(const AudioTrack&);
public:
AudioTrack(
Segment*,
const Info&,
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;
@@ -428,7 +458,12 @@ public:
long long size,
long long element_start,
long long element_size);
virtual ~Tracks();
~Tracks();
long Parse();
unsigned long GetTracksCount() const;
const Track* GetTrackByNumber(unsigned long tn) const;
const Track* GetTrackByIndex(unsigned long idx) const;
@@ -437,15 +472,13 @@ private:
Track** m_trackEntries;
Track** m_trackEntriesEnd;
void ParseTrackEntry(
long long,
long long,
Track*&,
long ParseTrackEntry(
long long payload_start,
long long payload_size,
long long element_start,
long long element_size);
long long element_size,
Track*&) const;
public:
unsigned long GetTracksCount() const;
};
@@ -470,6 +503,8 @@ public:
~SegmentInfo();
long Parse();
long long GetTimeCodeScale() const;
long long GetDuration() const; //scaled
const char* GetMuxingAppAsUTF8() const;
@@ -506,6 +541,8 @@ public:
~SeekHead();
long Parse();
struct Entry
{
//the SeekHead entry payload
@@ -680,9 +717,10 @@ public:
long long GetFirstTime() const; //time (ns) of first (earliest) block
long long GetLastTime() const; //time (ns) of last (latest) block
const BlockEntry* GetFirst() const;
const BlockEntry* GetLast() const;
const BlockEntry* GetNext(const BlockEntry*) 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&,
@@ -731,12 +769,12 @@ private:
mutable long m_entries_size;
mutable long m_entries_count;
long ParseSimpleBlock(long long, long long&, long&) const;
long ParseBlockGroup(long long, long long&, long&) const;
long ParseSimpleBlock(long long, long long&, long&);
long ParseBlockGroup(long long, long long&, long&);
void CreateBlock(long long id, long long pos, long long size) const;
void CreateBlockGroup(long long, long long, BlockEntry**&) const;
void CreateSimpleBlock(long long, long long, BlockEntry**&) const;
long CreateBlock(long long id, long long pos, long long size);
long CreateBlockGroup(long long, long long);
long CreateSimpleBlock(long long, long long);
};

View File

@@ -11,6 +11,7 @@
#include "mkvreader.hpp"
#include "mkvparser.hpp"
#include <memory>
#ifdef _MSC_VER
// Silences these warnings:
@@ -83,15 +84,18 @@ int main(int argc, char* argv[])
printf("\t\tDoc Type\t\t: %s\n", ebmlHeader.m_docType);
printf("\t\tPos\t\t\t: %lld\n", pos);
mkvparser::Segment* pSegment;
typedef mkvparser::Segment seg_t;
seg_t* pSegment_;
long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
long long ret = seg_t::CreateInstance(&reader, pos, pSegment_);
if (ret)
{
printf("\n Segment::CreateInstance() failed.");
return -1;
}
const std::auto_ptr<seg_t> pSegment(pSegment_);
ret = pSegment->Load();
if (ret < 0)
{
@@ -242,7 +246,6 @@ int main(int argc, char* argv[])
if (clusterCount == 0)
{
printf("\t\tSegment has no clusters.\n");
delete pSegment;
return -1;
}
@@ -256,7 +259,16 @@ int main(int argc, char* argv[])
const long long time_ns = pCluster->GetTime();
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
const BlockEntry* pBlockEntry = pCluster->GetFirst();
const BlockEntry* pBlockEntry;
long status = pCluster->GetFirst(pBlockEntry);
if (status < 0) //error
{
printf("\t\tError parsing first block of cluster\n");
fflush(stdout);
return -1;
}
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
{
@@ -264,30 +276,42 @@ int main(int argc, char* argv[])
const long long trackNum = pBlock->GetTrackNumber();
const unsigned long tn = static_cast<unsigned long>(trackNum);
const Track* const pTrack = pTracks->GetTrackByNumber(tn);
const long long trackType = pTrack->GetType();
const int frameCount = pBlock->GetFrameCount();
const long long time_ns = pBlock->GetTime(pCluster);
printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",
(trackType == VIDEO_TRACK) ? "V" : "A",
pBlock->IsKey() ? "I" : "P",
time_ns);
for (int i = 0; i < frameCount; ++i)
if (pTrack == NULL)
printf("\t\t\tBlock\t\t:UNKNOWN TRACK TYPE\n");
else
{
const Block::Frame& theFrame = pBlock->GetFrame(i);
const long size = theFrame.len;
const long long offset = theFrame.pos;
printf("\t\t\t %15ld,%15llx\n", size, offset);
const long long trackType = pTrack->GetType();
const int frameCount = pBlock->GetFrameCount();
const long long time_ns = pBlock->GetTime(pCluster);
printf("\t\t\tBlock\t\t:%s,%s,%15lld\n",
(trackType == VIDEO_TRACK) ? "V" : "A",
pBlock->IsKey() ? "I" : "P",
time_ns);
for (int i = 0; i < frameCount; ++i)
{
const Block::Frame& theFrame = pBlock->GetFrame(i);
const long size = theFrame.len;
const long long offset = theFrame.pos;
printf("\t\t\t %15ld,%15llx\n", size, offset);
}
}
pBlockEntry = pCluster->GetNext(pBlockEntry);
status = pCluster->GetNext(pBlockEntry, pBlockEntry);
if (status < 0)
{
printf("\t\t\tError parsing next block of cluster\n");
fflush(stdout);
return -1;
}
}
pCluster = pSegment->GetNext(pCluster);
}
delete pSegment;
fflush(stdout);
return 0;
}

View File

@@ -317,7 +317,15 @@ int main(int argc, char* argv[]) {
const mkvparser::Cluster* cluster = parser_segment->GetFirst();
while ((cluster != NULL) && !cluster->EOS()) {
const mkvparser::BlockEntry* block_entry = cluster->GetFirst();
const mkvparser::BlockEntry* block_entry;
long status = cluster->GetFirst(block_entry);
if (status)
{
printf("\n Could not get first block of cluster.\n");
return EXIT_FAILURE;
}
while ((block_entry != NULL) && !block_entry->EOS()) {
const mkvparser::Block* const block = block_entry->GetBlock();
@@ -362,7 +370,13 @@ int main(int argc, char* argv[]) {
}
}
block_entry = cluster->GetNext(block_entry);
status = cluster->GetNext(block_entry, block_entry);
if (status)
{
printf("\n Could not get next block of cluster.\n");
return EXIT_FAILURE;
}
}
cluster = parser_segment->GetNext(cluster);