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 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
00125
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
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;
00165 break;
00166 }
00167 }
00168 } while (!areDone);
00169
00170 return True;
00171 } catch (int ) {
00172 #ifdef DEBUG
00173 fprintf(stderr, "MatroskaFileParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00174 #endif
00175 return False;
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
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;
00190 }
00191 skipHeader(size);
00192
00193 fCurrentParseState = LOOKING_FOR_TRACKS;
00194 return False;
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
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: {
00212
00213 fOurFile.fSegmentDataOffset = fCurOffsetInFile;
00214 break;
00215 }
00216 case MATROSKA_ID_SEEK_HEAD: {
00217 break;
00218 }
00219 case MATROSKA_ID_SEEK: {
00220 break;
00221 }
00222 case MATROSKA_ID_SEEK_ID: {
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: {
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
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: {
00247 break;
00248 }
00249 case MATROSKA_ID_TIMECODE_SCALE: {
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: {
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: {
00268 fLimitOffsetInFile = fCurOffsetInFile + size.val();
00269 fCurrentParseState = PARSING_TRACK;
00270 break;
00271 }
00272 default: {
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
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");
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: {
00300
00301 if (track != NULL && track->trackNumber == 0) delete track;
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
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: {
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: {
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: {
00520 break;
00521 }
00522 case MATROSKA_ID_CONTENT_COMPRESSION: {
00523
00524
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
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: {
00560
00561 if (track != NULL) track->isEnabled = False;
00562
00563 }
00564 default: {
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;
00576 if (track != NULL && track->trackNumber == 0) delete track;
00577 return True;
00578 }
00579
00580 void MatroskaFileParser::lookForNextBlock() {
00581 #ifdef DEBUG
00582 fprintf(stderr, "looking for Block\n");
00583 #endif
00584
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: {
00594 break;
00595 }
00596 case MATROSKA_ID_CLUSTER: {
00597 break;
00598 }
00599 case MATROSKA_ID_TIMECODE: {
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: {
00610 break;
00611 }
00612 case MATROSKA_ID_SIMPLEBLOCK:
00613 case MATROSKA_ID_BLOCK: {
00614 fBlockSize = (unsigned)size.val();
00615 fCurrentParseState = PARSING_BLOCK;
00616 break;
00617 }
00618 case MATROSKA_ID_BLOCK_DURATION: {
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: {
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
00647 if (!parseEBMLIdAndSize(id, size) || id != MATROSKA_ID_CUES) return True;
00648 fLimitOffsetInFile = fCurOffsetInFile + size.val();
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");
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: {
00661 break;
00662 }
00663 case MATROSKA_ID_CUE_TIME: {
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: {
00674 break;
00675 }
00676 case MATROSKA_ID_CUE_TRACK: {
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: {
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
00693 fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, 1);
00694 }
00695 break;
00696 }
00697 case MATROSKA_ID_CUE_BLOCK_NUMBER: {
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
00704 fOurFile.addCuePoint(currentCueTime, currentClusterOffsetInFile, cueBlockNumber);
00705 }
00706 break;
00707 }
00708 default: {
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;
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;
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
00741 EBMLNumber trackNumber;
00742 if (!parseEBMLNumber(trackNumber)) break;
00743 fBlockTrackNumber = (unsigned)trackNumber.val();
00744
00745
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;
00761
00762
00763 fBlockTimecode = (get1Byte()<<8)|get1Byte();
00764
00765
00766 u_int8_t c = get1Byte();
00767 c &= 0x6;
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
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
00798 fFrameSizesWithinBlock[fNumFramesInBlock-1] += frameBytesAvailable%fNumFramesInBlock;
00799 } else {
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
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 {
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;
00831
00832
00833 unsigned headerBytesSeen = curOffset() - blockStartPos;
00834 if (headerBytesSeen + frameSizesTotal > fBlockSize) break;
00835 fFrameSizesWithinBlock[i] = fBlockSize - (headerBytesSeen + frameSizesTotal);
00836 }
00837
00838
00839
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
00854 fCurrentParseState = DELIVERING_FRAME_WITHIN_BLOCK;
00855 fCurOffsetWithinFrame = fNextFrameNumberToDeliver = 0;
00856 setParseState();
00857 return;
00858 } while (0);
00859
00860
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;
00874
00875 MatroskaDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fBlockTrackNumber);
00876 if (demuxedTrack == NULL) break;
00877 if (!demuxedTrack->isCurrentlyAwaitingData()) {
00878
00879
00880
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();
00887 return False;
00888 }
00889
00890 unsigned frameSize = fFrameSizesWithinBlock[fNextFrameNumberToDeliver];
00891 if (track->haveSubframes()) {
00892
00893 if (fCurOffsetWithinFrame + track->subframeSizeSize > frameSize) break;
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) {
00899 c = get1Byte();
00900 ++fCurOffsetWithinFrame;
00901 }
00902 subframeSize = subframeSize*256 + c;
00903 }
00904 if (subframeSize == 0 || fCurOffsetWithinFrame + subframeSize > frameSize) break;
00905 frameSize = subframeSize;
00906 }
00907
00908
00909 double pt = (fClusterTimecode+fBlockTimecode)*(fOurFile.fTimecodeScale/1000000000.0)
00910 + fNextFrameNumberToDeliver*(track->defaultDuration/1000000000.0);
00911 if (fPresentationTimeOffset == 0.0) {
00912
00913
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
00926 if (fCurOffsetWithinFrame + frameSize + track->subframeSizeSize < fFrameSizesWithinBlock[fNextFrameNumberToDeliver]) {
00927
00928 durationInMicroseconds = 0;
00929 }
00930 }
00931
00932 if (track->defaultDuration == 0) {
00933
00934 if (demuxedTrack->prevPresentationTime().tv_sec != 0) {
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
00942 int const adjustmentThreshold = 100000;
00943 adjustment = demuxedTrack->durationImbalance() > adjustmentThreshold
00944 ? adjustmentThreshold : demuxedTrack->durationImbalance();
00945 } else if (demuxedTrack->durationImbalance() < 0) {
00946
00947 adjustment = (unsigned)(-demuxedTrack->durationImbalance()) < durationInMicroseconds
00948 ? demuxedTrack->durationImbalance() : -(int)durationInMicroseconds;
00949 }
00950 durationInMicroseconds += adjustment;
00951 demuxedTrack->durationImbalance() -= durationInMicroseconds;
00952 demuxedTrack->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 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];
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;
01150
01151 u_int8_t c = get1Byte();
01152 ++fCurOffsetInFile;
01153
01154 *p++ = c;
01155 }
01156 if (i < resultLength) {
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;
01175
01176 u_int8_t c = get1Byte();
01177 ++fCurOffsetInFile;
01178
01179 *p++ = c;
01180 }
01181 if (i < resultLength) {
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
01194
01195
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;
01216 if (fileSource != NULL) {
01217 fileSource->seekToByteAbsolute(offsetInFile);
01218 resetStateAfterSeeking();
01219 }
01220 }
01221
01222 void MatroskaFileParser::seekToEndOfFile() {
01223 ByteStreamFileSource* fileSource = (ByteStreamFileSource*)fInputSource;
01224 if (fileSource != NULL) {
01225 fileSource->seekToEnd();
01226 resetStateAfterSeeking();
01227 }
01228 }
01229
01230 void MatroskaFileParser::resetStateAfterSeeking() {
01231
01232 fCurOffsetInFile = fSavedCurOffsetInFile = 0;
01233 fCurOffsetWithinFrame = fSavedCurOffsetWithinFrame = 0;
01234 flushInput();
01235 }