1 #ifndef MKVPARSER_HPP 2 #define MKVPARSER_HPP 3 4 #include <cstdlib> 5 #include <cstdio> 6 7 namespace mkvparser 8 { 9 10 const int E_FILE_FORMAT_INVALID = -2; 11 const int E_BUFFER_NOT_FULL = -3; 12 13 class IMkvReader 14 { 15 public: 16 virtual int Read(long long position, long length, unsigned char* buffer) = 0; 17 virtual int Length(long long* total, long long* available) = 0; 18 protected: 19 virtual ~IMkvReader(); 20 }; 21 22 long long GetUIntLength(IMkvReader*, long long, long&); 23 long long ReadUInt(IMkvReader*, long long, long&); 24 long long SyncReadUInt(IMkvReader*, long long pos, long long stop, long&); 25 long long UnserializeUInt(IMkvReader*, long long pos, long long size); 26 float Unserialize4Float(IMkvReader*, long long); 27 double Unserialize8Double(IMkvReader*, long long); 28 short Unserialize2SInt(IMkvReader*, long long); 29 signed char Unserialize1SInt(IMkvReader*, long long); 30 bool Match(IMkvReader*, long long&, unsigned long, long long&); 31 bool Match(IMkvReader*, long long&, unsigned long, char*&); 32 bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, 33 size_t *optionalSize = NULL); 34 bool Match(IMkvReader*, long long&, unsigned long, double&); 35 bool Match(IMkvReader*, long long&, unsigned long, short&); 36 37 38 struct EBMLHeader 39 { 40 EBMLHeader(); 41 ~EBMLHeader(); 42 long long m_version; 43 long long m_readVersion; 44 long long m_maxIdLength; 45 long long m_maxSizeLength; 46 char* m_docType; 47 long long m_docTypeVersion; 48 long long m_docTypeReadVersion; 49 50 long long Parse(IMkvReader*, long long&); 51 }; 52 53 54 class Segment; 55 class Track; 56 class Cluster; 57 58 class Block 59 { 60 Block(const Block&); 61 Block& operator=(const Block&); 62 63 public: 64 const long long m_start; 65 const long long m_size; 66 67 Block(long long start, long long size, IMkvReader*); 68 69 unsigned long GetTrackNumber() const; 70 71 long long GetTimeCode(Cluster*) const; //absolute, but not scaled 72 long long GetTime(Cluster*) const; //absolute, and scaled (nanosecond units) 73 bool IsKey() const; 74 void SetKey(bool); 75 76 long GetSize() const; 77 long Read(IMkvReader*, unsigned char*) const; 78 79 private: 80 long long m_track; //Track::Number() 81 short m_timecode; //relative to cluster 82 unsigned char m_flags; 83 long long m_frameOff; 84 long m_frameSize; 85 86 }; 87 88 89 class BlockEntry 90 { 91 BlockEntry(const BlockEntry&); 92 BlockEntry& operator=(const BlockEntry&); 93 94 public: 95 virtual ~BlockEntry(); 96 virtual bool EOS() const = 0; 97 virtual Cluster* GetCluster() const = 0; 98 virtual size_t GetIndex() const = 0; 99 virtual const Block* GetBlock() const = 0; 100 virtual bool IsBFrame() const = 0; 101 102 protected: 103 BlockEntry(); 104 105 }; 106 107 108 class SimpleBlock : public BlockEntry 109 { 110 SimpleBlock(const SimpleBlock&); 111 SimpleBlock& operator=(const SimpleBlock&); 112 113 public: 114 SimpleBlock(Cluster*, size_t, long long start, long long size); 115 116 bool EOS() const; 117 Cluster* GetCluster() const; 118 size_t GetIndex() const; 119 const Block* GetBlock() const; 120 bool IsBFrame() const; 121 122 protected: 123 Cluster* const m_pCluster; 124 const size_t m_index; 125 Block m_block; 126 127 }; 128 129 130 class BlockGroup : public BlockEntry 131 { 132 BlockGroup(const BlockGroup&); 133 BlockGroup& operator=(const BlockGroup&); 134 135 public: 136 BlockGroup(Cluster*, size_t, long long, long long); 137 ~BlockGroup(); 138 139 bool EOS() const; 140 Cluster* GetCluster() const; 141 size_t GetIndex() const; 142 const Block* GetBlock() const; 143 bool IsBFrame() const; 144 145 short GetPrevTimeCode() const; //relative to block's time 146 short GetNextTimeCode() const; //as above 147 148 protected: 149 Cluster* const m_pCluster; 150 const size_t m_index; 151 152 private: 153 BlockGroup(Cluster*, size_t, unsigned long); 154 void ParseBlock(long long start, long long size); 155 156 short m_prevTimeCode; 157 short m_nextTimeCode; 158 159 //TODO: the Matroska spec says you can have multiple blocks within the 160 //same block group, with blocks ranked by priority (the flag bits). 161 //For now we just cache a single block. 162 #if 0 163 typedef std::deque<Block*> blocks_t; 164 blocks_t m_blocks; //In practice should contain only a single element. 165 #else 166 Block* m_pBlock; 167 #endif 168 169 }; 170 171 172 class Track 173 { 174 Track(const Track&); 175 Track& operator=(const Track&); 176 177 public: 178 Segment* const m_pSegment; 179 virtual ~Track(); 180 181 long long GetType() const; 182 unsigned long GetNumber() const; 183 const char* GetNameAsUTF8() const; 184 const char* GetCodecNameAsUTF8() const; 185 const char* GetCodecId() const; 186 const unsigned char* GetCodecPrivate( 187 size_t *optionalSize = NULL) const; 188 189 const BlockEntry* GetEOS() const; 190 191 struct Settings 192 { 193 long long start; 194 long long size; 195 }; 196 197 struct Info 198 { 199 long long type; 200 long long number; 201 long long uid; 202 char* nameAsUTF8; 203 char* codecId; 204 unsigned char* codecPrivate; 205 size_t codecPrivateSize; 206 char* codecNameAsUTF8; 207 Settings settings; 208 Info(); 209 void Clear(); 210 }; 211 212 long GetFirst(const BlockEntry*&) const; 213 long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; 214 virtual bool VetEntry(const BlockEntry*) const = 0; 215 216 protected: 217 Track(Segment*, const Info&); 218 const Info m_info; 219 220 class EOSBlock : public BlockEntry 221 { 222 public: 223 EOSBlock(); 224 225 bool EOS() const; 226 Cluster* GetCluster() const; 227 size_t GetIndex() const; 228 const Block* GetBlock() const; 229 bool IsBFrame() const; 230 }; 231 232 EOSBlock m_eos; 233 234 }; 235 236 237 class VideoTrack : public Track 238 { 239 VideoTrack(const VideoTrack&); 240 VideoTrack& operator=(const VideoTrack&); 241 242 public: 243 VideoTrack(Segment*, const Info&); 244 long long GetWidth() const; 245 long long GetHeight() const; 246 double GetFrameRate() const; 247 248 bool VetEntry(const BlockEntry*) const; 249 250 private: 251 long long m_width; 252 long long m_height; 253 double m_rate; 254 255 }; 256 257 258 class AudioTrack : public Track 259 { 260 AudioTrack(const AudioTrack&); 261 AudioTrack& operator=(const AudioTrack&); 262 263 public: 264 AudioTrack(Segment*, const Info&); 265 double GetSamplingRate() const; 266 long long GetChannels() const; 267 long long GetBitDepth() const; 268 bool VetEntry(const BlockEntry*) const; 269 270 private: 271 double m_rate; 272 long long m_channels; 273 long long m_bitDepth; 274 }; 275 276 277 class Tracks 278 { 279 Tracks(const Tracks&); 280 Tracks& operator=(const Tracks&); 281 282 public: 283 Segment* const m_pSegment; 284 const long long m_start; 285 const long long m_size; 286 287 Tracks(Segment*, long long start, long long size); 288 virtual ~Tracks(); 289 290 Track* GetTrackByNumber(unsigned long tn) const; 291 Track* GetTrackByIndex(unsigned long idx) const; 292 293 private: 294 Track** m_trackEntries; 295 Track** m_trackEntriesEnd; 296 297 void ParseTrackEntry(long long, long long, Track*&); 298 299 public: 300 unsigned long GetTracksCount() const; 301 }; 302 303 304 class SegmentInfo 305 { 306 SegmentInfo(const SegmentInfo&); 307 SegmentInfo& operator=(const SegmentInfo&); 308 309 public: 310 Segment* const m_pSegment; 311 const long long m_start; 312 const long long m_size; 313 314 SegmentInfo(Segment*, long long start, long long size); 315 ~SegmentInfo(); 316 long long GetTimeCodeScale() const; 317 long long GetDuration() const; //scaled 318 const char* GetMuxingAppAsUTF8() const; 319 const char* GetWritingAppAsUTF8() const; 320 const char* GetTitleAsUTF8() const; 321 322 private: 323 long long m_timecodeScale; 324 double m_duration; 325 char* m_pMuxingAppAsUTF8; 326 char* m_pWritingAppAsUTF8; 327 char* m_pTitleAsUTF8; 328 }; 329 330 331 class Cluster 332 { 333 Cluster(const Cluster&); 334 Cluster& operator=(const Cluster&); 335 336 public: 337 Segment* const m_pSegment; 338 const size_t m_index; 339 340 public: 341 static Cluster* Parse(Segment*, size_t, long long off); 342 343 Cluster(); //EndOfStream 344 ~Cluster(); 345 346 bool EOS() const; 347 348 long long GetTimeCode(); //absolute, but not scaled 349 long long GetTime(); //absolute, and scaled (nanosecond units) 350 351 const BlockEntry* GetFirst(); 352 const BlockEntry* GetLast(); 353 const BlockEntry* GetNext(const BlockEntry*) const; 354 const BlockEntry* GetEntry(const Track*); 355 protected: 356 Cluster(Segment*, size_t, long long off); 357 358 private: 359 long long m_start; 360 long long m_size; 361 long long m_timecode; 362 BlockEntry** m_pEntries; 363 size_t m_entriesCount; 364 365 void Load(); 366 void LoadBlockEntries(); 367 void ParseBlockGroup(long long, long long, size_t); 368 void ParseSimpleBlock(long long, long long, size_t); 369 370 }; 371 372 373 class Segment 374 { 375 Segment(const Segment&); 376 Segment& operator=(const Segment&); 377 378 private: 379 Segment(IMkvReader*, long long pos, long long size); 380 381 public: 382 IMkvReader* const m_pReader; 383 const long long m_start; //posn of segment payload 384 const long long m_size; //size of segment payload 385 Cluster m_eos; //TODO: make private? 386 387 static long long CreateInstance(IMkvReader*, long long, Segment*&); 388 ~Segment(); 389 390 //for big-bang loading (source filter) 391 long Load(); 392 393 //for incremental loading (splitter) 394 long long Unparsed() const; 395 long long ParseHeaders(); 396 long ParseCluster(Cluster*&, long long& newpos) const; 397 bool AddCluster(Cluster*, long long); 398 399 Tracks* GetTracks() const; 400 const SegmentInfo* const GetInfo() const; 401 long long GetDuration() const; 402 403 //NOTE: this turned out to be too inefficient. 404 //long long Load(long long time_nanoseconds); 405 406 Cluster* GetFirst(); 407 Cluster* GetLast(); 408 unsigned long GetCount() const; 409 410 Cluster* GetNext(const Cluster*); 411 Cluster* GetCluster(long long time_nanoseconds); 412 413 private: 414 long long m_pos; //absolute file posn; what has been consumed so far 415 SegmentInfo* m_pInfo; 416 Tracks* m_pTracks; 417 Cluster** m_clusters; 418 size_t m_clusterCount; 419 420 void ParseSeekHead(long long pos, long long size, size_t*); 421 void ParseSeekEntry(long long pos, long long size, size_t*); 422 void ParseSecondarySeekHead(long long off, size_t*); 423 }; 424 425 426 } //end namespace mkvparser 427 428 #endif //MKVPARSER_HPP 429