MatroskaFileParser Class Reference

#include <MatroskaFileParser.hh>

Inheritance diagram for MatroskaFileParser:

Inheritance graph
[legend]
Collaboration diagram for MatroskaFileParser:

Collaboration graph
[legend]

Public Member Functions

 MatroskaFileParser (MatroskaFile &ourFile, FramedSource *inputSource, FramedSource::onCloseFunc *onEndFunc, void *onEndClientData, MatroskaDemux *ourDemux=NULL)
virtual ~MatroskaFileParser ()
void seekToTime (double &seekNPT)
void continueParsing ()
virtual void flushInput ()

Static Public Member Functions

static void continueParsing (void *clientData, unsigned char *ptr, unsigned size, struct timeval presentationTime)

Protected Types

typedef void( clientContinueFunc )(void *clientData, unsigned char *ptr, unsigned size, struct timeval presentationTime)

Protected Member Functions

void saveParserState ()
u_int32_t get4Bytes ()
u_int32_t test4Bytes ()
u_int16_t get2Bytes ()
u_int8_t get1Byte ()
void getBytes (u_int8_t *to, unsigned numBytes)
void testBytes (u_int8_t *to, unsigned numBytes)
void skipBytes (unsigned numBytes)
void skipBits (unsigned numBits)
unsigned getBits (unsigned numBits)
unsigned curOffset () const
unsigned & totNumValidBytes ()
Boolean haveSeenEOF () const
unsigned bankSize () const

Private Member Functions

Boolean parse ()
Boolean parseStartOfFile ()
void lookForNextTrack ()
Boolean parseTrack ()
Boolean parseCues ()
void lookForNextBlock ()
void parseBlock ()
Boolean deliverFrameWithinBlock ()
void deliverFrameBytes ()
void getCommonFrameBytes (MatroskaTrack *track, u_int8_t *to, unsigned numBytesToGet, unsigned numBytesToSkip)
Boolean parseEBMLNumber (EBMLNumber &num)
Boolean parseEBMLIdAndSize (EBMLId &id, EBMLDataSize &size)
Boolean parseEBMLVal_unsigned64 (EBMLDataSize &size, u_int64_t &result)
Boolean parseEBMLVal_unsigned (EBMLDataSize &size, unsigned &result)
Boolean parseEBMLVal_float (EBMLDataSize &size, float &result)
Boolean parseEBMLVal_string (EBMLDataSize &size, char *&result)
Boolean parseEBMLVal_binary (EBMLDataSize &size, u_int8_t *&result)
void skipHeader (EBMLDataSize const &size)
void setParseState ()
void seekToFilePosition (u_int64_t offsetInFile)
void seekToEndOfFile ()
void resetStateAfterSeeking ()
virtual void restoreSavedParserState ()

Private Attributes

MatroskaFilefOurFile
FramedSourcefInputSource
FramedSource::onCloseFuncfOnEndFunc
void * fOnEndClientData
MatroskaDemuxfOurDemux
MatroskaParseState fCurrentParseState
u_int64_t fCurOffsetInFile
u_int64_t fSavedCurOffsetInFile
u_int64_t fLimitOffsetInFile
EBMLId fLastSeekId
unsigned fClusterTimecode
unsigned fBlockSize
unsigned fBlockTrackNumber
short fBlockTimecode
unsigned fNumFramesInBlock
unsigned * fFrameSizesWithinBlock
double fPresentationTimeOffset
unsigned fNextFrameNumberToDeliver
unsigned fCurOffsetWithinFrame
unsigned fSavedCurOffsetWithinFrame
u_int8_t * fCurFrameTo
unsigned fCurFrameNumBytesToGet
unsigned fCurFrameNumBytesToSkip

Detailed Description

Definition at line 46 of file MatroskaFileParser.hh.


Member Typedef Documentation

typedef void( StreamParser::clientContinueFunc)(void *clientData, unsigned char *ptr, unsigned size, struct timeval presentationTime) [protected, inherited]

Definition at line 33 of file StreamParser.hh.


Constructor & Destructor Documentation

MatroskaFileParser::MatroskaFileParser ( MatroskaFile ourFile,
FramedSource inputSource,
FramedSource::onCloseFunc onEndFunc,
void *  onEndClientData,
MatroskaDemux ourDemux = NULL 
)

Definition at line 26 of file MatroskaFileParser.cpp.

References continueParsing(), fCurrentParseState, LOOKING_FOR_CLUSTER, NULL, and PARSING_START_OF_FILE.

00029   : StreamParser(inputSource, onEndFunc, onEndClientData, continueParsing, this),
00030     fOurFile(ourFile), fInputSource(inputSource),
00031     fOnEndFunc(onEndFunc), fOnEndClientData(onEndClientData),
00032     fOurDemux(ourDemux),
00033     fCurOffsetInFile(0), fSavedCurOffsetInFile(0), fLimitOffsetInFile(0),
00034     fClusterTimecode(0), fBlockTimecode(0),
00035     fFrameSizesWithinBlock(NULL),
00036     fPresentationTimeOffset(0.0) {
00037   if (ourDemux == NULL) {
00038     // Initialization
00039     fCurrentParseState = PARSING_START_OF_FILE;
00040     continueParsing();
00041   } else {
00042     fCurrentParseState = LOOKING_FOR_CLUSTER;
00043     // In this case, parsing (of track data) doesn't start until a client starts reading from a track.
00044   }
00045 }

MatroskaFileParser::~MatroskaFileParser (  )  [virtual]

Definition at line 47 of file MatroskaFileParser.cpp.

References Medium::close(), fFrameSizesWithinBlock, and fInputSource.

00047                                         {
00048   delete[] fFrameSizesWithinBlock;
00049   Medium::close(fInputSource);
00050 }


Member Function Documentation

void MatroskaFileParser::seekToTime ( double &  seekNPT  ) 

Definition at line 52 of file MatroskaFileParser.cpp.

References fCurrentParseState, MatroskaFile::fileDuration(), fOurFile, LOOKING_FOR_BLOCK, MatroskaFile::lookupCuePoint(), seekToEndOfFile(), and seekToFilePosition().

Referenced by MatroskaDemux::seekToTime().

00052                                                    {
00053 #ifdef DEBUG
00054   fprintf(stderr, "seekToTime(%f)\n", seekNPT);
00055 #endif
00056   if (seekNPT <= 0.0) {
00057 #ifdef DEBUG
00058     fprintf(stderr, "\t=> start of file\n");
00059 #endif
00060     seekNPT = 0.0;
00061     seekToFilePosition(0);
00062   } else if (seekNPT >= fOurFile.fileDuration()) {
00063 #ifdef DEBUG
00064     fprintf(stderr, "\t=> end of file\n");
00065 #endif
00066     seekNPT = fOurFile.fileDuration();
00067     seekToEndOfFile();
00068   } else {
00069     u_int64_t clusterOffsetInFile;
00070     unsigned blockNumWithinCluster;
00071     if (!fOurFile.lookupCuePoint(seekNPT, clusterOffsetInFile, blockNumWithinCluster)) {
00072 #ifdef DEBUG
00073       fprintf(stderr, "\t=> not supported\n");
00074 #endif
00075       return; // seeking not supported
00076     }
00077 
00078 #ifdef DEBUG
00079     fprintf(stderr, "\t=> seek time %f, file position %llu, block number within cluster %d\n", seekNPT, clusterOffsetInFile, blockNumWithinCluster);
00080 #endif
00081     seekToFilePosition(clusterOffsetInFile);
00082     fCurrentParseState = LOOKING_FOR_BLOCK;
00083     // LATER handle "blockNumWithinCluster"; for now, we assume that it's 0 #####
00084   }
00085 }

void MatroskaFileParser::continueParsing ( void *  clientData,
unsigned char *  ptr,
unsigned  size,
struct timeval  presentationTime 
) [static]

Definition at line 88 of file MatroskaFileParser.cpp.

Referenced by MatroskaDemux::continueReading().

00088                                                                                                                   {
00089   ((MatroskaFileParser*)clientData)->continueParsing();
00090 }

void MatroskaFileParser::continueParsing (  ) 

Definition at line 92 of file MatroskaFileParser.cpp.

References fInputSource, fOnEndClientData, fOnEndFunc, FramedSource::isCurrentlyAwaitingData(), NULL, and parse().

Referenced by MatroskaFileParser().

00092                                          {
00093   if (fInputSource != NULL) {
00094     if (fInputSource->isCurrentlyAwaitingData()) return; // Our input source is currently being read. Wait until that read completes
00095 
00096     if (!parse()) {
00097       // We didn't complete the parsing, because we had to read more data from the source, or because we're waiting for
00098       // another read from downstream.  Once that happens, we'll get called again.
00099       return;
00100     }
00101   }
00102 
00103   // We successfully parsed the file's 'Track' headers (or else there was no input source, because the specified file name
00104   // didn't exist).  Call our 'done' function now:
00105   if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData);
00106 }

Boolean MatroskaFileParser::parse (  )  [private]

Definition at line 108 of file MatroskaFileParser.cpp.

References deliverFrameBytes(), deliverFrameWithinBlock(), DELIVERING_FRAME_BYTES, DELIVERING_FRAME_WITHIN_BLOCK, False, MatroskaFile::fClusterOffset, MatroskaFile::fCuesOffset, fCurrentParseState, fOurFile, lookForNextBlock(), lookForNextTrack(), LOOKING_FOR_BLOCK, LOOKING_FOR_CLUSTER, LOOKING_FOR_TRACKS, parseBlock(), parseCues(), parseStartOfFile(), parseTrack(), PARSING_BLOCK, PARSING_CUES, PARSING_START_OF_FILE, PARSING_TRACK, seekToFilePosition(), and True.

Referenced by continueParsing().

