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 ()
u_int8_t test1Byte (unsigned numBytes)
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.  Call our 'done' function now:
00104   if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData);
00105 }

Boolean MatroskaFileParser::parse (  )  [private]

Definition at line 107 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().

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

Boolean MatroskaFileParser::parseStartOfFile (  )  [private]

Definition at line 179 of file MatroskaFileParser.cpp.

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

Referenced by parse().

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

void MatroskaFileParser::lookForNextTrack (  )  [private]

Definition at line 197 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().

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

Boolean MatroskaFileParser::parseTrack (  )  [private]

Definition at line 284 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().

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

Boolean MatroskaFileParser::parseCues (  )  [private]

Definition at line 639 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().

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

void MatroskaFileParser::lookForNextBlock (  )  [private]

Definition at line 580 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().

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

void MatroskaFileParser::parseBlock (  )  [private]

Definition at line 733 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().

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

Boolean MatroskaFileParser::deliverFrameWithinBlock (  )  [private]

Definition at line 867 of file MatroskaFileParser.cpp.

References MatroskaTrack::defaultDuration, DELIVERING_FRAME_BYTES, MatroskaDemuxedTrack::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(), MatroskaDemuxedTrack::prevPresentationTime(), restoreSavedParserState(), setParseState(), MatroskaTrack::subframeSizeSize, MatroskaDemuxedTrack::to(), and True.

Referenced by parse().

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

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

Definition at line 1141 of file MatroskaFileParser.cpp.

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

Referenced by parseTrack().

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

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

Definition at line 1166 of file MatroskaFileParser.cpp.

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

Referenced by parseTrack().

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

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

Definition at line 1190 of file MatroskaFileParser.cpp.

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

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

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

void MatroskaFileParser::setParseState (  )  [private]

Definition at line 1202 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 1214 of file MatroskaFileParser.cpp.

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

Referenced by parse(), and seekToTime().

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

void MatroskaFileParser::seekToEndOfFile (  )  [private]

Definition at line 1222 of file MatroskaFileParser.cpp.

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

Referenced by seekToTime().

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

void MatroskaFileParser::resetStateAfterSeeking (  )  [private]

Definition at line 1230 of file MatroskaFileParser.cpp.

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

Referenced by seekToEndOfFile(), and seekToFilePosition().

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

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

Reimplemented from StreamParser.

Definition at line 1208 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   }

u_int8_t StreamParser::test1Byte ( unsigned  numBytes  )  [inline, protected, inherited]

Definition at line 77 of file StreamParser.hh.

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

00077                                         { // as above, but doesn't advance ptr
00078     ensureValidBytes(1);
00079     return nextToParse()[0];
00080   }

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

Definition at line 82 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().

00082                                                  {
00083     testBytes(to, numBytes);
00084     fCurParserIndex += numBytes;
00085     fRemainingUnparsedBits = 0;
00086   }

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

Definition at line 87 of file StreamParser.hh.

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

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

00087                                                   { // as above, but doesn't advance ptr
00088     ensureValidBytes(numBytes);
00089     memmove(to, nextToParse(), numBytes);
00090   }

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

Definition at line 91 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().

00091                                     {
00092     ensureValidBytes(numBytes);
00093     fCurParserIndex += numBytes;
00094   }

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 100 of file StreamParser.hh.

References StreamParser::fCurParserIndex.

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

00100 { return fCurParserIndex; }

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

Definition at line 102 of file StreamParser.hh.

References StreamParser::fTotNumValidBytes.

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

00102 { return fTotNumValidBytes; }

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

Definition at line 104 of file StreamParser.hh.

References StreamParser::fHaveSeenEOF.

Referenced by H264VideoStreamParser::parse().

00104 { 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 Mon Apr 29 13:31:43 2013 for live by  doxygen 1.5.2