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-2013 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.  Call our 'done' function now:
00104   if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData);
00105 }
00106 
00107 Boolean MatroskaFileParser::parse() {
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 }
00178 
00179 Boolean MatroskaFileParser::parseStartOfFile() {
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 }
00196 
00197 void MatroskaFileParser::lookForNextTrack() {
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 }
00283 
00284 Boolean MatroskaFileParser::parseTrack() {
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 }
00579 
00580 void MatroskaFileParser::lookForNextBlock() {
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 }
00638 
00639 Boolean MatroskaFileParser::parseCues() {
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 }
00730 
00731 typedef enum { NoLacing, XiphLacing, FixedSizeLacing, EBMLLacing } MatroskaLacingType;
00732 
00733 void MatroskaFileParser::parseBlock() {
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 }
00866 
00867 Boolean MatroskaFileParser::deliverFrameWithinBlock() {
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 }
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   if (sizeof result != sizeof resultAsUnsigned) return False;
01137   memcpy(&result, &resultAsUnsigned, sizeof result);
01138   return True;
01139 }
01140 
01141 Boolean MatroskaFileParser::parseEBMLVal_string(EBMLDataSize& size, char*& result) {
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 }
01165 
01166 Boolean MatroskaFileParser::parseEBMLVal_binary(EBMLDataSize& size, u_int8_t*& result) {
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 }
01189 
01190 void MatroskaFileParser::skipHeader(EBMLDataSize const& size) {
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 }
01201 
01202 void MatroskaFileParser::setParseState() {
01203   fSavedCurOffsetInFile = fCurOffsetInFile;
01204   fSavedCurOffsetWithinFrame = fCurOffsetWithinFrame;
01205   saveParserState();
01206 }
01207 
01208 void MatroskaFileParser::restoreSavedParserState() {
01209   StreamParser::restoreSavedParserState();
01210   fCurOffsetInFile = fSavedCurOffsetInFile;
01211   fCurOffsetWithinFrame = fSavedCurOffsetWithinFrame;
01212 }
01213 
01214 void MatroskaFileParser::seekToFilePosition(u_int64_t offsetInFile) {
01215   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01216   if (fileSource != NULL) {
01217     fileSource->seekToByteAbsolute(offsetInFile);
01218     resetStateAfterSeeking();
01219   }
01220 }
01221 
01222 void MatroskaFileParser::seekToEndOfFile() {
01223   ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource; // we know it's a "ByteStreamFileSource"
01224   if (fileSource != NULL) {
01225     fileSource->seekToEnd();
01226     resetStateAfterSeeking();
01227   }
01228 }
01229 
01230 void MatroskaFileParser::resetStateAfterSeeking() {
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 }

Generated on Tue Jun 18 13:16:51 2013 for live by  doxygen 1.5.2