00108                                   {
00109   Boolean areDone = False;
00110 
00111   try {
00112     do {
00113       switch (fCurrentParseState) {
00114         case PARSING_START_OF_FILE: {
00115           areDone = parseStartOfFile();
00116           break;
00117         }
00118         case LOOKING_FOR_TRACKS: {
00119           lookForNextTrack();
00120           break;
00121         }
00122         case PARSING_TRACK: {
00123           areDone = parseTrack();
00124           if (areDone && fOurFile.fCuesOffset > 0) {
00125             // We've finished parsing the 'Track' information.  There are also 'Cues' in the file, so parse those before finishing:
00126             // Seek to the specified position in the file.  We were already told that the 'Cues' begins there:
00127 #ifdef DEBUG
00128             fprintf(stderr, "Seeking to file position %llu (the previously-reported location of 'Cues')\n", fOurFile.fCuesOffset);
00129 #endif
00130             seekToFilePosition(fOurFile.fCuesOffset);
00131             fCurrentParseState = PARSING_CUES;
00132             areDone = False;
00133           }
00134           break;
00135         }
00136         case PARSING_CUES: {
00137           areDone = parseCues();
00138           break;
00139         }
00140         case LOOKING_FOR_CLUSTER: {
00141           if (fOurFile.fClusterOffset > 0) {
00142             // Optimization: Seek to the specified position in the file.  We were already told that the 'Cluster' begins there:
00143 #ifdef DEBUG
00144             fprintf(stderr, "Optimization: Seeking to file position %llu (the previously-reported location of a 'Cluster')\n", fOurFile.fClusterOffset);
00145 #endif
00146             seekToFilePosition(fOurFile.fClusterOffset);
00147           }
00148           fCurrentParseState = LOOKING_FOR_BLOCK;
00149           break;
00150         }
00151         case LOOKING_FOR_BLOCK: {
00152           lookForNextBlock();
00153           break;
00154         }
00155         case PARSING_BLOCK: {
00156           parseBlock();
00157           break;
00158         }
00159         case DELIVERING_FRAME_WITHIN_BLOCK: {
00160           if (!deliverFrameWithinBlock()) return False;
00161           break;
00162         }
00163         case DELIVERING_FRAME_BYTES: {
00164           deliverFrameBytes();
00165           return False; // Halt parsing for now.  A new 'read' from downstream will cause parsing to resume.
00166           break;
00167         }
00168       }
00169     } while (!areDone);
00170 
00171     return True;
00172   } catch (int /*e*/) {
00173 #ifdef DEBUG
00174     fprintf(stderr, "MatroskaFileParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00175 #endif
00176     return False;  // the parsing got interrupted
00177   }
00178 }

Boolean MatroskaFileParser::parseStartOfFile (  )  [private]

Definition at line 180 of file MatroskaFileParser.cpp.

References Medium::envir(), False, fCurrentParseState, fOurFile, LOOKING_FOR_TRACKS, MATROSKA_ID_EBML, parseEBMLIdAndSize(), size, skipHeader(), and True.

Referenced by parse().

00180                                              {
00181 #ifdef DEBUG
00182   fprintf(stderr, "parsing start of file\n");
00183 #endif
00184   EBMLId id;
00185   EBMLDataSize size;
00186 
00187   // The file must begin with the standard EBML header (which we skip):
00188   if (!parseEBMLIdAndSize(id, size) || id != MATROSKA_ID_EBML) {
00189     fOurFile.envir() << "ERROR: FIle does not begin with an EBML header\n";
00190     return True; // We're done with the file, because it's not valid
00191   }
00192   skipHeader(size);
00193 
00194   fCurrentParseState = LOOKING_FOR_TRACKS;
00195   return False; // because we have more parsing to do - inside the 'Track' header
00196 }

void MatroskaFileParser::lookForNextTrack (  )  [private]

Definition at line 198 of file MatroskaFileParser.cpp.

References MatroskaFile::fClusterOffset, MatroskaFile::fCuesOffset, fCurOffsetInFile, fCurrentParseState, MatroskaFile::fileDuration(), fLastSeekId, fLimitOffsetInFile, fOurFile, MatroskaFile::fSegmentDataOffset, MatroskaFile::fSegmentDuration, MatroskaFile::fTimecodeScale, EBMLNumber::hexString(), LOOKING_FOR_TRACKS, MATROSKA_ID_CLUSTER, MATROSKA_ID_CUES, MATROSKA_ID_DURATION, MATROSKA_ID_INFO, MATROSKA_ID_SEEK, MATROSKA_ID_SEEK_HEAD, MATROSKA_ID_SEEK_ID, MATROSKA_ID_SEEK_POSITION, MATROSKA_ID_SEGMENT, MATROSKA_ID_TIMECODE_SCALE, MATROSKA_ID_TRACKS, parseEBMLIdAndSize(), parseEBMLNumber(), parseEBMLVal_float(), parseEBMLVal_unsigned(), parseEBMLVal_unsigned64(), PARSING_TRACK, MatroskaFile::segmentDuration(), setParseState(), size, skipHeader(), EBMLId::stringName(), and MatroskaFile::timecodeScale().

Referenced by parse().

00198                                           {
00199 #ifdef DEBUG
00200   fprintf(stderr, "looking for Track\n");
00201 #endif
00202   EBMLId id;
00203   EBMLDataSize size;
00204 
00205   // Read and skip over (or enter) each Matroska header, until we get to a 'Track'.
00206   while (fCurrentParseState == LOOKING_FOR_TRACKS) {
00207     while (!parseEBMLIdAndSize(id, size)) {}
00208 #ifdef DEBUG
00209     fprintf(stderr, "MatroskaFileParser::lookForNextTrack(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
00210 #endif
00211     switch (id.val()) {
00212       case MATROSKA_ID_SEGMENT: { // 'Segment' header: enter this
00213         // Remember the position, within the file, of the start of Segment data, because Seek Positions are relative to this:
00214         fOurFile.fSegmentDataOffset = fCurOffsetInFile;
00215         break;
00216       }
00217       case MATROSKA_ID_SEEK_HEAD: { // 'Seek Head' header: enter this
00218         break;
00219       }
00220       case MATROSKA_ID_SEEK: { // 'Seek' header: enter this
00221         break;
00222       }
00223       case MATROSKA_ID_SEEK_ID: { // 'Seek ID' header: get this value
00224         if (parseEBMLNumber(fLastSeekId)) {
00225 #ifdef DEBUG
00226           fprintf(stderr, "\tSeek ID 0x%s:\t%s\n", fLastSeekId.hexString(), fLastSeekId.stringName());
00227 #endif
00228         }
00229         break;
00230       }
00231       case MATROSKA_ID_SEEK_POSITION: { // 'Seek Position' header: get this value
00232         u_int64_t seekPosition;
00233         if (parseEBMLVal_unsigned64(size, seekPosition)) {
00234           u_int64_t offsetInFile = fOurFile.fSegmentDataOffset + seekPosition;
00235 #ifdef DEBUG
00236           fprintf(stderr, "\tSeek Position %llu (=> offset within the file: %llu (0x%llx))\n", seekPosition, offsetInFile, offsetInFile);
00237 #endif
00238           // The only 'Seek Position's that we care about are for 'Cluster' and 'Cues':
00239           if (fLastSeekId == MATROSKA_ID_CLUSTER) {
00240             fOurFile.fClusterOffset = offsetInFile;
00241           } else if (fLastSeekId == MATROSKA_ID_CUES) {
00242             fOurFile.fCuesOffset = offsetInFile;
00243           }
00244         }
00245         break;
00246       }
00247       case MATROSKA_ID_INFO: { // 'Segment Info' header: enter this
00248         break;
00249       }
00250       case MATROSKA_ID_TIMECODE_SCALE: { // 'Timecode Scale' header: get this value
00251         unsigned timecodeScale;
00252         if (parseEBMLVal_unsigned(size, timecodeScale) && timecodeScale > 0) {
00253           fOurFile.fTimecodeScale = timecodeScale;
00254 #ifdef DEBUG
00255           fprintf(stderr, "\tTimecode Scale %u ns (=> Segment Duration == %f seconds)\n", fOurFile.timecodeScale(), fOurFile.fileDuration());
00256 #endif
00257         }
00258         break;
00259       }
00260       case MATROSKA_ID_DURATION: { // 'Segment Duration' header: get this value
00261         if (parseEBMLVal_float(size, fOurFile.fSegmentDuration)) {
00262 #ifdef DEBUG
00263           fprintf(stderr, "\tSegment Duration %f (== %f seconds)\n", fOurFile.segmentDuration(), fOurFile.fileDuration());
00264 #endif
00265         }
00266         break;
00267       }
00268       case MATROSKA_ID_TRACKS: { // enter this, and move on to parsing 'Tracks'
00269         fLimitOffsetInFile = fCurOffsetInFile + size.val(); // Make sure we don't read past the end of this header
00270         fCurrentParseState = PARSING_TRACK;
00271         break;
00272       }
00273       default: { // skip over this header
00274         skipHeader(size);
00275 #ifdef DEBUG
00276         fprintf(stderr, "\tskipped %lld bytes\n", size.val());
00277 #endif
00278         break;
00279       }
00280     }
00281     setParseState();
00282   }
00283 }

Boolean MatroskaFileParser::parseTrack (  )  [private]

Definition at line 285 of file MatroskaFileParser.cpp.

References MatroskaTrack::codecID, MatroskaTrack::codecPrivate, MatroskaTrack::codecPrivateSize, MatroskaTrack::defaultDuration, False, fCurOffsetInFile, fLimitOffsetInFile, fOurFile, MatroskaFile::fTracks, MatroskaTrack::headerStrippedBytes, MatroskaTrack::headerStrippedBytesSize, MatroskaTrack::isDefault, MatroskaTrack::isEnabled, MatroskaTrack::isForced, MatroskaTrack::language, MATROSKA_ID_AUDIO, MATROSKA_ID_CHANNELS, MATROSKA_ID_CODEC, MATROSKA_ID_CODEC_PRIVATE, MATROSKA_ID_CONTENT_COMP_ALGO, MATROSKA_ID_CONTENT_COMP_SETTINGS, MATROSKA_ID_CONTENT_COMPRESSION, MATROSKA_ID_CONTENT_ENCODING, MATROSKA_ID_CONTENT_ENCODINGS, MATROSKA_ID_CONTENT_ENCRYPTION, MATROSKA_ID_DEFAULT_DURATION, MATROSKA_ID_DISPLAY_HEIGHT, MATROSKA_ID_DISPLAY_WIDTH, MATROSKA_ID_FLAG_DEFAULT, MATROSKA_ID_FLAG_ENABLED, MATROSKA_ID_FLAG_FORCED, MATROSKA_ID_LANGUAGE, MATROSKA_ID_MAX_BLOCK_ADDITION_ID, MATROSKA_ID_NAME, MATROSKA_ID_OUTPUT_SAMPLING_FREQUENCY, MATROSKA_ID_PIXEL_HEIGHT, MATROSKA_ID_PIXEL_WIDTH, MATROSKA_ID_SAMPLING_FREQUENCY, MATROSKA_ID_TRACK_ENTRY, MATROSKA_ID_TRACK_NUMBER, MATROSKA_ID_TRACK_TYPE, MATROSKA_ID_VIDEO, MATROSKA_TRACK_TYPE_AUDIO, MATROSKA_TRACK_TYPE_OTHER, MATROSKA_TRACK_TYPE_SUBTITLE, MATROSKA_TRACK_TYPE_VIDEO, MatroskaTrack::name, NULL, MatroskaTrack::numChannels, parseEBMLIdAndSize(), parseEBMLVal_binary(), parseEBMLVal_float(), parseEBMLVal_string(), parseEBMLVal_unsigned(), MatroskaTrack::samplingFrequency, setParseState(), size, skipHeader(), MatroskaTrack::trackNumber, MatroskaTrack::trackType, and True.

Referenced by parse().

00285                                        {
00286 #ifdef DEBUG
00287   fprintf(stderr, "parsing Track\n");
00288 #endif
00289   // Read and process each Matroska header, until we get to the end of the Track:
00290   MatroskaTrack* track = NULL;
00291   EBMLId id;
00292   EBMLDataSize size;
00293   while (fCurOffsetInFile < fLimitOffsetInFile) {
00294     while (!parseEBMLIdAndSize(id, size)) {}
00295 #ifdef DEBUG
00296     if (id == MATROSKA_ID_TRACK_ENTRY) fprintf(stderr, "\n"); // makes debugging output easier to read
00297     fprintf(stderr, "MatroskaFileParser::parseTrack(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
00298 #endif
00299     switch (id.val()) {
00300       case MATROSKA_ID_TRACK_ENTRY: { // 'Track Entry' header: enter this
00301         // Create a new "MatroskaTrack" object for this entry:
00302         if (track != NULL && track->trackNumber == 0) delete track; // We had a previous "MatroskaTrack" object that was never used
00303         track = new MatroskaTrack;
00304         break;
00305       }
00306       case MATROSKA_ID_TRACK_NUMBER: {
00307         unsigned trackNumber;
00308         if (parseEBMLVal_unsigned(size, trackNumber)) {
00309 #ifdef DEBUG
00310           fprintf(stderr, "\tTrack Number %d\n", trackNumber);
00311 #endif
00312           if (track != NULL && trackNumber != 0) {
00313             track->trackNumber = trackNumber;
00314             fOurFile.fTracks.add(track, trackNumber);
00315           }
00316         }
00317         break;
00318       }
00319       case MATROSKA_ID_TRACK_TYPE: {
00320         unsigned trackType;
00321         if (parseEBMLVal_unsigned(size, trackType) && track != NULL) {
00322           // We convert the Matroska 'track type' code into our own code (which we can use as a bitmap):
00323           track->trackType
00324             = trackType == 1 ? MATROSKA_TRACK_TYPE_VIDEO : trackType == 2 ? MATROSKA_TRACK_TYPE_AUDIO
00325             : trackType == 0x11 ? MATROSKA_TRACK_TYPE_SUBTITLE : MATROSKA_TRACK_TYPE_OTHER;
00326 #ifdef DEBUG
00327           fprintf(stderr, "\tTrack Type 0x%02x (%s)\n", trackType,
00328                   track->trackType == MATROSKA_TRACK_TYPE_VIDEO ? "video" :
00329                   track->trackType == MATROSKA_TRACK_TYPE_AUDIO ? "audio" :
00330                   track->trackType == MATROSKA_TRACK_TYPE_SUBTITLE ? "subtitle" :
00331                   "<other>");
00332 #endif
00333         }
00334         break;
00335       }
00336       case MATROSKA_ID_FLAG_ENABLED: {
00337         unsigned flagEnabled;
00338         if (parseEBMLVal_unsigned(size, flagEnabled)) {
00339 #ifdef DEBUG
00340           fprintf(stderr, "\tTrack is Enabled: %d\n", flagEnabled);
00341 #endif
00342           if (track != NULL) track->isEnabled = flagEnabled != 0;
00343         }
00344         break;
00345       }
00346       case MATROSKA_ID_FLAG_DEFAULT: {
00347         unsigned flagDefault;
00348         if (parseEBMLVal_unsigned(size, flagDefault)) {
00349 #ifdef DEBUG
00350           fprintf(stderr, "\tTrack is Default: %d\n", flagDefault);
00351 #endif
00352           if (track != NULL) track->isDefault = flagDefault != 0;
00353         }
00354         break;
00355       }
00356       case MATROSKA_ID_FLAG_FORCED: {
00357         unsigned flagForced;
00358         if (parseEBMLVal_unsigned(size, flagForced)) {
00359 #ifdef DEBUG
00360           fprintf(stderr, "\tTrack is Forced: %d\n", flagForced);
00361 #endif
00362           if (track != NULL) track->isForced = flagForced != 0;
00363         }
00364         break;
00365       }
00366       case MATROSKA_ID_DEFAULT_DURATION: {
00367         unsigned defaultDuration;
00368         if (parseEBMLVal_unsigned(size, defaultDuration)) {
00369 #ifdef DEBUG
00370           fprintf(stderr, "\tDefault duration %f ms\n", defaultDuration/1000000.0);
00371 #endif
00372           if (track != NULL) track->defaultDuration = defaultDuration;
00373         }
00374         break;
00375       }
00376       case MATROSKA_ID_MAX_BLOCK_ADDITION_ID: {
00377         unsigned maxBlockAdditionID;
00378         if (parseEBMLVal_unsigned(size, maxBlockAdditionID)) {
00379 #ifdef DEBUG
00380           fprintf(stderr, "\tMax Block Addition ID: %u\n", maxBlockAdditionID);
00381 #endif
00382         }
00383         break;
00384       }
00385       case MATROSKA_ID_NAME: {
00386         char* name;
00387         if (parseEBMLVal_string(size, name)) {
00388 #ifdef DEBUG
00389           fprintf(stderr, "\tName: %s\n", name);
00390 #endif
00391           if (track != NULL) {
00392             delete[] track->name; track->name = name;
00393           } else {
00394             delete[] name;
00395           }
00396         }
00397         break;
00398       }
00399       case MATROSKA_ID_LANGUAGE: {
00400         char* language;
00401         if (parseEBMLVal_string(size, language)) {
00402 #ifdef DEBUG
00403           fprintf(stderr, "\tLanguage: %s\n", language);
00404 #endif
00405           if (track != NULL) {
00406             delete[] track->language; track->language = language;
00407           } else {
00408             delete[] language;
00409           }
00410         }
00411         break;
00412       }
00413       case MATROSKA_ID_CODEC: {
00414         char* codecID;
00415         if (parseEBMLVal_string(size, codecID)) {
00416 #ifdef DEBUG
00417           fprintf(stderr, "\tCodec ID: %s\n", codecID);
00418 #endif
00419           if (track != NULL) {
00420             delete[] track->codecID; track->codecID = codecID;
00421           } else {
00422             delete[] codecID;
00423           }
00424         }
00425         break;
00426       }
00427       case MATROSKA_ID_CODEC_PRIVATE: {
00428         u_int8_t* codecPrivate;
00429         unsigned codecPrivateSize;
00430         if (parseEBMLVal_binary(size, codecPrivate)) {
00431           codecPrivateSize = (unsigned)size.val();
00432 #ifdef DEBUG
00433           fprintf(stderr, "\tCodec Private: ");
00434           for (unsigned i = 0; i < codecPrivateSize; ++i) fprintf(stderr, "%02x:", codecPrivate[i]);
00435           fprintf(stderr, "\n");
00436 #endif
00437           if (track != NULL) {
00438             delete[] track->codecPrivate; track->codecPrivate = codecPrivate;
00439             track->codecPrivateSize = codecPrivateSize;
00440           } else {
00441             delete[] codecPrivate;
00442           }
00443         }
00444         break;
00445       }
00446       case MATROSKA_ID_VIDEO: { // 'Video settings' header: enter this
00447         break;
00448       }
00449       case MATROSKA_ID_PIXEL_WIDTH: {
00450         unsigned pixelWidth;
00451         if (parseEBMLVal_unsigned(size, pixelWidth)) {
00452 #ifdef DEBUG
00453           fprintf(stderr, "\tPixel Width %d\n", pixelWidth);
00454 #endif
00455         }
00456         break;
00457       }
00458       case MATROSKA_ID_PIXEL_HEIGHT: {
00459         unsigned pixelHeight;
00460         if (parseEBMLVal_unsigned(size, pixelHeight)) {
00461 #ifdef DEBUG
00462           fprintf(stderr, "\tPixel Height %d\n", pixelHeight);
00463 #endif
00464         }
00465         break;
00466       }
00467       case MATROSKA_ID_DISPLAY_WIDTH: {
00468         unsigned displayWidth;
00469         if (parseEBMLVal_unsigned(size, displayWidth)) {
00470 #ifdef DEBUG
00471           fprintf(stderr, "\tDisplay Width %d\n", displayWidth);
00472 #endif
00473         }
00474         break;
00475       }
00476       case MATROSKA_ID_DISPLAY_HEIGHT: {
00477         unsigned displayHeight;
00478         if (parseEBMLVal_unsigned(size, displayHeight)) {
00479 #ifdef DEBUG
00480           fprintf(stderr, "\tDisplay Height %d\n", displayHeight);
00481 #endif
00482         }
00483         break;
00484       }
00485       case MATROSKA_ID_AUDIO: { // 'Audio settings' header: enter this
00486         break;
00487       }
00488       case MATROSKA_ID_SAMPLING_FREQUENCY: {
00489         float samplingFrequency;
00490         if (parseEBMLVal_float(size, samplingFrequency)) {
00491           if (track != NULL) {
00492             track->samplingFrequency = (unsigned)samplingFrequency;
00493 #ifdef DEBUG
00494             fprintf(stderr, "\tSampling frequency %f (->%d)\n", samplingFrequency, track->samplingFrequency);
00495 #endif
00496           }
00497         }
00498         break;
00499       }
00500       case MATROSKA_ID_OUTPUT_SAMPLING_FREQUENCY: {
00501         float outputSamplingFrequency;
00502         if (parseEBMLVal_float(size, outputSamplingFrequency)) {
00503 #ifdef DEBUG
00504           fprintf(stderr, "\tOutput sampling frequency %f\n", outputSamplingFrequency);
00505 #endif
00506         }
00507         break;
00508       }
00509       case MATROSKA_ID_CHANNELS: {
00510         unsigned numChannels;
00511         if (parseEBMLVal_unsigned(size, numChannels)) {
00512 #ifdef DEBUG
00513           fprintf(stderr, "\tChannels %d\n", numChannels);
00514 #endif
00515           if (track != NULL) track->numChannels = numChannels;
00516         }
00517         break;
00518       }
00519       case MATROSKA_ID_CONTENT_ENCODINGS:
00520       case MATROSKA_ID_CONTENT_ENCODING: { // 'Content Encodings' or 'Content Encoding' header: enter this
00521         break;
00522       }
00523       case MATROSKA_ID_CONTENT_COMPRESSION: { // 'Content Compression' header: enter this
00524         // Note: We currently support only 'Header Stripping' compression, not 'zlib' compression (the default algorithm).
00525         // Therefore, we disable this track, unless/until we later see that 'Header Stripping' is supported:
00526         if (track != NULL) track->isEnabled = False;
00527         break;
00528       }
00529       case MATROSKA_ID_CONTENT_COMP_ALGO: {
00530         unsigned contentCompAlgo;
00531         if (parseEBMLVal_unsigned(size, contentCompAlgo)) {
00532 #ifdef DEBUG
00533           fprintf(stderr, "\tContent Compression Algorithm %d (%s)\n", contentCompAlgo,
00534                   contentCompAlgo == 0 ? "zlib" : contentCompAlgo == 3 ? "Header Stripping" : "<unknown>");
00535 #endif
00536           // The only compression algorithm that we support is #3: Header Stripping; disable the track otherwise
00537           if (track != NULL) track->isEnabled = contentCompAlgo == 3;
00538         }
00539         break;
00540       }
00541       case MATROSKA_ID_CONTENT_COMP_SETTINGS: {
00542         u_int8_t* headerStrippedBytes;
00543         unsigned headerStrippedBytesSize;
00544         if (parseEBMLVal_binary(size, headerStrippedBytes)) {
00545           headerStrippedBytesSize = (unsigned)size.val();
00546 #ifdef DEBUG
00547           fprintf(stderr, "\tHeader Stripped Bytes: ");
00548           for (unsigned i = 0; i < headerStrippedBytesSize; ++i) fprintf(stderr, "%02x:", headerStrippedBytes[i]);
00549           fprintf(stderr, "\n");
00550 #endif
00551           if (track != NULL) {
00552             delete[] track->headerStrippedBytes; track->headerStrippedBytes = headerStrippedBytes;
00553             track->headerStrippedBytesSize = headerStrippedBytesSize;
00554           } else {
00555             delete[] headerStrippedBytes;
00556           }
00557         }
00558         break;
00559       }
00560       case MATROSKA_ID_CONTENT_ENCRYPTION: { // 'Content Encrpytion' header: skip this
00561         // Note: We don't currently support encryption at all.  Therefore, we disable this track:
00562         if (track != NULL) track->isEnabled = False;
00563         // Fall through to...
00564       }
00565       default: { // We don't process this header, so just skip over it:
00566         skipHeader(size);
00567 #ifdef DEBUG
00568         fprintf(stderr, "\tskipped %lld bytes\n", size.val());
00569 #endif
00570         break;
00571       }
00572     }
00573     setParseState();
00574   }
00575 
00576   fLimitOffsetInFile = 0; // reset
00577   if (track != NULL && track->trackNumber == 0) delete track; // We had a previous "MatroskaTrack" object that was never used
00578   return True; // we're done parsing track entries
00579 }

Boolean MatroskaFileParser::parseCues (  )  [private]

Definition at line 640 of file MatroskaFileParser.cpp.

References MatroskaFile::addCuePoint(), fCurOffsetInFile, fLimitOffsetInFile, fOurFile, MatroskaFile::fSegmentDataOffset, MatroskaFile::fTimecodeScale, MATROSKA_ID_CUE_BLOCK_NUMBER, MATROSKA_ID_CUE_CLUSTER_POSITION, MATROSKA_ID_CUE_POINT, MATROSKA_ID_CUE_TIME, MATROSKA_ID_CUE_TRACK, MATROSKA_ID_CUE_TRACK_POSITIONS, MATROSKA_ID_CUES, parseEBMLIdAndSize(), parseEBMLVal_unsigned(), parseEBMLVal_unsigned64(), MatroskaFile::printCuePoints(), setParseState(), size, skipHeader(), and True.

Referenced by parse().

00640                                       {
00641 #if defined(DEBUG) || defined(DEBUG_CUES)
00642   fprintf(stderr, "parsing Cues\n");
00643 #endif
00644   EBMLId id;
00645   EBMLDataSize size;
00646 
00647   // Read the next header, which should be MATROSKA_ID_CUES:
00648   if (!parseEBMLIdAndSize(id, size) || id != MATROSKA_ID_CUES) return True; // The header wasn't what we expected, so we're done
00649   fLimitOffsetInFile = fCurOffsetInFile + size.val(); // Make sure we don't read past the end of this header
00650 
00651   double currentCueTime = 0.0;
00652   u_int64_t currentClusterOffsetInFile = 0;
00653 
00654   while (fCurOffsetInFile < fLimitOffsetInFile) {
00655     while (!parseEBMLIdAndSize(id, size)) {}
00656 #ifdef DEBUG_CUES
00657     if (id == MATROSKA_ID_CUE_POINT) fprintf(stderr, "\n"); // makes debugging output easier to read
00658     fprintf(stderr, "MatroskaFileParser::parseCues(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
00659 #endif
00660     switch (id.val()) {
00661       case MATROSKA_ID_CUE_POINT: { // 'Cue Point' header: enter this
00662         break;
00663       }
00664       case MATROSKA_ID_CUE_TIME: { // 'Cue Time' header: get this value
00665         unsigned cueTime;
00666         if (parseEBMLVal_unsigned(size, cueTime)) {
00667           currentCueTime = cueTime*(fOurFile.fTimecodeScale/1000000000.0);
00668 #ifdef DEBUG_CUES
00669           fprintf(stderr, "\tCue Time %d (== %f seconds)\n", cueTime, currentCueTime);
00670 #endif
00671         }
00672         break;
00673       }
00674       case MATROSKA_ID_CUE_TRACK_POSITIONS: { // 'Cue Track Positions' header: enter this
00675         break;
00676       }
00677       case MATROSKA_ID_CUE_TRACK: { // 'Cue Track' header: get this value (but only for debugging; we don't do anything with it)
00678         unsigned cueTrack;
00679         if (parseEBMLVal_unsigned(size, cueTrack)) {
00680 #ifdef DEBUG_CUES
00681           fprintf(stderr, "\tCue Track %d\n", cueTrack);
00682 #endif
00683         }
00684         break;
00685       }
00686       case MATROSKA_ID_CUE_CLUSTER_POSITION: { // 'Cue Cluster Position' header: get this value
00687         u_int64_t cueClusterPosition;
00688         if (parseEBMLVal_unsigned64(size, cueClusterPosition)) {
00689           currentClusterOffsetInFile = fOurFile.fSegmentDataOffset + cueClusterPosition;
00690 #ifdef DEBUG_CUES
00691           fprintf(stderr, "\tCue Cluster Position %llu (=> offset within the file: %llu (0x%llx))\n", cueClusterPosition, currentClusterOffsetInFile, currentClusterOffsetInFile);
00692 #endif
00693           // Record this cue point:
00694           fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, 1/*default block number within cluster*/);
00695         }
00696         break;
00697       }
00698       case MATROSKA_ID_CUE_BLOCK_NUMBER: { // 'Cue Block Number' header: get this value
00699         unsigned cueBlockNumber;
00700         if (parseEBMLVal_unsigned(size, cueBlockNumber) && cueBlockNumber != 0) {
00701 #ifdef DEBUG_CUES
00702           fprintf(stderr, "\tCue Block Number %d\n", cueBlockNumber);
00703 #endif
00704           // Record this cue point (overwriting any existing entry for this cue time):
00705           fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, cueBlockNumber);
00706         }
00707         break;
00708       }
00709       default: { // We don't process this header, so just skip over it:
00710         skipHeader(size);
00711 #ifdef DEBUG_CUES
00712         fprintf(stderr, "\tskipped %lld bytes\n", size.val());
00713 #endif
00714         break;
00715       }
00716     }
00717     setParseState();
00718   }
00719 
00720   fLimitOffsetInFile = 0; // reset
00721 #if defined(DEBUG) || defined(DEBUG_CUES)
00722   fprintf(stderr, "done parsing Cues\n");
00723 #endif
00724 #ifdef DEBUG_CUES
00725   fprintf(stderr, "Cue Point tree: ");
00726   fOurFile.printCuePoints(stderr);
00727   fprintf(stderr, "\n");
00728 #endif
00729   return True; // we're done parsing Cues
00730 }

void MatroskaFileParser::lookForNextBlock (  )  [private]

Definition at line 581 of file MatroskaFileParser.cpp.

References fBlockSize, fClusterTimecode, fCurrentParseState, fOurFile, MatroskaFile::fTimecodeScale, LOOKING_FOR_BLOCK, MATROSKA_ID_BLOCK, MATROSKA_ID_BLOCK_DURATION, MATROSKA_ID_BLOCK_GROUP, MATROSKA_ID_CLUSTER, MATROSKA_ID_SEGMENT, MATROSKA_ID_SIMPLEBLOCK, MATROSKA_ID_TIMECODE, parseEBMLIdAndSize(), parseEBMLVal_unsigned(), PARSING_BLOCK, setParseState(), size, and skipHeader().

Referenced by parse().

00581                                           {
00582 #ifdef DEBUG
00583   fprintf(stderr, "looking for Block\n");
00584 #endif
00585   // Read and skip over each Matroska header, until we get to a 'Cluster':
00586   EBMLId id;
00587   EBMLDataSize size;
00588   while (fCurrentParseState == LOOKING_FOR_BLOCK) {
00589     while (!parseEBMLIdAndSize(id, size)) {}
00590 #ifdef DEBUG
00591     fprintf(stderr, "MatroskaFileParser::lookForNextBlock(): Parsed id 0x%s (%s), size: %lld\n", id.hexString(), id.stringName(), size.val());
00592 #endif
00593     switch (id.val()) {
00594       case MATROSKA_ID_SEGMENT: { // 'Segment' header: enter this
00595         break;
00596       }
00597       case MATROSKA_ID_CLUSTER: { // 'Cluster' header: enter this
00598         break;
00599       }
00600       case MATROSKA_ID_TIMECODE: { // 'Timecode' header: get this value
00601         unsigned timecode;
00602         if (parseEBMLVal_unsigned(size, timecode)) {
00603           fClusterTimecode = timecode;
00604 #ifdef DEBUG
00605           fprintf(stderr, "\tCluster timecode: %d (== %f seconds)\n", fClusterTimecode, fClusterTimecode*(fOurFile.fTimecodeScale/1000000000.0));
00606 #endif
00607         }
00608         break;
00609       }
00610       case MATROSKA_ID_BLOCK_GROUP: { // 'Block Group' header: enter this
00611         break;
00612       }
00613       case MATROSKA_ID_SIMPLEBLOCK:
00614       case MATROSKA_ID_BLOCK: { // 'SimpleBlock' or 'Block' header: enter this (and we're done)
00615         fBlockSize = (unsigned)size.val();
00616         fCurrentParseState = PARSING_BLOCK;
00617         break;
00618       }
00619       case MATROSKA_ID_BLOCK_DURATION: { // 'Block Duration' header: get this value (but we currently don't do anything with it)
00620         unsigned blockDuration;
00621         if (parseEBMLVal_unsigned(size, blockDuration)) {
00622 #ifdef DEBUG
00623           fprintf(stderr, "\tblock duration: %d (== %f ms)\n", blockDuration, (float)(blockDuration*fOurFile.fTimecodeScale/1000000.0));
00624 #endif
00625         }
00626         break;
00627       }
00628       default: { // skip over this header
00629         skipHeader(size);
00630 #ifdef DEBUG
00631         fprintf(stderr, "\tskipped %lld bytes\n", size.val());
00632 #endif
00633         break;
00634       }
00635     }
00636     setParseState();
00637   }
00638 }

void MatroskaFileParser::parseBlock (  )  [private]

Definition at line 734 of file MatroskaFileParser.cpp.

References StreamParser::curOffset(), DELIVERING_FRAME_WITHIN_BLOCK, EBMLLacing, fBlockSize, fBlockTimecode, fBlockTrackNumber, fClusterTimecode, fCurOffsetWithinFrame, fCurrentParseState, fFrameSizesWithinBlock, FixedSizeLacing, fNextFrameNumberToDeliver, fNumFramesInBlock, fOurDemux, fOurFile, frameSize, MatroskaFile::fTimecodeScale, StreamParser::get1Byte(), MatroskaTrack::headerStrippedBytesSize, LOOKING_FOR_BLOCK, MatroskaFile::lookup(), MatroskaDemux::lookupDemuxedTrack(), NoLacing, NULL, parseEBMLNumber(), setParseState(), StreamParser::skipBytes(), EBMLNumber::val(), and XiphLacing.

Referenced by parse().

00734                                     {
00735 #ifdef DEBUG
00736   fprintf(stderr, "parsing SimpleBlock or Block\n");
00737 #endif
00738   do {
00739     unsigned blockStartPos = curOffset();
00740 
00741     // The block begins with the track number:
00742     EBMLNumber trackNumber;
00743     if (!parseEBMLNumber(trackNumber)) break;
00744     fBlockTrackNumber = (unsigned)trackNumber.val();
00745 
00746     // If this track is not being read, then skip the rest of this block, and look for another one:
00747     if (fOurDemux->lookupDemuxedTrack(fBlockTrackNumber) == NULL) {
00748       unsigned headerBytesSeen = curOffset() - blockStartPos;
00749       if (headerBytesSeen < fBlockSize) {
00750         skipBytes(fBlockSize - headerBytesSeen);
00751       }
00752 #ifdef DEBUG
00753       fprintf(stderr, "\tSkipped block for unused track number %d\n", fBlockTrackNumber);
00754 #endif
00755       fCurrentParseState = LOOKING_FOR_BLOCK;
00756       setParseState();
00757       return;
00758     }
00759 
00760     MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
00761     if (track == NULL) break; // shouldn't happen
00762 
00763     // The next two bytes are the block's timecode (relative to the cluster timecode)
00764     fBlockTimecode = (get1Byte()<<8)|get1Byte();
00765 
00766     // The next byte indicates the type of 'lacing' used:
00767     u_int8_t c = get1Byte();
00768     c &= 0x6; // we're interested in bits 5-6 only
00769     MatroskaLacingType lacingType = (c==0x0)?NoLacing : (c==0x02)?XiphLacing : (c==0x04)?FixedSizeLacing : EBMLLacing;
00770 #ifdef DEBUG
00771     fprintf(stderr, "\ttrack number %d, timecode %d (=> %f seconds), %s lacing\n", fBlockTrackNumber, fBlockTimecode, (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0), (lacingType==NoLacing)?"no" : (lacingType==XiphLacing)?"Xiph" : (lacingType==FixedSizeLacing)?"fixed-size" : "EBML");
00772 #endif
00773 
00774     if (lacingType == NoLacing) {
00775       fNumFramesInBlock = 1;
00776     } else {
00777       // The next byte tells us how many frames are present in this block
00778       fNumFramesInBlock = get1Byte() + 1;
00779     }
00780     delete[] fFrameSizesWithinBlock; fFrameSizesWithinBlock = new unsigned[fNumFramesInBlock];
00781     if (fFrameSizesWithinBlock == NULL) break;
00782   
00783     if (lacingType == NoLacing) {
00784       unsigned headerBytesSeen = curOffset() - blockStartPos;
00785       if (headerBytesSeen > fBlockSize) break;
00786 
00787       fFrameSizesWithinBlock[0] = fBlockSize - headerBytesSeen;
00788     } else if (lacingType == FixedSizeLacing) {
00789       unsigned headerBytesSeen = curOffset() - blockStartPos;
00790       if (headerBytesSeen > fBlockSize) break;
00791 
00792       unsigned frameBytesAvailable = fBlockSize - headerBytesSeen;
00793       unsigned constantFrameSize = frameBytesAvailable/fNumFramesInBlock;
00794 
00795       for (unsigned i = 0; i < fNumFramesInBlock; ++i) {
00796         fFrameSizesWithinBlock[i] = constantFrameSize;
00797       }
00798       // If there are any bytes left over, assign them to the last frame:
00799       fFrameSizesWithinBlock[fNumFramesInBlock-1] += frameBytesAvailable%fNumFramesInBlock;
00800     } else { // EBML or Xiph lacing
00801       unsigned curFrameSize = 0;
00802       unsigned frameSizesTotal = 0;
00803       unsigned i;
00804 
00805       for (i = 0; i < fNumFramesInBlock-1; ++i) {
00806         if (lacingType == EBMLLacing) {
00807           EBMLNumber frameSize;
00808           if (!parseEBMLNumber(frameSize)) break;
00809           unsigned fsv = (unsigned)frameSize.val();
00810 
00811           if (i == 0) {
00812             curFrameSize = fsv;
00813           } else {
00814             // The value we read is a signed value, that's added to the previous frame size, to get the current frame size:
00815             unsigned toSubtract = (fsv>0xFFFFFF)?0x07FFFFFF : (fsv>0xFFFF)?0x0FFFFF : (fsv>0xFF)?0x1FFF : 0x3F;
00816             int fsv_signed = fsv - toSubtract;
00817             curFrameSize += fsv_signed;
00818             if ((int)curFrameSize < 0) break;
00819           }
00820         } else { // Xiph lacing
00821           curFrameSize = 0;
00822           u_int8_t c;
00823           do {
00824             c = get1Byte();
00825             curFrameSize += c;
00826           } while (c == 0xFF);
00827         }
00828         fFrameSizesWithinBlock[i] = curFrameSize;
00829         frameSizesTotal += curFrameSize;
00830       }
00831       if (i != fNumFramesInBlock-1) break; // an error occurred within the "for" loop
00832 
00833       // Compute the size of the final frame within the block (from the block's size, and the frame sizes already computed):)
00834       unsigned headerBytesSeen = curOffset() - blockStartPos;
00835       if (headerBytesSeen + frameSizesTotal > fBlockSize) break;
00836       fFrameSizesWithinBlock[i] = fBlockSize - (headerBytesSeen + frameSizesTotal);
00837     }
00838 
00839     // We're done parsing headers within the block, and (as a result) we now know the sizes of all frames within the block.
00840     // If we have 'stripped bytes' that are common to (the front of) all frames, then count them now:
00841     if (track->headerStrippedBytesSize != 0) {
00842       for (unsigned i = 0; i < fNumFramesInBlock; ++i) fFrameSizesWithinBlock[i] += track->headerStrippedBytesSize;
00843     }
00844 #ifdef DEBUG
00845     fprintf(stderr, "\tThis block contains %d frame(s); size(s):", fNumFramesInBlock);
00846     unsigned frameSizesTotal = 0;
00847     for (unsigned i = 0; i < fNumFramesInBlock; ++i) {
00848       fprintf(stderr, " %d", fFrameSizesWithinBlock[i]);
00849       frameSizesTotal += fFrameSizesWithinBlock[i];
00850     }
00851     if (fNumFramesInBlock > 1) fprintf(stderr, " (total: %u)", frameSizesTotal);
00852     fprintf(stderr, " bytes\n");
00853 #endif
00854     // Next, start delivering these frames:
00855     fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
00856     fCurOffsetWithinFrame = fNextFrameNumberToDeliver = 0;
00857     setParseState();
00858     return;
00859   } while (0);
00860 
00861   // An error occurred.  Try to recover:
00862 #ifdef DEBUG
00863   fprintf(stderr, "parseBlock(): Error parsing data; trying to recover...\n");
00864 #endif
00865   fCurrentParseState = LOOKING_FOR_BLOCK;
00866 }

Boolean MatroskaFileParser::deliverFrameWithinBlock (  )  [private]

Definition at line 868 of file MatroskaFileParser.cpp.

References MatroskaTrack::defaultDuration, DELIVERING_FRAME_BYTES, MatroskaTrack::durationImbalance, MatroskaDemuxedTrack::durationInMicroseconds(), False, fBlockTimecode, fBlockTrackNumber, fClusterTimecode, fCurFrameNumBytesToGet, fCurOffsetWithinFrame, fCurrentParseState, fFrameSizesWithinBlock, fNextFrameNumberToDeliver, fOurDemux, fOurFile, fPresentationTimeOffset, MatroskaDemuxedTrack::frameSize(), frameSize, MatroskaFile::fTimecodeScale, StreamParser::get1Byte(), getCommonFrameBytes(), MatroskaTrack::haveSubframes(), FramedSource::isCurrentlyAwaitingData(), LOOKING_FOR_BLOCK, MatroskaFile::lookup(), MatroskaDemux::lookupDemuxedTrack(), MatroskaDemuxedTrack::maxSize(), NULL, MatroskaDemuxedTrack::numTruncatedBytes(), MatroskaDemuxedTrack::presentationTime(), MatroskaTrack::prevPresentationTime, restoreSavedParserState(), setParseState(), MatroskaTrack::subframeSizeSize, MatroskaDemuxedTrack::to(), and True.

Referenced by parse().

00868                                                     {
00869 #ifdef DEBUG
00870   fprintf(stderr, "delivering frame within SimpleBlock or Block\n");
00871 #endif
00872   do {
00873     MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
00874     if (track == NULL) break; // shouldn't happen
00875 
00876     MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
00877     if (demuxedTrack == NULL) break; // shouldn't happen
00878     if (!demuxedTrack->isCurrentlyAwaitingData()) {
00879       // Someone has been reading this stream, but isn't right now.
00880       // We can't deliver this frame until he asks for it, so punt for now.
00881       // The next time he asks for a frame, he'll get it.
00882 #ifdef DEBUG
00883       fprintf(stderr, "\tdeferring delivery of frame #%d (%d bytes)", fNextFrameNumberToDeliver, fFrameSizesWithinBlock[fNextFrameNumberToDeliver]);
00884       if (track->haveSubframes()) fprintf(stderr, "[offset %d]", fCurOffsetWithinFrame);
00885       fprintf(stderr, "\n");
00886 #endif
00887       restoreSavedParserState(); // so we read from the beginning next time
00888       return False;
00889     }
00890 
00891     unsigned frameSize = fFrameSizesWithinBlock[fNextFrameNumberToDeliver];
00892     if (track->haveSubframes()) {
00893       // The next "track->subframeSizeSize" bytes contain the length of a 'subframe':
00894       if (fCurOffsetWithinFrame + track->subframeSizeSize > frameSize) break; // sanity check
00895       unsigned subframeSize = 0;
00896       for (unsigned i = 0; i < track->subframeSizeSize; ++i) {
00897         u_int8_t c;
00898         getCommonFrameBytes(track, &c, 1, 0);
00899         if (fCurFrameNumBytesToGet > 0) { // it'll be 1
00900           c = get1Byte();
00901           ++fCurOffsetWithinFrame;
00902         }
00903         subframeSize = subframeSize*256 + c;
00904       }
00905       if (subframeSize == 0 || fCurOffsetWithinFrame + subframeSize > frameSize) break; // sanity check
00906       frameSize = subframeSize;
00907     }
00908 
00909     // Compute the presentation time of this frame (from the cluster timecode, the block timecode, and the default duration):
00910     double pt = (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0)
00911       + fNextFrameNumberToDeliver*(track->defaultDuration/1000000000.0);
00912     if (fPresentationTimeOffset == 0.0) {
00913       // This is the first time we've computed a presentation time.  Compute an offset to make the presentation times aligned
00914       // with 'wall clock' time:
00915       struct timeval timeNow;
00916       gettimeofday(&timeNow, NULL);
00917       double ptNow = timeNow.tv_sec + timeNow.tv_usec/1000000.0;
00918       fPresentationTimeOffset = ptNow - pt;
00919     }
00920     pt += fPresentationTimeOffset;
00921     struct timeval presentationTime;
00922     presentationTime.tv_sec = (unsigned)pt;
00923     presentationTime.tv_usec = (unsigned)((pt - presentationTime.tv_sec)*1000000);
00924     unsigned durationInMicroseconds = track->defaultDuration/1000;
00925     if (track->haveSubframes()) {
00926       // If this is a 'subframe', use a duration of 0 instead (unless it's the last 'subframe'):
00927       if (fCurOffsetWithinFrame + frameSize + track->subframeSizeSize < fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
00928         // There's room for at least one more subframe after this, so give this subframe a duration of 0
00929         durationInMicroseconds = 0;
00930       }
00931     }
00932 
00933     if (track->defaultDuration == 0) {
00934       // Adjust the frame duration to keep the sum of frame durations aligned with presentation times.
00935       if (track->prevPresentationTime.tv_sec != 0) { // not the first time for this track
00936         track->durationImbalance
00937           += (presentationTime.tv_sec - track->prevPresentationTime.tv_sec)*1000000
00938           + (presentationTime.tv_usec - track->prevPresentationTime.tv_usec);
00939       }
00940       int adjustment = 0;
00941       if (track->durationImbalance > 0) {
00942         // The duration needs to be increased.
00943         int const adjustmentThreshold = 100000; // don't increase the duration by more than this amount (in case there's a mistake)
00944         adjustment = track->durationImbalance > adjustmentThreshold ? adjustmentThreshold : track->durationImbalance;
00945       } else if (track->durationImbalance < 0) {
00946         // The duration needs to be decreased.
00947         adjustment
00948           = (unsigned)(-track->durationImbalance) < durationInMicroseconds ? track->durationImbalance : -(int)durationInMicroseconds;
00949       }
00950       durationInMicroseconds += adjustment;
00951       track->durationImbalance -= durationInMicroseconds; // for next time
00952       track->prevPresentationTime = presentationTime; // for next time
00953     }
00954 
00955     demuxedTrack->presentationTime() = presentationTime;
00956     demuxedTrack->durationInMicroseconds() = durationInMicroseconds;
00957 
00958     // Deliver the next block now:
00959     if (frameSize > demuxedTrack->maxSize()) {
00960       demuxedTrack->numTruncatedBytes() = frameSize - demuxedTrack->maxSize();
00961       demuxedTrack->frameSize() = demuxedTrack->maxSize();
00962     } else { // normal case
00963       demuxedTrack->numTruncatedBytes() = 0;
00964       demuxedTrack->frameSize() = frameSize;
00965     }
00966     getCommonFrameBytes(track, demuxedTrack->to(), demuxedTrack->frameSize(), demuxedTrack->numTruncatedBytes());
00967 
00968     // Next, deliver (and/or skip) bytes from the input file:
00969     fCurrentParseState = DELIVERING_FRAME_BYTES;
00970     setParseState();
00971     return True;
00972   } while (0);
00973 
00974   // An error occurred.  Try to recover:
00975 #ifdef DEBUG
00976   fprintf(stderr, "deliverFrameWithinBlock(): Error parsing data; trying to recover...\n");
00977 #endif
00978   fCurrentParseState = LOOKING_FOR_BLOCK;
00979   return True;
00980 }

void MatroskaFileParser::deliverFrameBytes (  )  [private]

Definition at line 982 of file MatroskaFileParser.cpp.

References FramedSource::afterGetting(), BANK_SIZE, StreamParser::bankSize(), DELIVERING_FRAME_WITHIN_BLOCK, MatroskaDemuxedTrack::durationInMicroseconds(), fBlockTrackNumber, fCurFrameNumBytesToGet, fCurFrameNumBytesToSkip, fCurFrameTo, fCurOffsetWithinFrame, fCurrentParseState, fFrameSizesWithinBlock, fNextFrameNumberToDeliver, fNumFramesInBlock, fOurDemux, fOurFile, fPresentationTimeOffset, MatroskaDemuxedTrack::frameSize(), StreamParser::getBytes(), MatroskaTrack::haveSubframes(), LOOKING_FOR_BLOCK, MatroskaFile::lookup(), MatroskaDemux::lookupDemuxedTrack(), NULL, MatroskaDemuxedTrack::numTruncatedBytes(), MatroskaDemuxedTrack::presentationTime(), setParseState(), StreamParser::skipBytes(), and MatroskaTrack::subframeSizeSize.

Referenced by parse().

00982                                            {
00983   do {
00984     MatroskaTrack* track = fOurFile.lookup(fBlockTrackNumber);
00985     if (track == NULL) break; // shouldn't happen
00986 
00987     MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
00988     if (demuxedTrack == NULL) break; // shouldn't happen
00989 
00990     unsigned const BANK_SIZE = bankSize();
00991     while (fCurFrameNumBytesToGet > 0) {
00992       // Hack: We can get no more than BANK_SIZE bytes at a time:
00993       unsigned numBytesToGet = fCurFrameNumBytesToGet > BANK_SIZE ? BANK_SIZE : fCurFrameNumBytesToGet;
00994       getBytes(fCurFrameTo, numBytesToGet);
00995       fCurFrameTo += numBytesToGet;
00996       fCurFrameNumBytesToGet -= numBytesToGet;
00997       fCurOffsetWithinFrame += numBytesToGet;
00998       setParseState();
00999     }
01000     while (fCurFrameNumBytesToSkip > 0) {
01001       // Hack: We can skip no more than BANK_SIZE bytes at a time:
01002       unsigned numBytesToSkip = fCurFrameNumBytesToSkip > BANK_SIZE ? BANK_SIZE : fCurFrameNumBytesToSkip;
01003       skipBytes(numBytesToSkip);
01004       fCurFrameNumBytesToSkip -= numBytesToSkip;
01005       fCurOffsetWithinFrame += numBytesToSkip;
01006       setParseState();
01007     }
01008 #ifdef DEBUG
01009     fprintf(stderr, "\tdelivered frame #%d: %d bytes", fNextFrameNumberToDeliver, demuxedTrack->frameSize());
01010     if (track->haveSubframes()) fprintf(stderr, "[offset %d]", fCurOffsetWithinFrame - track->subframeSizeSize - demuxedTrack->frameSize() - demuxedTrack->numTruncatedBytes());
01011     if (demuxedTrack->numTruncatedBytes() > 0) fprintf(stderr, " (%d bytes truncated)", demuxedTrack->numTruncatedBytes());
01012     fprintf(stderr, " @%u.%06u (%.06f from start); duration %u us\n", demuxedTrack->presentationTime().tv_sec, demuxedTrack->presentationTime().tv_usec, demuxedTrack->presentationTime().tv_sec+demuxedTrack->presentationTime().tv_usec/1000000.0-fPresentationTimeOffset, demuxedTrack->durationInMicroseconds());
01013 #endif
01014 
01015     if (!track->haveSubframes()
01016         || fCurOffsetWithinFrame + track->subframeSizeSize >= fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
01017       // Either we don't have subframes, or there's no more room for another subframe => We're completely done with this frame now:
01018       ++fNextFrameNumberToDeliver;
01019       fCurOffsetWithinFrame = 0;
01020     }
01021     if (fNextFrameNumberToDeliver == fNumFramesInBlock) {
01022       // We've delivered all of the frames from this block.  Look for another block next:
01023       fCurrentParseState = LOOKING_FOR_BLOCK;
01024     } else {
01025       fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
01026     }
01027 
01028     setParseState();
01029     FramedSource::afterGetting(demuxedTrack); // completes delivery
01030     return;
01031   } while (0);
01032 
01033   // An error occurred.  Try to recover:
01034 #ifdef DEBUG
01035   fprintf(stderr, "deliverFrameBytes(): Error parsing data; trying to recover...\n");
01036 #endif
01037   fCurrentParseState = LOOKING_FOR_BLOCK;
01038 }

void MatroskaFileParser::getCommonFrameBytes ( MatroskaTrack track,
u_int8_t *  to,
unsigned  numBytesToGet,
unsigned  numBytesToSkip 
) [private]

Definition at line 1041 of file MatroskaFileParser.cpp.

References fCurFrameNumBytesToGet, fCurFrameNumBytesToSkip, fCurFrameTo, fCurOffsetWithinFrame, MatroskaTrack::headerStrippedBytes, and MatroskaTrack::headerStrippedBytesSize.

Referenced by deliverFrameWithinBlock().

01041                                                                                                          {
01042   if (track->headerStrippedBytesSize > fCurOffsetWithinFrame) {
01043     // We have some common 'header stripped' bytes that remain to be prepended to the frame.  Use these first:
01044     unsigned numRemainingHeaderStrippedBytes = track->headerStrippedBytesSize - fCurOffsetWithinFrame;
01045     unsigned numHeaderStrippedBytesToGet;
01046     if (numBytesToGet <= numRemainingHeaderStrippedBytes) {
01047       numHeaderStrippedBytesToGet = numBytesToGet;
01048       numBytesToGet = 0;
01049       if (numBytesToGet + numBytesToSkip <= numRemainingHeaderStrippedBytes) {
01050         numBytesToSkip = 0;
01051       } else {
01052         numBytesToSkip = numBytesToGet + numBytesToSkip - numRemainingHeaderStrippedBytes;
01053       }
01054     } else {
01055       numHeaderStrippedBytesToGet = numRemainingHeaderStrippedBytes;
01056       numBytesToGet = numBytesToGet - numRemainingHeaderStrippedBytes;
01057     }
01058 
01059     if (numHeaderStrippedBytesToGet > 0) {
01060       memmove(to, &track->headerStrippedBytes[fCurOffsetWithinFrame], numHeaderStrippedBytesToGet);
01061       to += numHeaderStrippedBytesToGet;
01062       fCurOffsetWithinFrame += numHeaderStrippedBytesToGet;
01063     }
01064   }
01065 
01066   fCurFrameTo = to;
01067   fCurFrameNumBytesToGet = numBytesToGet;
01068   fCurFrameNumBytesToSkip = numBytesToSkip;
01069 }

Boolean MatroskaFileParser::parseEBMLNumber ( EBMLNumber num  )  [private]

Definition at line 1071 of file MatroskaFileParser.cpp.

References EBMLNumber::data, EBML_NUMBER_MAX_LEN, False, fCurOffsetInFile, fLimitOffsetInFile, StreamParser::get1Byte(), EBMLNumber::len, setParseState(), EBMLNumber::stripLeading1, and True.

Referenced by lookForNextTrack(), parseBlock(), and parseEBMLIdAndSize().

01071                                                            {
01072   unsigned i;
01073   u_int8_t bitmask = 0x80;
01074   for (i = 0; i < EBML_NUMBER_MAX_LEN; ++i) {
01075     while (1) {
01076       if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) return False; // We've hit our pre-set limit
01077       num.data[i] = get1Byte();
01078       ++fCurOffsetInFile;
01079 
01080       // If we're looking for an id, skip any leading bytes that don't contain a '1' in the first 4 bits:
01081       if (i == 0/*we're a leading byte*/ && !num.stripLeading1/*we're looking for an id*/ && (num.data[i]&0xF0) == 0) {
01082         setParseState(); // ensures that we make forward progress if the parsing gets interrupted
01083         continue;
01084       }
01085       break;
01086     }
01087     if ((num.data[0]&bitmask) != 0) {
01088       // num[i] is the last byte of the id
01089       if (num.stripLeading1) num.data[0] &=~ bitmask;
01090       break;
01091     }
01092     bitmask >>= 1;
01093   }
01094   if (i == EBML_NUMBER_MAX_LEN) return False;
01095 
01096   num.len = i+1;
01097   return True;
01098 }

Boolean MatroskaFileParser::parseEBMLIdAndSize ( EBMLId id,
EBMLDataSize size 
) [private]

Definition at line 1100 of file MatroskaFileParser.cpp.

References parseEBMLNumber(), and size.

Referenced by lookForNextBlock(), lookForNextTrack(), parseCues(), parseStartOfFile(), and parseTrack().

01100                                                                              {
01101   return parseEBMLNumber(id) && parseEBMLNumber(size);
01102 }

Boolean MatroskaFileParser::parseEBMLVal_unsigned64 ( EBMLDataSize size,
u_int64_t &  result 
) [private]

Definition at line 1104 of file MatroskaFileParser.cpp.

References False, fCurOffsetInFile, fLimitOffsetInFile, StreamParser::get1Byte(), size, and True.

Referenced by lookForNextTrack(), parseCues(), and parseEBMLVal_unsigned().

01104                                                                                          {
01105   u_int64_t sv = size.val();
01106   if (sv > 8) return False; // size too large
01107 
01108   result = 0; // initially
01109   for (unsigned i = (unsigned)sv; i > 0; --i) {
01110     if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) return False; // We've hit our pre-set limit
01111 
01112     u_int8_t c = get1Byte();
01113     ++fCurOffsetInFile;
01114 
01115     result = result*256 + c;
01116   }
01117 
01118   return True;
01119 }

