00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "MatroskaFileParser.hh"
00022 #include "MatroskaDemuxedTrack.hh"
00023 #include <ByteStreamFileSource.hh>
00024 #include <GroupsockHelper.hh>
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
00039 fCurrentParseState = PARSING_START_OF_FILE;
00040 continueParsing();
00041 } else {
00042 fCurrentParseState = LOOKING_FOR_CLUSTER;
00043
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;
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
00084 }
00085 }
00086
00087 void MatroskaFileParser
00088 ::continueParsing(void* clientData, unsigned char* , unsigned , struct timeval ) {
00089 ((MatroskaFileParser*)clientData)->continueParsing();
00090 }
00091
00092 void MatroskaFileParser::continueParsing() {
00093 if (fInputSource != NULL) {
00094 if (fInputSource->isCurrentlyAwaitingData()) return;
00095
00096 if (!parse()) {
00097
00098
00099 return;
00100 }
00101 }
00102
00103
00104
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
00126
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
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;
00166 break;
00167 }
00168 }
00169 } while (!areDone);
00170
00171 return True;
00172 } catch (int ) {
00173 #ifdef DEBUG
00174 fprintf(stderr, "MatroskaFileParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00175 #endif
00176 return False;
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
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;
00191 }
00192 skipHeader(size);
00193
00194 fCurrentParseState = LOOKING_FOR_TRACKS;
00195 return False;
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
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: {
00213
00214 fOurFile.fSegmentDataOffset = fCurOffsetInFile;
00215 break;
00216 }
00217 case MATROSKA_ID_SEEK_HEAD: {
00218 break;
00219 }
00220 case MATROSKA_ID_SEEK: {
00221 break;
00222 }
00223 case MATROSKA_ID_SEEK_ID: {
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: {
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
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: {
00248 break;
00249 }
00250 case MATROSKA_ID_TIMECODE_SCALE: {
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: {
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: {
00269 fLimitOffsetInFile = fCurOffsetInFile + size.val();
00270 fCurrentParseState = PARSING_TRACK;
00271 break;
00272 }
00273 default: {
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
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");
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: {
00301
00302 if (track != NULL && track->trackNumber == 0) delete track;
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
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: {
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: {
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: {
00521 break;
00522 }
00523 case MATROSKA_ID_CONTENT_COMPRESSION: {
00524
00525
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
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: {
00561
00562 if (track != NULL) track->isEnabled = False;
00563
00564 }
00565 default: {
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;
00577 if (track != NULL && track->trackNumber == 0) delete track;
00578 return True;
00579 }
00580
00581 void MatroskaFileParser::lookForNextBlock() {
00582 #ifdef DEBUG
00583 fprintf(stderr, "looking for Block\n");
00584 #endif
00585
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: {
00595 break;
00596 }
00597 case MATROSKA_ID_CLUSTER: {
00598 break;
00599 }
00600 case MATROSKA_ID_TIMECODE: {
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: {
00611 break;
00612 }
00613 case MATROSKA_ID_SIMPLEBLOCK:
00614 case MATROSKA_ID_BLOCK: {
00615 fBlockSize = (unsigned)size.val();
00616 fCurrentParseState = PARSING_BLOCK;
00617 break;
00618 }
00619 case MATROSKA_ID_BLOCK_DURATION: {
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: {
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
00648 if (!parseEBMLIdAndSize(id, size) || id != MATROSKA_ID_CUES) return True;
00649 fLimitOffsetInFile = fCurOffsetInFile + size.val();
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");
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: {
00662 break;
00663 }
00664 case MATROSKA_ID_CUE_TIME: {
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: {
00675 break;
00676 }
00677 case MATROSKA_ID_CUE_TRACK: {
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: {
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
00694 fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, 1);
00695 }
00696 break;
00697 }
00698 case MATROSKA_ID_CUE_BLOCK_NUMBER: {
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
00705 fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, cueBlockNumber);
00706 }
00707 break;
00708 }
00709 default: {
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;
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;
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
00742 EBMLNumber trackNumber;
00743 if (!parseEBMLNumber(trackNumber)) break;
00744 fBlockTrackNumber = (unsigned)trackNumber.val();
00745
00746
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;
00762
00763
00764 fBlockTimecode = (get1Byte()<<8)|get1Byte();
00765
00766
00767 u_int8_t c = get1Byte();
00768 c &= 0x6;
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
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
00799 fFrameSizesWithinBlock[fNumFramesInBlock-1] += frameBytesAvailable%fNumFramesInBlock;
00800 } else {
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
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 {
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;
00832
00833
00834 unsigned headerBytesSeen = curOffset() - blockStartPos;
00835 if (headerBytesSeen + frameSizesTotal > fBlockSize) break;
00836 fFrameSizesWithinBlock[i] = fBlockSize - (headerBytesSeen + frameSizesTotal);
00837 }
00838
00839
00840
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
00855 fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
00856 fCurOffsetWithinFrame = fNextFrameNumberToDeliver = 0;
00857 setParseState();
00858 return;
00859 } while (0);
00860
00861
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;
00875
00876 MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
00877 if (demuxedTrack == NULL) break;
00878 if (!demuxedTrack->isCurrentlyAwaitingData()) {
00879
00880
00881
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();
00888 return False;
00889 }
00890
00891 unsigned frameSize = fFrameSizesWithinBlock[fNextFrameNumberToDeliver];
00892 if (track->haveSubframes()) {
00893
00894 if (fCurOffsetWithinFrame + track->subframeSizeSize > frameSize) break;
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) {
00900 c = get1Byte();
00901 ++fCurOffsetWithinFrame;
00902 }
00903 subframeSize = subframeSize*256 + c;
00904 }
00905 if (subframeSize == 0 || fCurOffsetWithinFrame + subframeSize > frameSize) break;
00906 frameSize = subframeSize;
00907 }
00908
00909
00910 double pt = (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0)
00911 + fNextFrameNumberToDeliver*(track->defaultDuration/1000000000.0);
00912 if (fPresentationTimeOffset == 0.0) {
00913
00914
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
00927 if (fCurOffsetWithinFrame + frameSize + track->subframeSizeSize < fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
00928
00929 durationInMicroseconds = 0;
00930 }
00931 }
00932
00933 if (track->defaultDuration == 0) {
00934
00935 if (track->prevPresentationTime.tv_sec != 0) {
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
00943 int const adjustmentThreshold = 100000;
00944 adjustment = track->durationImbalance > adjustmentThreshold ? adjustmentThreshold : track->durationImbalance;
00945 } else if (track->durationImbalance < 0) {
00946
00947 adjustment
00948 = (unsigned)(-track->durationImbalance) < durationInMicroseconds ? track->durationImbalance : -(int)durationInMicroseconds;
00949 }
00950 durationInMicroseconds += adjustment;
00951 track->durationImbalance -= durationInMicroseconds;
00952 track->prevPresentationTime = presentationTime;
00953 }
00954
00955 demuxedTrack->presentationTime() = presentationTime;
00956 demuxedTrack->durationInMicroseconds() = durationInMicroseconds;
00957
00958
00959 if (frameSize > demuxedTrack->maxSize()) {
00960 demuxedTrack->numTruncatedBytes() = frameSize - demuxedTrack->maxSize();
00961 demuxedTrack->frameSize() = demuxedTrack->maxSize();
00962 } else {
00963 demuxedTrack->numTruncatedBytes() = 0;
00964 demuxedTrack->frameSize() = frameSize;
00965 }
00966 getCommonFrameBytes(track, demuxedTrack->to(), demuxedTrack->frameSize(), demuxedTrack->numTruncatedBytes());
00967
00968
00969 fCurrentParseState = DELIVERING_FRAME_BYTES;
00970 setParseState();
00971 return True;
00972 } while (0);
00973
00974
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;
00986
00987 MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
00988 if (demuxedTrack == NULL) break;
00989
00990 unsigned const BANK_SIZE = bankSize();
00991 while (fCurFrameNumBytesToGet > 0) {
00992
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
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
01018 ++fNextFrameNumberToDeliver;
01019 fCurOffsetWithinFrame = 0;
01020 }
01021 if (fNextFrameNumberToDeliver == fNumFramesInBlock) {
01022
01023 fCurrentParseState = LOOKING_FOR_BLOCK;
01024 } else {
01025 fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
01026 }
01027
01028 setParseState();
01029 FramedSource::afterGetting(demuxedTrack);
01030 return;
01031 } while (0);
01032
01033
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
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;
01077 num.data[i] = get1Byte();
01078 ++fCurOffsetInFile;
01079
01080
01081 if (i == 0 && !num.stripLeading1 && (num.data[i]&0xF0) == 0) {
01082 setParseState();
01083 continue;
01084 }
01085 break;
01086 }
01087 if ((num.data[0]&bitmask) != 0) {
01088
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;
01107
01108 result = 0;
01109 for (unsigned i = (unsigned)sv; i > 0; --i) {
01110 if (fLimitOffsetInFile > 0 && fCurOffsetInFile > fLimitOffsetInFile) return False;
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;
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];
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;
01149
01150 u_int8_t c = get1Byte();
01151 ++fCurOffsetInFile;
01152
01153 *p++ = c;
01154 }
01155 if (i < resultLength) {
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;
01174
01175 u_int8_t c = get1Byte();
01176 ++fCurOffsetInFile;
01177
01178 *p++ = c;
01179 }
01180 if (i < resultLength) {
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
01193
01194
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;
01215 if (fileSource != NULL) {
01216 fileSource->seekToByteAbsolute(offsetInFile);
01217 resetStateAfterSeeking();
01218 }
01219 }
01220
01221 void MatroskaFileParser::seekToEndOfFile() {
01222 ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource;
01223 if (fileSource != NULL) {
01224 fileSource->seekToEnd();
01225 resetStateAfterSeeking();
01226 }
01227 }
01228
01229 void MatroskaFileParser::resetStateAfterSeeking() {
01230
01231 fCurOffsetInFile = fSavedCurOffsetInFile = 0;
01232 fCurOffsetWithinFrame = fSavedCurOffsetWithinFrame = 0;
01233 flushInput();
01234 }