Merge "DO NOT MERGE Upgrade to the latest version of libwebm to fix YouTube webm playback." into gingerbread

This commit is contained in:
Andreas Huber
2010-11-30 14:06:26 -08:00
committed by Android (Google) Code Review
3 changed files with 5067 additions and 3533 deletions

View File

@@ -252,7 +252,7 @@ void BlockIterator::reset() {
} }
void BlockIterator::seek(int64_t seekTimeUs) { void BlockIterator::seek(int64_t seekTimeUs) {
mCluster = mSegment->GetCluster(seekTimeUs * 1000ll); mCluster = mSegment->FindCluster(seekTimeUs * 1000ll);
mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL; mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;
while (!eos() && block()->GetTrackNumber() != mTrackNum) { while (!eos() && block()->GetTrackNumber() != mTrackNum) {
@@ -476,7 +476,7 @@ void MatroskaExtractor::addTracks() {
size_t codecPrivateSize; size_t codecPrivateSize;
const unsigned char *codecPrivate = const unsigned char *codecPrivate =
track->GetCodecPrivate(&codecPrivateSize); track->GetCodecPrivate(codecPrivateSize);
enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 }; enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };

File diff suppressed because it is too large Load Diff

View File

@@ -1,428 +1,554 @@
#ifndef MKVPARSER_HPP // Copyright (c) 2010 The WebM project authors. All Rights Reserved.
#define MKVPARSER_HPP //
// Use of this source code is governed by a BSD-style license
#include <cstdlib> // that can be found in the LICENSE file in the root of the source
#include <cstdio> // tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
namespace mkvparser // be found in the AUTHORS file in the root of the source tree.
{
#ifndef MKVPARSER_HPP
const int E_FILE_FORMAT_INVALID = -2; #define MKVPARSER_HPP
const int E_BUFFER_NOT_FULL = -3;
#include <cstdlib>
class IMkvReader #include <cstdio>
{
public: namespace mkvparser
virtual int Read(long long position, long length, unsigned char* buffer) = 0; {
virtual int Length(long long* total, long long* available) = 0;
protected: const int E_FILE_FORMAT_INVALID = -2;
virtual ~IMkvReader(); const int E_BUFFER_NOT_FULL = -3;
};
class IMkvReader
long long GetUIntLength(IMkvReader*, long long, long&); {
long long ReadUInt(IMkvReader*, long long, long&); public:
long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&); virtual int Read(long long pos, long len, unsigned char* buf) = 0;
long long UnserializeUInt(IMkvReader*, long long pos, long long size); virtual int Length(long long* total, long long* available) = 0;
float Unserialize4Float(IMkvReader*, long long); protected:
double Unserialize8Double(IMkvReader*, long long); virtual ~IMkvReader();
short Unserialize2SInt(IMkvReader*, long long); };
signed char Unserialize1SInt(IMkvReader*, long long);
bool Match(IMkvReader*, long long&, unsigned long, long long&); long long GetUIntLength(IMkvReader*, long long, long&);
bool Match(IMkvReader*, long long&, unsigned long, char*&); long long ReadUInt(IMkvReader*, long long, long&);
bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&);
size_t *optionalSize = NULL); long long UnserializeUInt(IMkvReader*, long long pos, long long size);
bool Match(IMkvReader*, long long&, unsigned long, double&); float Unserialize4Float(IMkvReader*, long long);
bool Match(IMkvReader*, long long&, unsigned long, short&); double Unserialize8Double(IMkvReader*, long long);
short Unserialize2SInt(IMkvReader*, long long);
signed char Unserialize1SInt(IMkvReader*, long long);
struct EBMLHeader bool Match(IMkvReader*, long long&, unsigned long, long long&);
{ bool Match(IMkvReader*, long long&, unsigned long, char*&);
EBMLHeader(); bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, size_t&);
~EBMLHeader(); bool Match(IMkvReader*, long long&, unsigned long, double&);
long long m_version; bool Match(IMkvReader*, long long&, unsigned long, short&);
long long m_readVersion;
long long m_maxIdLength; void GetVersion(int& major, int& minor, int& build, int& revision);
long long m_maxSizeLength;
char* m_docType; struct EBMLHeader
long long m_docTypeVersion; {
long long m_docTypeReadVersion; EBMLHeader();
~EBMLHeader();
long long Parse(IMkvReader*, long long&); long long m_version;
}; long long m_readVersion;
long long m_maxIdLength;
long long m_maxSizeLength;
class Segment; char* m_docType;
class Track; long long m_docTypeVersion;
class Cluster; long long m_docTypeReadVersion;
class Block long long Parse(IMkvReader*, long long&);
{ };
Block(const Block&);
Block& operator=(const Block&);
class Segment;
public: class Track;
const long long m_start; class Cluster;
const long long m_size;
class Block
Block(long long start, long long size, IMkvReader*); {
Block(const Block&);
unsigned long GetTrackNumber() const; Block& operator=(const Block&);
long long GetTimeCode(Cluster*) const; //absolute, but not scaled public:
long long GetTime(Cluster*) const; //absolute, and scaled (nanosecond units) const long long m_start;
bool IsKey() const; const long long m_size;
void SetKey(bool);
Block(long long start, long long size, IMkvReader*);
long GetSize() const;
long Read(IMkvReader*, unsigned char*) const; long long GetTrackNumber() const;
long long GetTimeCode(Cluster*) const; //absolute, but not scaled
private: long long GetTime(Cluster*) const; //absolute, and scaled (ns units)
long long m_track; //Track::Number() bool IsKey() const;
short m_timecode; //relative to cluster void SetKey(bool);
unsigned char m_flags;
long long m_frameOff; long long GetOffset() const;
long m_frameSize; long GetSize() const;
long Read(IMkvReader*, unsigned char*) const;
};
private:
long long m_track; //Track::Number()
class BlockEntry short m_timecode; //relative to cluster
{ unsigned char m_flags;
BlockEntry(const BlockEntry&); long long m_frameOff;
BlockEntry& operator=(const BlockEntry&); long m_frameSize;
public: };
virtual ~BlockEntry();
virtual bool EOS() const = 0;
virtual Cluster* GetCluster() const = 0; class BlockEntry
virtual size_t GetIndex() const = 0; {
virtual const Block* GetBlock() const = 0; BlockEntry(const BlockEntry&);
virtual bool IsBFrame() const = 0; BlockEntry& operator=(const BlockEntry&);
protected: public:
BlockEntry(); virtual ~BlockEntry();
virtual bool EOS() const = 0;
}; virtual Cluster* GetCluster() const = 0;
virtual size_t GetIndex() const = 0;
virtual const Block* GetBlock() const = 0;
class SimpleBlock : public BlockEntry virtual bool IsBFrame() const = 0;
{
SimpleBlock(const SimpleBlock&); protected:
SimpleBlock& operator=(const SimpleBlock&); BlockEntry();
public: };
SimpleBlock(Cluster*, size_t, long long start, long long size);
bool EOS() const; class SimpleBlock : public BlockEntry
Cluster* GetCluster() const; {
size_t GetIndex() const; SimpleBlock(const SimpleBlock&);
const Block* GetBlock() const; SimpleBlock& operator=(const SimpleBlock&);
bool IsBFrame() const;
public:
protected: SimpleBlock(Cluster*, size_t, long long start, long long size);
Cluster* const m_pCluster;
const size_t m_index; bool EOS() const;
Block m_block; Cluster* GetCluster() const;
size_t GetIndex() const;
}; const Block* GetBlock() const;
bool IsBFrame() const;
class BlockGroup : public BlockEntry protected:
{ Cluster* const m_pCluster;
BlockGroup(const BlockGroup&); const size_t m_index;
BlockGroup& operator=(const BlockGroup&); Block m_block;
public: };
BlockGroup(Cluster*, size_t, long long, long long);
~BlockGroup();
class BlockGroup : public BlockEntry
bool EOS() const; {
Cluster* GetCluster() const; BlockGroup(const BlockGroup&);
size_t GetIndex() const; BlockGroup& operator=(const BlockGroup&);
const Block* GetBlock() const;
bool IsBFrame() const; public:
BlockGroup(Cluster*, size_t, long long, long long);
short GetPrevTimeCode() const; //relative to block's time ~BlockGroup();
short GetNextTimeCode() const; //as above
bool EOS() const;
protected: Cluster* GetCluster() const;
Cluster* const m_pCluster; size_t GetIndex() const;
const size_t m_index; const Block* GetBlock() const;
bool IsBFrame() const;
private:
BlockGroup(Cluster*, size_t, unsigned long); short GetPrevTimeCode() const; //relative to block's time
void ParseBlock(long long start, long long size); short GetNextTimeCode() const; //as above
short m_prevTimeCode; protected:
short m_nextTimeCode; Cluster* const m_pCluster;
const size_t m_index;
//TODO: the Matroska spec says you can have multiple blocks within the
//same block group, with blocks ranked by priority (the flag bits). private:
//For now we just cache a single block. BlockGroup(Cluster*, size_t, unsigned long);
#if 0 void ParseBlock(long long start, long long size);
typedef std::deque<Block*> blocks_t;
blocks_t m_blocks; //In practice should contain only a single element. short m_prevTimeCode;
#else short m_nextTimeCode;
Block* m_pBlock;
#endif //TODO: the Matroska spec says you can have multiple blocks within the
//same block group, with blocks ranked by priority (the flag bits).
}; //For now we just cache a single block.
#if 0
typedef std::deque<Block*> blocks_t;
class Track blocks_t m_blocks; //In practice should contain only a single element.
{ #else
Track(const Track&); Block* m_pBlock;
Track& operator=(const Track&); #endif
public: };
Segment* const m_pSegment;
virtual ~Track();
class Track
long long GetType() const; {
unsigned long GetNumber() const; Track(const Track&);
const char* GetNameAsUTF8() const; Track& operator=(const Track&);
const char* GetCodecNameAsUTF8() const;
const char* GetCodecId() const; public:
const unsigned char* GetCodecPrivate( Segment* const m_pSegment;
size_t *optionalSize = NULL) const; virtual ~Track();
const BlockEntry* GetEOS() const; long long GetType() const;
long long GetNumber() const;
struct Settings const char* GetNameAsUTF8() const;
{ const char* GetCodecNameAsUTF8() const;
long long start; const char* GetCodecId() const;
long long size; const unsigned char* GetCodecPrivate(size_t&) const;
};
const BlockEntry* GetEOS() const;
struct Info
{ struct Settings
long long type; {
long long number; long long start;
long long uid; long long size;
char* nameAsUTF8; };
char* codecId;
unsigned char* codecPrivate; struct Info
size_t codecPrivateSize; {
char* codecNameAsUTF8; long long type;
Settings settings; long long number;
Info(); long long uid;
void Clear(); char* nameAsUTF8;
}; char* codecId;
unsigned char* codecPrivate;
long GetFirst(const BlockEntry*&) const; size_t codecPrivateSize;
long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; char* codecNameAsUTF8;
virtual bool VetEntry(const BlockEntry*) const = 0; Settings settings;
Info();
protected: void Clear();
Track(Segment*, const Info&); };
const Info m_info;
long GetFirst(const BlockEntry*&) const;
class EOSBlock : public BlockEntry long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
{ virtual bool VetEntry(const BlockEntry*) const = 0;
public:
EOSBlock(); protected:
Track(Segment*, const Info&);
bool EOS() const; const Info m_info;
Cluster* GetCluster() const;
size_t GetIndex() const; class EOSBlock : public BlockEntry
const Block* GetBlock() const; {
bool IsBFrame() const; public:
}; EOSBlock();
EOSBlock m_eos; bool EOS() const;
Cluster* GetCluster() const;
}; size_t GetIndex() const;
const Block* GetBlock() const;
bool IsBFrame() const;
class VideoTrack : public Track };
{
VideoTrack(const VideoTrack&); EOSBlock m_eos;
VideoTrack& operator=(const VideoTrack&);
};
public:
VideoTrack(Segment*, const Info&);
long long GetWidth() const; class VideoTrack : public Track
long long GetHeight() const; {
double GetFrameRate() const; VideoTrack(const VideoTrack&);
VideoTrack& operator=(const VideoTrack&);
bool VetEntry(const BlockEntry*) const;
public:
private: VideoTrack(Segment*, const Info&);
long long m_width; long long GetWidth() const;
long long m_height; long long GetHeight() const;
double m_rate; double GetFrameRate() const;
}; bool VetEntry(const BlockEntry*) const;
private:
class AudioTrack : public Track long long m_width;
{ long long m_height;
AudioTrack(const AudioTrack&); double m_rate;
AudioTrack& operator=(const AudioTrack&);
};
public:
AudioTrack(Segment*, const Info&);
double GetSamplingRate() const; class AudioTrack : public Track
long long GetChannels() const; {
long long GetBitDepth() const; AudioTrack(const AudioTrack&);
bool VetEntry(const BlockEntry*) const; AudioTrack& operator=(const AudioTrack&);
private: public:
double m_rate; AudioTrack(Segment*, const Info&);
long long m_channels; double GetSamplingRate() const;
long long m_bitDepth; long long GetChannels() const;
}; long long GetBitDepth() const;
bool VetEntry(const BlockEntry*) const;
class Tracks private:
{ double m_rate;
Tracks(const Tracks&); long long m_channels;
Tracks& operator=(const Tracks&); long long m_bitDepth;
};
public:
Segment* const m_pSegment;
const long long m_start; class Tracks
const long long m_size; {
Tracks(const Tracks&);
Tracks(Segment*, long long start, long long size); Tracks& operator=(const Tracks&);
virtual ~Tracks();
public:
Track* GetTrackByNumber(unsigned long tn) const; Segment* const m_pSegment;
Track* GetTrackByIndex(unsigned long idx) const; const long long m_start;
const long long m_size;
private:
Track** m_trackEntries; Tracks(Segment*, long long start, long long size);
Track** m_trackEntriesEnd; virtual ~Tracks();
void ParseTrackEntry(long long, long long, Track*&); Track* GetTrackByNumber(unsigned long tn) const;
Track* GetTrackByIndex(unsigned long idx) const;
public:
unsigned long GetTracksCount() const; private:
}; Track** m_trackEntries;
Track** m_trackEntriesEnd;
class SegmentInfo void ParseTrackEntry(long long, long long, Track*&);
{
SegmentInfo(const SegmentInfo&); public:
SegmentInfo& operator=(const SegmentInfo&); unsigned long GetTracksCount() const;
};
public:
Segment* const m_pSegment;
const long long m_start; class SegmentInfo
const long long m_size; {
SegmentInfo(const SegmentInfo&);
SegmentInfo(Segment*, long long start, long long size); SegmentInfo& operator=(const SegmentInfo&);
~SegmentInfo();
long long GetTimeCodeScale() const; public:
long long GetDuration() const; //scaled Segment* const m_pSegment;
const char* GetMuxingAppAsUTF8() const; const long long m_start;
const char* GetWritingAppAsUTF8() const; const long long m_size;
const char* GetTitleAsUTF8() const;
SegmentInfo(Segment*, long long start, long long size);
private: ~SegmentInfo();
long long m_timecodeScale; long long GetTimeCodeScale() const;
double m_duration; long long GetDuration() const; //scaled
char* m_pMuxingAppAsUTF8; const char* GetMuxingAppAsUTF8() const;
char* m_pWritingAppAsUTF8; const char* GetWritingAppAsUTF8() const;
char* m_pTitleAsUTF8; const char* GetTitleAsUTF8() const;
};
private:
long long m_timecodeScale;
class Cluster double m_duration;
{ char* m_pMuxingAppAsUTF8;
Cluster(const Cluster&); char* m_pWritingAppAsUTF8;
Cluster& operator=(const Cluster&); char* m_pTitleAsUTF8;
};
public:
Segment* const m_pSegment; class Cues;
const size_t m_index; class CuePoint
{
public: friend class Cues;
static Cluster* Parse(Segment*, size_t, long long off);
CuePoint(size_t, long long);
Cluster(); //EndOfStream ~CuePoint();
~Cluster();
CuePoint(const CuePoint&);
bool EOS() const; CuePoint& operator=(const CuePoint&);
long long GetTimeCode(); //absolute, but not scaled public:
long long GetTime(); //absolute, and scaled (nanosecond units) void Load(IMkvReader*);
const BlockEntry* GetFirst(); long long GetTimeCode() const; //absolute but unscaled
const BlockEntry* GetLast(); long long GetTime(Segment*) const; //absolute and scaled (ns units)
const BlockEntry* GetNext(const BlockEntry*) const;
const BlockEntry* GetEntry(const Track*); struct TrackPosition
protected: {
Cluster(Segment*, size_t, long long off); long long m_track;
long long m_pos; //of cluster
private: long long m_block;
long long m_start; //codec_state //defaults to 0
long long m_size; //reference = clusters containing req'd referenced blocks
long long m_timecode; // reftime = timecode of the referenced block
BlockEntry** m_pEntries;
size_t m_entriesCount; void Parse(IMkvReader*, long long, long long);
};
void Load();
void LoadBlockEntries(); const TrackPosition* Find(const Track*) const;
void ParseBlockGroup(long long, long long, size_t);
void ParseSimpleBlock(long long, long long, size_t); private:
const size_t m_index;
}; long long m_timecode;
TrackPosition* m_track_positions;
size_t m_track_positions_count;
class Segment
{ };
Segment(const Segment&);
Segment& operator=(const Segment&);
class Cues
private: {
Segment(IMkvReader*, long long pos, long long size); friend class Segment;
public: Cues(Segment*, long long start, long long size);
IMkvReader* const m_pReader; ~Cues();
const long long m_start; //posn of segment payload
const long long m_size; //size of segment payload Cues(const Cues&);
Cluster m_eos; //TODO: make private? Cues& operator=(const Cues&);
static long long CreateInstance(IMkvReader*, long long, Segment*&); public:
~Segment(); Segment* const m_pSegment;
const long long m_start;
//for big-bang loading (source filter) const long long m_size;
long Load();
bool Find( //lower bound of time_ns
//for incremental loading (splitter) long long time_ns,
long long Unparsed() const; const Track*,
long long ParseHeaders(); const CuePoint*&,
long ParseCluster(Cluster*&, long long& newpos) const; const CuePoint::TrackPosition*&) const;
bool AddCluster(Cluster*, long long);
#if 0
Tracks* GetTracks() const; bool FindNext( //upper_bound of time_ns
const SegmentInfo* const GetInfo() const; long long time_ns,
long long GetDuration() const; const Track*,
const CuePoint*&,
//NOTE: this turned out to be too inefficient. const CuePoint::TrackPosition*&) const;
//long long Load(long long time_nanoseconds); #endif
Cluster* GetFirst(); const CuePoint* GetFirst() const;
Cluster* GetLast(); const CuePoint* GetLast() const;
unsigned long GetCount() const;
const CuePoint* GetNext(const CuePoint*) const;
Cluster* GetNext(const Cluster*);
Cluster* GetCluster(long long time_nanoseconds); const BlockEntry* GetBlock(
const CuePoint*,
private: const CuePoint::TrackPosition*) const;
long long m_pos; //absolute file posn; what has been consumed so far
SegmentInfo* m_pInfo; private:
Tracks* m_pTracks; void Init() const;
Cluster** m_clusters; bool LoadCuePoint() const;
size_t m_clusterCount; void PreloadCuePoint(size_t&, long long) const;
void ParseSeekHead(long long pos, long long size, size_t*); mutable CuePoint** m_cue_points;
void ParseSeekEntry(long long pos, long long size, size_t*); mutable size_t m_count;
void ParseSecondarySeekHead(long long off, size_t*); mutable size_t m_preload_count;
}; mutable long long m_pos;
};
} //end namespace mkvparser
#endif //MKVPARSER_HPP class Cluster
{
Cluster(const Cluster&);
Cluster& operator=(const Cluster&);
public:
Segment* const m_pSegment;
public:
static Cluster* Parse(Segment*, long, long long off);
Cluster(); //EndOfStream
~Cluster();
bool EOS() const;
long long GetTimeCode(); //absolute, but not scaled
long long GetTime(); //absolute, and scaled (nanosecond units)
long long GetFirstTime(); //time (ns) of first (earliest) block
long long GetLastTime(); //time (ns) of last (latest) block
const BlockEntry* GetFirst();
const BlockEntry* GetLast();
const BlockEntry* GetNext(const BlockEntry*) const;
const BlockEntry* GetEntry(const Track*);
const BlockEntry* GetEntry(
const CuePoint&,
const CuePoint::TrackPosition&);
const BlockEntry* GetMaxKey(const VideoTrack*);
protected:
Cluster(Segment*, long, long long off);
public:
//TODO: these should all be private, with public selector functions
long m_index;
long long m_pos;
long long m_size;
private:
long long m_timecode;
BlockEntry** m_entries;
size_t m_entriesCount;
void Load();
void LoadBlockEntries();
void ParseBlockGroup(long long, long long, size_t);
void ParseSimpleBlock(long long, long long, size_t);
};
class Segment
{
friend class Cues;
Segment(const Segment&);
Segment& operator=(const Segment&);
private:
Segment(IMkvReader*, long long pos, long long size);
public:
IMkvReader* const m_pReader;
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 (splitter)
long long Unparsed() const;
long long ParseHeaders(); //stops when first cluster is found
long LoadCluster(); //loads one cluster
#if 0
//This pair parses one cluster, but only changes the state of the
//segment object when the cluster is actually added to the index.
long ParseCluster(Cluster*&, long long& newpos) const;
bool AddCluster(Cluster*, long long);
#endif
Tracks* GetTracks() const;
const SegmentInfo* GetInfo() const;
const Cues* GetCues() const;
long long GetDuration() const;
unsigned long GetCount() const;
Cluster* GetFirst();
Cluster* GetLast();
Cluster* GetNext(const Cluster*);
Cluster* FindCluster(long long time_nanoseconds);
const BlockEntry* Seek(long long time_nanoseconds, const Track*);
private:
long long m_pos; //absolute file posn; what has been consumed so far
SegmentInfo* m_pInfo;
Tracks* m_pTracks;
Cues* m_pCues;
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
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&);
};
} //end namespace mkvparser
#endif //MKVPARSER_HPP