Boolean MatroskaFileParser::parseEBMLVal_unsigned ( EBMLDataSize size,
unsigned &  result 
) [private]

Definition at line 1121 of file MatroskaFileParser.cpp.

References False, parseEBMLVal_unsigned64(), size, and True.

Referenced by lookForNextBlock(), lookForNextTrack(), parseCues(), parseEBMLVal_float(), and parseTrack().

01121                                                                                       {
01122   if (size.val() > 4) return False; // size too large
01123 
01124   u_int64_t result64;
01125   if (!parseEBMLVal_unsigned64(size, result64)) return False;
01126 
01127   result = (unsigned)result64;
01128 
01129   return True;
01130 }

Boolean MatroskaFileParser::parseEBMLVal_float ( EBMLDataSize size,
float &  result 
) [private]

Definition at line 1132 of file MatroskaFileParser.cpp.

References False, parseEBMLVal_unsigned(), size, and True.

Referenced by lookForNextTrack(), and parseTrack().

01132                                                                                 {
01133   unsigned resultAsUnsigned;
01134   if (!parseEBMLVal_unsigned(size, resultAsUnsigned)) return False;
01135 
01136   result = *(float*)&resultAsUnsigned;
01137   return True;
01138 }

Boolean MatroskaFileParser::parseEBMLVal_string ( EBMLDataSize size,
char *&  result 
) [private]

