liveMedia/MatroskaFileParser.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2012 Live Networks, Inc.  All rights reserved.
00018 // A parser for a Matroska file.
00019 // Implementation
00020 
00021 #include "MatroskaFileParser.hh"
00022 #include "MatroskaDemuxedTrack.hh"
00023 #include <ByteStreamFileSource.hh>
00024 #include <GroupsockHelper.hh> // for "gettimeofday()
00025 
00026 MatroskaFileParser::MatroskaFileParser(MatroskaFile& ourFile, FramedSource* inputSource,
00027                                        FramedSource::onCloseFunc* onEndFunc, void* onEndClientData,
00028                                        MatroskaDemux* ourDemux)
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 }
00046 
00047 MatroskaFileParser::~MatroskaFileParser() {
00048   delete[] fFrameSizesWithinBlock;
00049   Medium::close(fInputSource);
00050 }
00051 
00052 void MatroskaFileParser::seekToTime(double& seekNPT) {
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 }
00086 
00087 void MatroskaFileParser
00088 ::continueParsing(void* clientData, unsigned char* /*ptr*/, unsigned /*size*/, struct timeval /*presentationTime*/) {
00089   ((MatroskaFileParser*)clientData)->continueParsing();
00090 }
00091 
00092 void MatroskaFileParser::continueParsing() {
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 }
00107 
00108 Boolean MatroskaFileParser::parse() {
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 }
00179 
00180 Boolean MatroskaFileParser::parseStartOfFile() {
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 }
00197 
00198 void MatroskaFileParser::lookForNextTrack() {
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 }
00284 
00285 Boolean MatroskaFileParser::parseTrack() {
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 }
00580 
00581 void MatroskaFileParser::lookForNextBlock() {
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 }
00639 
00640 Boolean MatroskaFileParser::parseCues() {
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 }
00731 
00732 typedef enum { NoLacing, XiphLacing, FixedSizeLacing, EBMLLacing } MatroskaLacingType;
00733 
00734 void MatroskaFileParser::parseBlock() {
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 }
00867 
00868 Boolean MatroskaFileParser::deliverFrameWithinBlock() {
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 }
00981 
00982 void MatroskaFileParser::deliverFrameBytes() {
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 }
01039 
01040 void MatroskaFileParser
01041 ::getCommonFrameBytes(MatroskaTrack* track, u_int8_t* to, unsigned numBytesToGet, unsigned numBytesToSkip) {
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 }
01070 
01071 Boolean MatroskaFileParser::parseEBMLNumber(EBMLNumber& num) {
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 }
01099 
01100 Boolean MatroskaFileParser::parseEBMLIdAndSize(EBMLId& id, EBMLDataSize& size) {
01101   return parseEBMLNumber(id) && parseEBMLNumber(size);
01102 }
01103 
01104 Boolean MatroskaFileParser::parseEBMLVal_unsigned64(EBMLDataSize& size, u_int64_t& result) {
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 }
01120 
01121 Boolean MatroskaFileParser::parseEBMLVal_unsigned(EBMLDataSize& size, unsigned& result) {
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 }
01131 
01132 Boolean MatroskaFileParser::parseEBMLVal_float(EBMLDataSize& size, float& result) {
01133   unsigned resultAsUnsigned;
01134   if (!parseEBMLVal_unsigned(size, resultAsUnsigned)) return False;
01135 
01136   result = *(float*)&resultAsUnsigned;
01137   return True;
01138 }
01139 
01140 Boolean MatroskaFileParser::parseEBMLVal_string(EBMLDataSize& size, char*& result) {
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 }
01164 
01165 Boolean MatroskaFileParser::parseEBMLVal_binary(EBMLDataSize& size, u_int8_t*& result) {
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 }
01188 
01189 void MatroskaFileParser::skipHeader(EBMLDataSize const& size) {
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 }
01200 
01201 void MatroskaFileParser::setParseState() {
01202   fSavedCurOffsetInFile = fCurOffsetInFile;
01203   fSavedCurOffsetWithinFrame = fCurOffsetWithinFrame;
01204   saveParserState();
01205 }
01206 
01207 void MatroskaFileParser::restoreSavedParserState() {
01208   StreamParser::restoreSavedParserState();
01209   fCurOffsetInFile = fSavedCurOffsetInFile;
01210   fCurOffsetWithinFrame = fSavedCurOffsetWithinFrame;
01211 }
01212 
01213 void MatroskaFileParser::seekToFilePosition(u_int64_t offsetInFile) {
01214   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01215   if (fileSource != NULL) {
01216     fileSource->seekToByteAbsolute(offsetInFile);
01217     resetStateAfterSeeking();
01218   }
01219 }
01220 
01221 void MatroskaFileParser::seekToEndOfFile() {
01222   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01223   if (fileSource != NULL) {
01224     fileSource->seekToEnd();
01225     resetStateAfterSeeking();
01226   }
01227 }
01228 
01229 void MatroskaFileParser::resetStateAfterSeeking() {
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 }

Generated on Thu May 17 07:11:46 2012 for live by  doxygen 1.5.2