Definition at line 1140 of file MatroskaFileParser.cpp.

References False, fCurOffsetInFile, fLimitOffsetInFile, StreamParser::get1Byte(), NULL, size, and True.

Referenced by parseTrack().

01140                                                                                  {
01141   unsigned resultLength = (unsigned)size.val();
01142   result = new char[resultLength + 1]; // allow for the trailing '\0'
01143   if (result == NULL) return False;
01144 
01145   char* p = result;
01146   unsigned i;
01147   for (i = 0; i < resultLength; ++i) {
01148     if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) break; // We've hit our pre-set limit
01149 
01150     u_int8_t c = get1Byte();
01151     ++fCurOffsetInFile;
01152 
01153     *p++ = c;
01154   }
01155   if (i < resultLength) { // an error occurred
01156     delete[] result;
01157     result = NULL;
01158     return False;
01159   }
01160   *p = '\0';
01161 
01162   return True;
01163 }

Boolean MatroskaFileParser::parseEBMLVal_binary ( EBMLDataSize size,
u_int8_t *&  result 
) [private]

Definition at line 1165 of file MatroskaFileParser.cpp.

References False, fCurOffsetInFile, fLimitOffsetInFile, StreamParser::get1Byte(), NULL, size, and True.

Referenced by parseTrack().

01165                                                                                      {
01166   unsigned resultLength = (unsigned)size.val();
01167   result = new u_int8_t[resultLength];
01168   if (result == NULL) return False;
01169 
01170   u_int8_t* p = result;
01171   unsigned i;
01172   for (i = 0; i < resultLength; ++i) {
01173     if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) break; // We've hit our pre-set limit
01174 
01175     u_int8_t c = get1Byte();
01176     ++fCurOffsetInFile;
01177 
01178     *p++ = c;
01179   }
01180   if (i < resultLength) { // an error occurred
01181     delete[] result;
01182     result = NULL;
01183     return False;
01184   }
01185 
01186   return True;
01187 }

void MatroskaFileParser::skipHeader ( EBMLDataSize const &  size  )  [private]

Definition at line 1189 of file MatroskaFileParser.cpp.

References StreamParser::bankSize(), fCurOffsetInFile, size, and StreamParser::skipBytes().

Referenced by lookForNextBlock(), lookForNextTrack(), parseCues(), parseStartOfFile(), and parseTrack().

01189                                                             {
01190   unsigned sv = (unsigned)size.val();
01191 
01192   // Hack: To avoid tripping into a parser 'internal error' if we try to skip an excessively large distance.
01193   // (Such large distances are likely caused by erroneous data.  We might not be able to recover from this, but at least we won't
01194   //  generate a parser 'internal error'.)
01195   if (sv > bankSize()-12) sv = bankSize()-12;
01196   
01197   skipBytes(sv);
01198   fCurOffsetInFile += sv;
01199 }

void MatroskaFileParser::setParseState (  )  [private]

Definition at line 1201 of file MatroskaFileParser.cpp.

References fCurOffsetInFile, fCurOffsetWithinFrame, fSavedCurOffsetInFile, fSavedCurOffsetWithinFrame, and StreamParser::saveParserState().

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), lookForNextBlock(), lookForNextTrack(), parseBlock(), parseCues(), parseEBMLNumber(), and parseTrack().

void MatroskaFileParser::seekToFilePosition ( u_int64_t  offsetInFile  )  [private]

Definition at line 1213 of file MatroskaFileParser.cpp.

References fInputSource, NULL, resetStateAfterSeeking(), and ByteStreamFileSource::seekToByteAbsolute().

Referenced by parse(), and seekToTime().

01213                                                                   {
01214   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01215   if (fileSource != NULL) {
01216     fileSource->seekToByteAbsolute(offsetInFile);
01217     resetStateAfterSeeking();
01218   }
01219 }

void MatroskaFileParser::seekToEndOfFile (  )  [private]

Definition at line 1221 of file MatroskaFileParser.cpp.

References fInputSource, NULL, resetStateAfterSeeking(), and ByteStreamFileSource::seekToEnd().

Referenced by seekToTime().

01221                                          {
01222   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01223   if (fileSource != NULL) {
01224     fileSource->seekToEnd();
01225     resetStateAfterSeeking();
01226   }
01227 }

void MatroskaFileParser::resetStateAfterSeeking (  )  [private]

Definition at line 1229 of file MatroskaFileParser.cpp.

References fCurOffsetInFile, fCurOffsetWithinFrame, StreamParser::flushInput(), fSavedCurOffsetInFile, and fSavedCurOffsetWithinFrame.

Referenced by seekToEndOfFile(), and seekToFilePosition().

01229                                                 {
01230   // Because we're resuming parsing after seeking to a new position in the file, reset the parser state:
01231   fCurOffsetInFile = fSavedCurOffsetInFile = 0;
01232   fCurOffsetWithinFrame = fSavedCurOffsetWithinFrame = 0;
01233   flushInput();
01234 }

void MatroskaFileParser::restoreSavedParserState (  )  [private, virtual]

Reimplemented from StreamParser.

Definition at line 1207 of file MatroskaFileParser.cpp.

References fCurOffsetInFile, fCurOffsetWithinFrame, fSavedCurOffsetInFile, fSavedCurOffsetWithinFrame, and StreamParser::restoreSavedParserState().

Referenced by deliverFrameWithinBlock().

void StreamParser::flushInput (  )  [virtual, inherited]

Reimplemented in H264VideoStreamParser, MPEG1or2VideoStreamParser, and MPEG4VideoStreamParser.

Definition at line 28 of file StreamParser.cpp.

References StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, StreamParser::fSavedParserIndex, StreamParser::fSavedRemainingUnparsedBits, and StreamParser::fTotNumValidBytes.

Referenced by MPEGVideoStreamFramer::flushInput(), MPEG4VideoStreamParser::flushInput(), MPEG1or2VideoStreamParser::flushInput(), MPEG1or2Demux::flushInput(), MPEG1or2AudioStreamFramer::flushInput(), H264VideoStreamParser::flushInput(), AC3AudioStreamFramer::flushInput(), and resetStateAfterSeeking().

void StreamParser::saveParserState (  )  [protected, inherited]

Definition at line 58 of file StreamParser.cpp.

References StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, StreamParser::fSavedParserIndex, and StreamParser::fSavedRemainingUnparsedBits.

Referenced by MPEG1or2AudioStreamParser::parse(), AC3AudioStreamParser::parseFrame(), MPEGVideoStreamParser::setParseState(), MPEGProgramStreamParser::setParseState(), setParseState(), and H263plusVideoStreamParser::setParseState().

u_int32_t StreamParser::get4Bytes (  )  [inline, protected, inherited]

Definition at line 46 of file StreamParser.hh.

References StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, and StreamParser::test4Bytes().

Referenced by AC3AudioStreamParser::parseFrame(), MPEG1or2VideoStreamParser::parseGOPHeader(), MPEG4VideoStreamParser::parseGroupOfVideoObjectPlane(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), MPEG1or2VideoStreamParser::parsePictureHeader(), MPEG4VideoStreamParser::parseVideoObjectLayer(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG1or2VideoStreamParser::parseVideoSequenceHeader(), MPEG4VideoStreamParser::parseVisualObject(), MPEG4VideoStreamParser::parseVisualObjectSequence(), MPEGVideoStreamParser::saveToNextCode(), and MPEGVideoStreamParser::skipToNextCode().

00046                         { // byte-aligned; returned in big-endian order
00047     u_int32_t result = test4Bytes();
00048     fCurParserIndex += 4;
00049     fRemainingUnparsedBits = 0;
00050 
00051     return result;
00052   }

u_int32_t StreamParser::test4Bytes (  )  [inline, protected, inherited]

Definition at line 53 of file StreamParser.hh.

References StreamParser::ensureValidBytes(), and StreamParser::nextToParse().

Referenced by StreamParser::get4Bytes(), StreamParser::getBits(), MPEG1or2AudioStreamParser::parse(), H264VideoStreamParser::parse(), AC3AudioStreamParser::parseFrame(), MPEG1or2VideoStreamParser::parseGOPHeader(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), MPEGProgramStreamParser::parseSystemHeader(), MPEG1or2VideoStreamParser::parseVideoSequenceHeader(), and MPEG4VideoStreamParser::parseVisualObjectSequence().

00053                          { // as above, but doesn't advance ptr
00054     ensureValidBytes(4);
00055 
00056     unsigned char const* ptr = nextToParse();
00057     return (ptr[0]<<24)|(ptr[1]<<16)|(ptr[2]<<8)|ptr[3];
00058   }

u_int16_t StreamParser::get2Bytes (  )  [inline, protected, inherited]

Definition at line 60 of file StreamParser.hh.

References StreamParser::ensureValidBytes(), StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, and StreamParser::nextToParse().

Referenced by MPEGProgramStreamParser::parsePESPacket(), and MPEGProgramStreamParser::parseSystemHeader().

00060                         {
00061     ensureValidBytes(2);
00062 
00063     unsigned char const* ptr = nextToParse();
00064     u_int16_t result = (ptr[0]<<8)|ptr[1];
00065 
00066     fCurParserIndex += 2;
00067     fRemainingUnparsedBits = 0;
00068 
00069     return result;
00070   }

u_int8_t StreamParser::get1Byte (  )  [inline, protected, inherited]

Definition at line 72 of file StreamParser.hh.

References StreamParser::curBank(), StreamParser::ensureValidBytes(), StreamParser::fCurParserIndex, and StreamParser::fRemainingUnparsedBits.

Referenced by deliverFrameWithinBlock(), H264VideoStreamParser::parse(), parseBlock(), parseEBMLNumber(), parseEBMLVal_binary(), parseEBMLVal_string(), parseEBMLVal_unsigned64(), MPEG1or2VideoStreamParser::parseGOPHeader(), H263plusVideoStreamParser::parseH263Frame(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), MPEG4VideoStreamParser::parseVideoObjectPlane(), MPEG1or2VideoStreamParser::parseVideoSequenceHeader(), MPEG4VideoStreamParser::parseVisualObject(), MPEG4VideoStreamParser::parseVisualObjectSequence(), MPEGVideoStreamParser::saveToNextCode(), and MPEGVideoStreamParser::skipToNextCode().

00072                       { // byte-aligned
00073     ensureValidBytes(1);
00074     fRemainingUnparsedBits = 0;
00075     return curBank()[fCurParserIndex++];
00076   }

void StreamParser::getBytes ( u_int8_t *  to,
unsigned  numBytes 
) [inline, protected, inherited]

Definition at line 78 of file StreamParser.hh.

References StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, and StreamParser::testBytes().

Referenced by deliverFrameBytes(), MPEG1or2AudioStreamParser::parse(), AC3AudioStreamParser::parseFrame(), MPEG4VideoStreamParser::parseGroupOfVideoObjectPlane(), H263plusVideoStreamParser::parseH263Frame(), and MPEGProgramStreamParser::parsePESPacket().

00078                                                  {
00079     testBytes(to, numBytes);
00080     fCurParserIndex += numBytes;
00081     fRemainingUnparsedBits = 0;
00082   }

void StreamParser::testBytes ( u_int8_t *  to,
unsigned  numBytes 
) [inline, protected, inherited]

Definition at line 83 of file StreamParser.hh.

References StreamParser::ensureValidBytes(), and StreamParser::nextToParse().

Referenced by StreamParser::getBytes(), and H264VideoStreamParser::parse().

00083                                                   { // as above, but doesn't advance ptr
00084     ensureValidBytes(numBytes);
00085     memmove(to, nextToParse(), numBytes);
00086   }

void StreamParser::skipBytes ( unsigned  numBytes  )  [inline, protected, inherited]

Definition at line 87 of file StreamParser.hh.

References StreamParser::ensureValidBytes(), and StreamParser::fCurParserIndex.

Referenced by deliverFrameBytes(), MPEG1or2AudioStreamParser::parse(), H264VideoStreamParser::parse(), parseBlock(), AC3AudioStreamParser::parseFrame(), MPEGProgramStreamParser::parsePackHeader(), MPEGProgramStreamParser::parsePESPacket(), MPEGProgramStreamParser::parseSystemHeader(), and skipHeader().

00087                                     {
00088     ensureValidBytes(numBytes);
00089     fCurParserIndex += numBytes;
00090   }

void StreamParser::skipBits ( unsigned  numBits  )  [protected, inherited]

Definition at line 68 of file StreamParser.cpp.

References StreamParser::ensureValidBytes(), StreamParser::fCurParserIndex, and StreamParser::fRemainingUnparsedBits.

Referenced by MPEGProgramStreamParser::parsePackHeader().

00068                                             {
00069   if (numBits <= fRemainingUnparsedBits) {
00070     fRemainingUnparsedBits -= numBits;
00071   } else {
00072     numBits -= fRemainingUnparsedBits;
00073 
00074     unsigned numBytesToExamine = (numBits+7)/8; // round up
00075     ensureValidBytes(numBytesToExamine);
00076     fCurParserIndex += numBytesToExamine;
00077 
00078     fRemainingUnparsedBits = 8*numBytesToExamine - numBits;
00079   }
00080 }

unsigned StreamParser::getBits ( unsigned  numBits  )  [protected, inherited]

Definition at line 82 of file StreamParser.cpp.

References StreamParser::fCurParserIndex, StreamParser::fRemainingUnparsedBits, StreamParser::lastParsed(), and StreamParser::test4Bytes().

Referenced by MPEGProgramStreamParser::parsePackHeader(), and MPEGProgramStreamParser::parsePESPacket().

00082                                                {
00083   if (numBits <= fRemainingUnparsedBits) {
00084     unsigned char lastByte = *lastParsed();
00085     lastByte >>= (fRemainingUnparsedBits - numBits);
00086     fRemainingUnparsedBits -= numBits;
00087 
00088     return (unsigned)lastByte &~ ((~0)<<numBits);
00089   } else {
00090     unsigned char lastByte;
00091     if (fRemainingUnparsedBits > 0) {
00092       lastByte = *lastParsed();
00093     } else {
00094       lastByte = 0;
00095     }
00096 
00097     unsigned remainingBits = numBits - fRemainingUnparsedBits; // > 0
00098 
00099     // For simplicity, read the next 4 bytes, even though we might not
00100     // need all of them here:
00101     unsigned result = test4Bytes();
00102 
00103     result >>= (32 - remainingBits);
00104     result |= (lastByte << remainingBits);
00105     if (numBits < 32) result &=~ ((~0)<<numBits);
00106 
00107     unsigned const numRemainingBytes = (remainingBits+7)/8;
00108     fCurParserIndex += numRemainingBytes;
00109     fRemainingUnparsedBits = 8*numRemainingBytes - remainingBits;
00110 
00111     return result;
00112   }
00113 }

unsigned StreamParser::curOffset (  )  const [inline, protected, inherited]

Definition at line 96 of file StreamParser.hh.

References StreamParser::fCurParserIndex.

Referenced by H264VideoStreamParser::parse(), parseBlock(), and MPEGProgramStreamParser::parsePESPacket().

00096 { return fCurParserIndex; }

unsigned& StreamParser::totNumValidBytes (  )  [inline, protected, inherited]

Definition at line 98 of file StreamParser.hh.

References StreamParser::fTotNumValidBytes.

Referenced by H264VideoStreamParser::parse(), and AC3AudioStreamParser::testStreamCode().

00098 { return fTotNumValidBytes; }

Boolean StreamParser::haveSeenEOF (  )  const [inline, protected, inherited]

Definition at line 100 of file StreamParser.hh.

References StreamParser::fHaveSeenEOF.

Referenced by H264VideoStreamParser::parse().

00100 { return fHaveSeenEOF; }

unsigned StreamParser::bankSize (  )  const [protected, inherited]

Definition at line 115 of file StreamParser.cpp.

References BANK_SIZE.

Referenced by deliverFrameBytes(), and skipHeader().

00115                                       {
00116   return BANK_SIZE;
00117 }


Field Documentation

MatroskaFile& MatroskaFileParser::fOurFile [private]

Definition at line 98 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), lookForNextBlock(), lookForNextTrack(), parse(), parseBlock(), parseCues(), parseStartOfFile(), parseTrack(), and seekToTime().

FramedSource* MatroskaFileParser::fInputSource [private]

Reimplemented from StreamParser.

Definition at line 99 of file MatroskaFileParser.hh.

Referenced by continueParsing(), seekToEndOfFile(), seekToFilePosition(), and ~MatroskaFileParser().

FramedSource::onCloseFunc* MatroskaFileParser::fOnEndFunc [private]

Definition at line 100 of file MatroskaFileParser.hh.

Referenced by continueParsing().

void* MatroskaFileParser::fOnEndClientData [private]

Definition at line 101 of file MatroskaFileParser.hh.

Referenced by continueParsing().

MatroskaDemux* MatroskaFileParser::fOurDemux [private]

Definition at line 102 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), and parseBlock().

MatroskaParseState MatroskaFileParser::fCurrentParseState [private]

Definition at line 103 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), lookForNextBlock(), lookForNextTrack(), MatroskaFileParser(), parse(), parseBlock(), parseStartOfFile(), and seekToTime().

u_int64_t MatroskaFileParser::fCurOffsetInFile [private]

Definition at line 104 of file MatroskaFileParser.hh.

Referenced by lookForNextTrack(), parseCues(), parseEBMLNumber(), parseEBMLVal_binary(), parseEBMLVal_string(), parseEBMLVal_unsigned64(), parseTrack(), resetStateAfterSeeking(), restoreSavedParserState(), setParseState(), and skipHeader().

u_int64_t MatroskaFileParser::fSavedCurOffsetInFile [private]

Definition at line 104 of file MatroskaFileParser.hh.

Referenced by resetStateAfterSeeking(), restoreSavedParserState(), and setParseState().

u_int64_t MatroskaFileParser::fLimitOffsetInFile [private]

Definition at line 104 of file MatroskaFileParser.hh.

Referenced by lookForNextTrack(), parseCues(), parseEBMLNumber(), parseEBMLVal_binary(), parseEBMLVal_string(), parseEBMLVal_unsigned64(), and parseTrack().

EBMLId MatroskaFileParser::fLastSeekId [private]

Definition at line 107 of file MatroskaFileParser.hh.

Referenced by lookForNextTrack().

unsigned MatroskaFileParser::fClusterTimecode [private]

Definition at line 110 of file MatroskaFileParser.hh.

Referenced by deliverFrameWithinBlock(), lookForNextBlock(), and parseBlock().

unsigned MatroskaFileParser::fBlockSize [private]

Definition at line 113 of file MatroskaFileParser.hh.

Referenced by lookForNextBlock(), and parseBlock().

unsigned MatroskaFileParser::fBlockTrackNumber [private]

Definition at line 114 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), and parseBlock().

short MatroskaFileParser::fBlockTimecode [private]

Definition at line 115 of file MatroskaFileParser.hh.

Referenced by deliverFrameWithinBlock(), and parseBlock().

unsigned MatroskaFileParser::fNumFramesInBlock [private]

Definition at line 116 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), and parseBlock().

unsigned* MatroskaFileParser::fFrameSizesWithinBlock [private]

Definition at line 117 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), parseBlock(), and ~MatroskaFileParser().

double MatroskaFileParser::fPresentationTimeOffset [private]

Definition at line 120 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), and deliverFrameWithinBlock().

unsigned MatroskaFileParser::fNextFrameNumberToDeliver [private]

Definition at line 121 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), and parseBlock().

unsigned MatroskaFileParser::fCurOffsetWithinFrame [private]

Definition at line 122 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), getCommonFrameBytes(), parseBlock(), resetStateAfterSeeking(), restoreSavedParserState(), and setParseState().

unsigned MatroskaFileParser::fSavedCurOffsetWithinFrame [private]

Definition at line 122 of file MatroskaFileParser.hh.

Referenced by resetStateAfterSeeking(), restoreSavedParserState(), and setParseState().

u_int8_t* MatroskaFileParser::fCurFrameTo [private]

Definition at line 125 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), and getCommonFrameBytes().

unsigned MatroskaFileParser::fCurFrameNumBytesToGet [private]

Definition at line 126 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), deliverFrameWithinBlock(), and getCommonFrameBytes().

unsigned MatroskaFileParser::fCurFrameNumBytesToSkip [private]

Definition at line 127 of file MatroskaFileParser.hh.

Referenced by deliverFrameBytes(), and getCommonFrameBytes().


The documentation for this class was generated from the following files:
Generated on Thu May 17 07:15:29 2012 for live by  doxygen 1.5.2