1/* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18/*********************************************************************************/ 19/* ------------------------------------------------------------------- */ 20/* MPEG-4 SampleTableAtom Class */ 21/* ------------------------------------------------------------------- */ 22/*********************************************************************************/ 23/* 24 This SampleTableAtom Class contains all the time and data indexing of the 25 media samples in a track. 26*/ 27 28 29#define IMPLEMENT_SampleTableAtom 30 31//HEADER FILES REQD FOR MULTIPLE SAMPLE RETRIEVAL API 32#include "sampletableatom.h" 33#include "atomutils.h" 34#include "atomdefs.h" 35#include "oscl_media_data.h" 36#include "pv_gau.h" 37#include "amrdecoderspecificinfo.h" 38#include "oscl_int64_utils.h" 39#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 40#include "oscl_tickcount.h" 41 42#define PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS 5 43#endif 44 45// Stream-in ctor 46SampleTableAtom::SampleTableAtom(MP4_FF_FILE *fp, 47 uint32 mediaType, 48 OSCL_wString& filename, 49 uint32 size, 50 uint32 type, 51 bool oPVContentDownloadable, 52 uint32 parsingMode) 53 : Atom(fp, size, type), 54 _currentPlaybackSampleTimestamp(0), 55 _currentPlaybackSampleNumber(0), 56 _trackStartTSOffset(0), 57 _fileSize(0), 58 _IsUpdateFileSize(0) 59{ 60 _ptimeToSampleAtom = NULL; 61 _pcompositionOffsetAtom = NULL; 62 _psampleDescriptionAtom = NULL; 63 _psampleSizeAtom = NULL; 64 _psampleToChunkAtom = NULL; 65 _pchunkOffsetAtom = NULL; 66 _psyncSampleAtom = NULL; 67 68 _SDIndex = 0; 69 70 SamplesCount = 0; 71 72 _oMultipleSampleDescription = false; 73 _numAMRFramesPerSample = 0; 74 _pAMRTempBuffer = NULL; 75 _oResidualSample = false; 76 _remainingFramesInSample = 0; 77 _amrTempBufferOffset = 0; 78 _amrFrameDelta = 0; 79 _pinput = NULL; 80 _commonFilePtr = NULL; 81 _currChunkOffset = 0; 82 83 _defaultMimeType += _STRLIT_WCHAR("UNKNOWN"); 84 85 iLogger = PVLogger::GetLoggerObject("mp4ffparser"); 86 iStateVarLogger = PVLogger::GetLoggerObject("mp4ffparser_mediasamplestats"); 87 iParsedDataLogger = PVLogger::GetLoggerObject("mp4ffparser_parseddata"); 88 iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.mp4ffparser"); 89 90 _oPVContentDownloadable = oPVContentDownloadable; 91 92 _parsingMode = parsingMode; 93 94 if (_success) 95 { 96 _filename = filename; 97 _pinput = NULL; 98 99 OsclAny*ptr = oscl_malloc(sizeof(MP4_FF_FILE)); 100 if (ptr == NULL) 101 { 102 _success = false; 103 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 104 return; 105 } 106 _pinput = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE()); 107 _pinput->_fileServSession = fp->_fileServSession; 108 _pinput->_pvfile.SetCPM(fp->_pvfile.GetCPM()); 109 110#ifndef OPEN_FILE_ONCE_PER_TRACK 111 ptr = oscl_malloc(sizeof(MP4_FF_FILE)); 112 if (ptr == NULL) 113 { 114 _success = false; 115 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 116 return; 117 } 118 _commonFilePtr = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE(*fp)); 119 120#endif 121 122 _currentPlaybackSampleNumber = 0; // Initializing playback start point 123 124 _pparent = NULL; 125 _success = true; 126 127 int32 count = _size - DEFAULT_ATOM_SIZE; 128 129 while (count > 0) 130 { 131 uint32 atomType = UNKNOWN_ATOM; 132 uint32 atomSize = 0; 133 134 AtomUtils::getNextAtomType(fp, atomSize, atomType); 135 136 if (atomType == TIME_TO_SAMPLE_ATOM) 137 { //"stts" 138 PV_MP4_FF_NEW(fp->auditCB, TimeToSampleAtom, 139 (fp, mediaType, atomSize, 140 atomType, filename, parsingMode), 141 _ptimeToSampleAtom); 142 143 // Check for success 144 if (!_ptimeToSampleAtom->MP4Success()) 145 { 146 _success = false; 147 _mp4ErrorCode = _ptimeToSampleAtom->GetMP4Error(); 148 return; 149 } 150 _ptimeToSampleAtom->setParent(this); 151 count -= _ptimeToSampleAtom->getSize(); 152 } 153 154 else if (atomType == COMPOSITION_OFFSET_ATOM) 155 { //"ctts" 156 PV_MP4_FF_NEW(fp->auditCB, CompositionOffsetAtom, 157 (fp, mediaType, atomSize, 158 atomType, filename, parsingMode), 159 _pcompositionOffsetAtom); 160 161 // Check for success 162 if (!_pcompositionOffsetAtom->MP4Success()) 163 { 164 _success = false; 165 _mp4ErrorCode = _pcompositionOffsetAtom->GetMP4Error(); 166 return; 167 } 168 _pcompositionOffsetAtom->setParent(this); 169 count -= _pcompositionOffsetAtom->getSize(); 170 } 171 172 else if ((atomType == UUID_ATOM) 173 || (atomType == SHADOW_SYNC_SAMPLE_ATOM) 174 || (atomType == UNKNOWN_ATOM) 175 || (atomType == USER_DATA_ATOM) 176 || (atomType == DEGRADATION_PRIORITY_ATOM)) 177 { 178 if (atomSize < DEFAULT_ATOM_SIZE) 179 { 180 _success = false; 181 _mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE; 182 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom ZERO_OR_NEGATIVE_ATOM_SIZE")); 183 break; 184 } 185 if (count < (int32)atomSize) 186 { 187 _success = false; 188 _mp4ErrorCode = READ_FAILED; 189 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom READ FAILED count<atomSize")); 190 break; 191 } 192 count -= atomSize; 193 atomSize -= DEFAULT_ATOM_SIZE; 194 AtomUtils::seekFromCurrPos(fp, atomSize); 195 } 196 else if (atomType == SAMPLE_DESCRIPTION_ATOM) 197 { 198 int32 myOffset = AtomUtils::getCurrentFilePosition(fp); 199 //"stsd" 200 if (_psampleDescriptionAtom == NULL) 201 { 202 PV_MP4_FF_NEW(fp->auditCB, SampleDescriptionAtom, (fp, mediaType, atomSize, atomType), _psampleDescriptionAtom); 203 204 // Check for success 205 if (!_psampleDescriptionAtom->MP4Success()) 206 { 207 _success = false; 208 _mp4ErrorCode = _psampleDescriptionAtom->GetMP4Error(); 209 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom Sample Description Atom Failed")); 210 return; 211 } 212 _psampleDescriptionAtom->setParent(this); 213 count -= _psampleDescriptionAtom->getSize(); 214 215 if (_psampleDescriptionAtom->Is3GPPAMR()) 216 { 217 AMRSampleEntry *entry = _psampleDescriptionAtom->getAMRSampleEntry(); 218 AMRSpecificAtom *amrAtom = NULL; 219 _numAMRFramesPerSample = 0; 220 221 if (entry != NULL) 222 { 223 amrAtom = entry->getDecoderSpecificInfo(); 224 if (amrAtom != NULL) 225 _numAMRFramesPerSample = amrAtom->getFramesPerSample(); 226 } 227 228 if (_numAMRFramesPerSample == 0) 229 { 230 _success = false; 231 _mp4ErrorCode = READ_AMR_SAMPLE_ENTRY_FAILED; 232 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom Read AMR SAmple Entry Failed")); 233 return; 234 } 235 236 _pAMRTempBuffer = (uint8 *)(oscl_malloc(sizeof(uint8) * 512)); 237 } 238 else 239 { 240 if (_psampleDescriptionAtom->getObjectTypeIndication() == AMR_AUDIO) 241 { 242 _numAMRFramesPerSample = 1; 243 } 244 else 245 { 246 _numAMRFramesPerSample = 0; 247 } 248 } 249 } 250 else 251 { 252 //Duplicate stsd++++ 253 _oMultipleSampleDescription = true; 254 } 255 atomSize -= DEFAULT_ATOM_SIZE; 256 atomSize += myOffset; 257 AtomUtils::seekFromStart(fp, atomSize); 258 } 259 else if (atomType == SAMPLE_SIZE_ATOM) 260 { //"stsz" 261 PV_MP4_FF_NEW(fp->auditCB, SampleSizeAtom, 262 (fp, mediaType, atomSize, atomType, 263 filename, parsingMode), 264 _psampleSizeAtom); 265 266 SamplesCount = _psampleSizeAtom->getSampleCount(); 267 // Check for success 268 if (!_psampleSizeAtom->MP4Success()) 269 { 270 _success = false; 271 _mp4ErrorCode = _psampleSizeAtom->GetMP4Error(); 272 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sample Sized Atom Failed")); 273 return; 274 } 275 _psampleSizeAtom->setParent(this); 276 count -= _psampleSizeAtom->getSize(); 277 } 278 else if (atomType == SAMPLE_TO_CHUNK_ATOM) 279 { 280 //"stsc" 281 PV_MP4_FF_NEW(fp->auditCB, SampleToChunkAtom, (fp, atomSize, atomType, filename, parsingMode), _psampleToChunkAtom); 282 283 // Check for success 284 if (!_psampleToChunkAtom->MP4Success()) 285 { 286 _success = false; 287 _mp4ErrorCode = _psampleToChunkAtom->GetMP4Error(); 288 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sample to chunk atom failed")); 289 return; 290 } 291 _psampleToChunkAtom->setParent(this); 292 count -= _psampleToChunkAtom->getSize(); 293 } 294 else if (atomType == CHUNK_OFFSET_ATOM) 295 { 296 //"stco" 297 PV_MP4_FF_NEW(fp->auditCB, ChunkOffsetAtom, (fp, atomSize, atomType, filename, parsingMode), _pchunkOffsetAtom); 298 299 // Check for success 300 if (!_pchunkOffsetAtom->MP4Success()) 301 { 302 _success = false; 303 _mp4ErrorCode = _pchunkOffsetAtom->GetMP4Error(); 304 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Chunk Offset atom failed")); 305 return; 306 } 307 _pchunkOffsetAtom->setParent(this); 308 count -= _pchunkOffsetAtom->getSize(); 309 } 310 else if (atomType == SYNC_SAMPLE_ATOM) 311 { 312 //"stss" 313 PV_MP4_FF_NEW(fp->auditCB, SyncSampleAtom, (fp, atomSize, atomType), _psyncSampleAtom); 314 315 // Check for success 316 if (!_psyncSampleAtom->MP4Success()) 317 { 318 _success = false; 319 _mp4ErrorCode = _psyncSampleAtom->GetMP4Error(); 320 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sync Sample Atom Failed")); 321 return; 322 } 323 _psyncSampleAtom->setParent(this); 324 count -= _psyncSampleAtom->getSize(); 325 } 326 else if (atomType == AVC_SAMPLE_DEPENDENCY_TYPE_BOX) 327 { 328 //"sdtp" 329 uint32 SamplesCount = _psampleSizeAtom->getSampleCount(); 330 331 PV_MP4_FF_NEW(fp->auditCB, AVCSampleDependencyType, 332 (fp, atomSize, atomType, SamplesCount), 333 _pavcSampleDependencyType); 334 335 // Check for success 336 if (!_pavcSampleDependencyType->MP4Success()) 337 { 338 _success = false; 339 _mp4ErrorCode = _pavcSampleDependencyType->GetMP4Error(); 340 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample Dependency Type Box failed")); 341 return; 342 } 343 _pavcSampleDependencyType->setParent(this); 344 count -= _pavcSampleDependencyType->getSize(); 345 346 } 347 else if (atomType == AVC_SAMPLE_TO_GROUP_BOX) 348 { 349 //"sgpd" 350 PV_MP4_FF_NEW(fp->auditCB, AVCSampleToGroup, (fp, atomSize, atomType), _pavcSampleToGroup); 351 // Check for success 352 if (!_pavcSampleToGroup->MP4Success()) 353 { 354 _success = false; 355 _mp4ErrorCode = _pavcSampleToGroup->GetMP4Error(); 356 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample to group box failed")); 357 return; 358 } 359 _pavcSampleToGroup->setParent(this); 360 count -= _pavcSampleToGroup->getSize(); 361 362 363 } 364 else if (atomType == AVC_SAMPLE_DEPENDENCY_BOX) 365 { 366 uint32 SamplesCount = _psampleSizeAtom->getSampleCount(); 367 PV_MP4_FF_NEW(fp->auditCB, AVCSampleDependency, (fp, atomSize, atomType, SamplesCount), _pavcSampleDependency); 368 // Check for success 369 if (!_pavcSampleDependency->MP4Success()) 370 { 371 _success = false; 372 _mp4ErrorCode = _pavcSampleDependency->GetMP4Error(); 373 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample Dependency box failed")); 374 return; 375 } 376 _pavcSampleDependency->setParent(this); 377 count -= _pavcSampleDependency->getSize(); 378 } 379 else 380 { 381 count -= atomSize; 382 atomSize -= DEFAULT_ATOM_SIZE; 383 AtomUtils::seekFromCurrPos(fp, atomSize); 384 385 } 386 387 } 388 389 if (_pcompositionOffsetAtom != NULL) 390 { 391 if (SamplesCount != 0) 392 { 393 _pcompositionOffsetAtom->setSamplesCount(SamplesCount); 394 } 395 } 396 /* 397 * These 5 atoms are mandatory. In case any of it is absent 398 * return ERROR!!! 399 */ 400 if ((_ptimeToSampleAtom == NULL) || 401 (_psampleDescriptionAtom == NULL) || 402 (_psampleSizeAtom == NULL) || 403 (_psampleToChunkAtom == NULL) || 404 (_pchunkOffsetAtom == NULL)) 405 { 406 _success = false; 407 _mp4ErrorCode = READ_SAMPLE_TABLE_ATOM_FAILED; 408 return; 409 } 410 411 if (_psampleDescriptionAtom->Is3GPPAMR()) 412 { 413 int32 sampleDelta = _ptimeToSampleAtom->getSampleDeltaAt(0); 414 415 // The notion of separate decode and composition timestamps is specific to 416 // video tracks. Therefore no ned to Adjust sampleDelta with CTTS value. 417 418 if (_numAMRFramesPerSample > 0) 419 { 420 _amrFrameDelta = ((sampleDelta) / (_numAMRFramesPerSample)); 421 } 422 _amrSampleSize = 0; 423 } 424 425 } 426 else 427 { 428 _mp4ErrorCode = READ_SAMPLE_TABLE_ATOM_FAILED; 429 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Read Sample Table Atom Failed")); 430 } 431} 432 433// Destructor 434SampleTableAtom::~SampleTableAtom() 435{ 436 // Clean up member atoms 437 if (_ptimeToSampleAtom != NULL) 438 { 439 PV_MP4_FF_DELETE(NULL, TimeToSampleAtom, _ptimeToSampleAtom); 440 } 441 442 if (_pcompositionOffsetAtom != NULL) 443 { 444 PV_MP4_FF_DELETE(NULL, CompositionOffsetAtom, _pcompositionOffsetAtom); 445 } 446 447 if (_psampleDescriptionAtom != NULL) 448 { 449 PV_MP4_FF_DELETE(NULL, SampleDescriptionAtom, _psampleDescriptionAtom); 450 } 451 452 if (_psampleSizeAtom != NULL) 453 { 454 PV_MP4_FF_DELETE(NULL, SampleSizeAtom, _psampleSizeAtom); 455 } 456 457 if (_psampleToChunkAtom != NULL) 458 { 459 PV_MP4_FF_DELETE(NULL, SampleToChunkAtom, _psampleToChunkAtom); 460 } 461 462 if (_pchunkOffsetAtom != NULL) 463 { 464 PV_MP4_FF_DELETE(NULL, ChunkOffsetAtom, _pchunkOffsetAtom); 465 } 466 467 if (_psyncSampleAtom != NULL) 468 { 469 PV_MP4_FF_DELETE(NULL, SyncSampleAtom, _psyncSampleAtom); 470 } 471 472#ifdef OPEN_FILE_ONCE_PER_TRACK 473 if (_pinput != NULL) 474 { 475 AtomUtils::CloseMP4File(_pinput); 476 oscl_free(_pinput); 477 } 478#else 479 if (_pinput != NULL) 480 { 481 oscl_free(_pinput); 482 } 483 if (_commonFilePtr != NULL) 484 { 485 oscl_free(_commonFilePtr); 486 } 487#endif 488 489 if (_pAMRTempBuffer != NULL) 490 { 491 oscl_free(_pAMRTempBuffer); 492 } 493} 494 495 496// Returns the specific sample with number 'sampleNum' 497int32 498SampleTableAtom::getSample(uint32 sampleNum, uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset) 499{ 500 if ((_psampleSizeAtom == NULL) || 501 (_psampleToChunkAtom == NULL) || 502 (_pchunkOffsetAtom == NULL)) 503 { 504 size = 0; 505 return DEFAULT_ERROR; 506 } 507 508 // return NULL if sampleNum is past end of stream 509 uint32 numSamples = _psampleSizeAtom->getSampleCount(); 510 if (sampleNum >= numSamples) 511 { 512 size = 0; 513 return END_OF_TRACK; // Past end of samples 514 } 515 516 // Check sample size from SampleSizeAtom 517 int32 sampleSize = _psampleSizeAtom->getSampleSizeAt(sampleNum); 518 size = 0; 519 if (sampleSize == PV_ERROR) 520 { 521 return DEFAULT_ERROR; 522 } 523 524 // Find chunk 525 int32 chunk = _psampleToChunkAtom->getChunkNumberForSampleGet(sampleNum); 526 // Find first sample in that chunk 527 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunkGet(); 528 529 //set the sample description index 530 _SDIndex = _psampleToChunkAtom->getSDIndexGet(); 531 if ((int32)_SDIndex <= 0) 532 { 533 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Sample Description Atom Failed")); 534 return READ_SAMPLE_DESCRIPTION_ATOM_FAILED; 535 } 536 _SDIndex -= 1; 537 index = _SDIndex; 538 539 if (sampleSize == 0) 540 { //shortcut 541 return EVERYTHING_FINE; 542 } 543 544 // Find chunk offset to file 545 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 546 //uint32 offset to int32, possible error for large files 547 if (offset == PV_ERROR) 548 { 549 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Chunk Offset Atom Failed")); 550 return READ_CHUNK_OFFSET_ATOM_FAILED; 551 } 552 553 // Need to add up all the sizes from the first sample in this run up to the 554 // the requested sample (but not including it) 555 int32 sampleSizeOffset = 0; 556 int32 tempSize = 0; 557 for (uint32 i = first; i < sampleNum; i++) 558 { 559 // Check sample size from SampleSizeAtom 560 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 561 // Check for error condition 562 if (tempSize == PV_ERROR) 563 { 564 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Sample Sized Atom Failed")); 565 return READ_SAMPLE_SIZE_ATOM_FAILED; 566 } 567 568 sampleSizeOffset += tempSize; 569 } 570 571 // Find actual file offset to sample 572 int32 sampleFileOffset = offset + sampleSizeOffset; 573 574 SampleOffset = sampleFileOffset; 575 576 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getSample- sampleFileOffset =%d", sampleFileOffset)); 577 // Open file 578 if (!_pinput->IsOpen()) 579 { 580#ifdef OPEN_FILE_ONCE_PER_TRACK 581 // Check if file is already open 582 // Opens file in binary mode with read sharing permissions 583 // Return Error in case the file open fails. 584 if (AtomUtils::OpenMP4File(_filename, 585 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 586 _pinput) != 0) 587 { 588 return FILE_OPEN_FAILED; 589 } 590#else 591 _pinput->_fileSize = _commonFilePtr->_fileSize; 592 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 593 AtomUtils::Flush(_pinput); 594 AtomUtils::seekFromStart(_pinput, 0); 595#endif 596 if (!_IsUpdateFileSize) 597 { 598 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 599 { 600 return READ_FAILED; 601 } 602 } 603 } 604 605 if (sampleFileOffset + sampleSize > (int32)_fileSize) 606 { 607 return INSUFFICIENT_DATA; 608 } 609 610#ifdef OPEN_FILE_ONCE_PER_TRACK 611 if (_oPVContentDownloadable) 612 { 613 if (sampleNum == 0) 614 { 615 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 616 } 617 } 618 else 619 { 620 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 621 } 622#else 623 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 624#endif 625 626 // Read byte data into buffer 627 if (AtomUtils::readByteData(_pinput, sampleSize, buf)) 628 { 629 size = sampleSize; 630 return EVERYTHING_FINE; 631 } 632 else 633 { 634 return DEFAULT_ERROR; 635 } 636} 637 638MP4_ERROR_CODE SampleTableAtom::getKeyMediaSampleNumAt(uint32 aKeySampleNum, 639 GAU *pgau) 640{ 641 uint32 n = 1; 642 if (_psyncSampleAtom == NULL) 643 { 644 //all samples are key frames 645 _currentPlaybackSampleNumber = aKeySampleNum; 646 } 647 else 648 { 649 uint32 totalNumSyncSamples = getSyncSampleAtom()->getEntryCount(); 650 if (aKeySampleNum >= totalNumSyncSamples) 651 { 652 aKeySampleNum = 0; 653 } 654 _currentPlaybackSampleNumber = 655 getSyncSampleAtom()->getSampleNumberAt(aKeySampleNum); 656 } 657 int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 658 if (retValA == PV_ERROR) 659 { 660 _currentPlaybackSampleNumber = 0; 661 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 662 _ptimeToSampleAtom->resetStateVariables(); 663 return READ_FAILED; 664 } 665 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 666 if (retValB == PV_ERROR) 667 { 668 _currentPlaybackSampleNumber = 0; 669 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 670 _psampleToChunkAtom->resetStateVariables(); 671 return READ_FAILED; 672 } 673 if (NULL != _pcompositionOffsetAtom) 674 { 675 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 676 if (PV_ERROR == retValC) 677 { 678 _currentPlaybackSampleNumber = 0; 679 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 680 _pcompositionOffsetAtom->resetStateVariables(); 681 return READ_FAILED; 682 } 683 } 684 if (_currentPlaybackSampleNumber > 0) 685 { 686 _currentPlaybackSampleTimestamp = 687 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 688 _currentPlaybackSampleTimestamp += _trackStartTSOffset; 689 } 690 else 691 { 692 _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0); 693 } 694 //Reset the file pointer to the correct location. In case of non-interleaved 695 //pv content, we do not seek for every media sample. 696 if (_oPVContentDownloadable) 697 { 698 int32 sampleSize = 699 _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber); 700 701 // Find chunk 702 int32 chunk = 703 _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber); 704 705 // Find first sample in that chunk 706 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 707 708 // Find chunk offset to file 709 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 710 711 //uint32 offset to int32, possible error for large files 712 if (offset == PV_ERROR) 713 { 714 _currentPlaybackSampleNumber = 0; 715 return (READ_FAILED); 716 } 717 718 // Need to add up all the sizes from the first sample in this run up to the 719 // the requested sample (but not including it) 720 int32 sampleSizeOffset = 0; 721 int32 tempSize = 0; 722 for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++) 723 { 724 // Check sample size from SampleSizeAtom 725 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 726 // Check for error condition 727 if (tempSize == PV_ERROR) 728 { 729 _currentPlaybackSampleNumber = 0; 730 return (READ_FAILED); 731 } 732 sampleSizeOffset += tempSize; 733 } 734 735 // Find actual file offset to sample 736 int32 sampleFileOffset = offset + sampleSizeOffset; 737 738 if (!_pinput->IsOpen()) 739 { 740#ifdef OPEN_FILE_ONCE_PER_TRACK 741 // Check if file is already open 742 // Opens file in binary mode with read sharing permissions 743 // Return Error in case the file open fails. 744 if (AtomUtils::OpenMP4File(_filename, 745 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 746 _pinput) != 0) 747 { 748 return FILE_OPEN_FAILED; 749 } 750#else 751 _pinput->_fileSize = _commonFilePtr->_fileSize; 752 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 753 AtomUtils::Flush(_pinput); 754 AtomUtils::seekFromStart(_pinput, 0); 755#endif 756 if (!_IsUpdateFileSize) 757 { 758 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 759 { 760 _currentPlaybackSampleNumber = 0; 761 return (READ_FAILED); 762 } 763 } 764 } 765 766 if (sampleFileOffset + sampleSize > (int32)_fileSize) 767 { 768 _currentPlaybackSampleNumber = 0; 769 return (READ_FAILED); 770 } 771 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 772 } 773 774 { 775 int32 chunk = 776 getMutableSampleToChunkAtom(). 777 getChunkNumberForSampleGet(_currentPlaybackSampleNumber); 778 779 uint32 FirstSampleNumInChunk = 780 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 781 782 uint32 offsetIntoRunOfChunks = 783 (_currentPlaybackSampleNumber - FirstSampleNumInChunk); 784 785 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 786 787 if (offset == PV_ERROR) 788 { 789 _currentPlaybackSampleNumber = 0; 790 return READ_FAILED; 791 } 792 793 int32 sampleSizeOffset = 0; 794 int32 tempSize = 0; 795 796 _currChunkOffset = 0; 797 for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk + 798 offsetIntoRunOfChunks; i++) 799 { 800 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 801 if (tempSize == PV_ERROR) 802 { 803 _currentPlaybackSampleNumber = 0; 804 return READ_FAILED; 805 } 806 sampleSizeOffset += tempSize; 807 } 808 _currChunkOffset = sampleSizeOffset; 809 } 810 811 int32 retVal = getNextNSamples(_currentPlaybackSampleNumber, &n, pgau); 812 MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal; 813 return errCode; 814} 815 816int32 817SampleTableAtom::getPrevKeyMediaSample(uint32 inputtimestamp, uint32 &aKeySampleNum, uint32 *n, GAU *pgau) 818{ 819 if (_ptimeToSampleAtom == NULL) 820 { 821 return PV_ERROR; 822 } 823 824 // Get sample number at timestamp 825 _currentPlaybackSampleNumber = 826 _ptimeToSampleAtom->getSampleNumberFromTimestamp(inputtimestamp); 827 // Go for composition offset adjustment. 828 _currentPlaybackSampleNumber = 829 getSampleNumberAdjustedWithCTTS(inputtimestamp, _currentPlaybackSampleNumber); 830 831 // Check if sample is an I-frame. If not, need to find the sample number of the 832 // first I-frame sample that follows ts 833 // Need to check syncSampleAtom for this - if not present, all samples are synch samples 834 // (i.e. all audio samples are synch samples) 835 if (_psyncSampleAtom != NULL) 836 { 837 _currentPlaybackSampleNumber = 838 getSyncSampleAtom()->getSyncSampleBefore(_currentPlaybackSampleNumber); 839 } 840 841 if (_currentPlaybackSampleNumber == PV_ERROR) 842 { 843 return PV_ERROR; 844 } 845 846 aKeySampleNum = _currentPlaybackSampleNumber; 847 848 // Increment ts for current sample in this random access:No more correct in case of CTTS presence 849 if (_currentPlaybackSampleNumber != 0) 850 { 851 // ts for sample 0 is 0 852 _currentPlaybackSampleTimestamp = 853 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 854 } 855 else 856 { 857 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 858 859 } 860 int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 861 if (retValA == PV_ERROR) 862 { 863 _currentPlaybackSampleNumber = 0; 864 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 865 _ptimeToSampleAtom->resetStateVariables(); 866 return 0; 867 } 868 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 869 if (retValB == PV_ERROR) 870 { 871 _currentPlaybackSampleNumber = 0; 872 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 873 _psampleToChunkAtom->resetStateVariables(); 874 return 0; 875 } 876 if (NULL != _pcompositionOffsetAtom) 877 { 878 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 879 if (PV_ERROR == retValC) 880 { 881 _currentPlaybackSampleNumber = 0; 882 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 883 _pcompositionOffsetAtom->resetStateVariables(); 884 return 0; 885 } 886 } 887 if (_currentPlaybackSampleNumber > 0) 888 { 889 _currentPlaybackSampleTimestamp = 890 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 891 _currentPlaybackSampleTimestamp += _trackStartTSOffset; 892 } 893 else 894 { 895 _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0); 896 } 897 //Reset the file pointer to the correct location. In case of non-interleaved 898 //pv content, we do not seek for every media sample. 899 if (_oPVContentDownloadable) 900 { 901 int32 sampleSize = 902 _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber); 903 904 // Find chunk 905 int32 chunk = 906 _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber); 907 908 // Find first sample in that chunk 909 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 910 911 // Find chunk offset to file 912 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 913 914 //uint32 offset to int32, possible error for large files 915 if (offset == PV_ERROR) 916 { 917 _currentPlaybackSampleNumber = 0; 918 return (READ_FAILED); 919 } 920 921 // Need to add up all the sizes from the first sample in this run up to the 922 // the requested sample (but not including it) 923 int32 sampleSizeOffset = 0; 924 int32 tempSize = 0; 925 for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++) 926 { 927 // Check sample size from SampleSizeAtom 928 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 929 // Check for error condition 930 if (tempSize == PV_ERROR) 931 { 932 _currentPlaybackSampleNumber = 0; 933 return (READ_FAILED); 934 } 935 sampleSizeOffset += tempSize; 936 } 937 938 // Find actual file offset to sample 939 int32 sampleFileOffset = offset + sampleSizeOffset; 940 941 if (!_pinput->IsOpen()) 942 { 943#ifdef OPEN_FILE_ONCE_PER_TRACK 944 // Check if file is already open 945 // Opens file in binary mode with read sharing permissions 946 // Return Error in case the file open fails. 947 if (AtomUtils::OpenMP4File(_filename, 948 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 949 _pinput) != 0) 950 { 951 return FILE_OPEN_FAILED; 952 } 953#else 954 _pinput->_fileSize = _commonFilePtr->_fileSize; 955 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 956 AtomUtils::Flush(_pinput); 957 AtomUtils::seekFromStart(_pinput, 0); 958#endif 959 if (!_IsUpdateFileSize) 960 { 961 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 962 { 963 _currentPlaybackSampleNumber = 0; 964 return (READ_FAILED); 965 } 966 } 967 } 968 969 if (sampleFileOffset + sampleSize > (int32)_fileSize) 970 { 971 _currentPlaybackSampleNumber = 0; 972 return (READ_FAILED); 973 } 974 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 975 } 976 977 { 978 int32 chunk = 979 getMutableSampleToChunkAtom(). 980 getChunkNumberForSampleGet(_currentPlaybackSampleNumber); 981 982 uint32 FirstSampleNumInChunk = 983 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 984 985 uint32 offsetIntoRunOfChunks = 986 (_currentPlaybackSampleNumber - FirstSampleNumInChunk); 987 988 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 989 990 if (offset == PV_ERROR) 991 { 992 _currentPlaybackSampleNumber = 0; 993 return READ_FAILED; 994 } 995 996 int32 sampleSizeOffset = 0; 997 int32 tempSize = 0; 998 999 _currChunkOffset = 0; 1000 for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk + 1001 offsetIntoRunOfChunks; i++) 1002 { 1003 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 1004 if (tempSize == PV_ERROR) 1005 { 1006 _currentPlaybackSampleNumber = 0; 1007 return READ_FAILED; 1008 } 1009 sampleSizeOffset += tempSize; 1010 } 1011 _currChunkOffset = sampleSizeOffset; 1012 } 1013 int32 retVal = getNextNSamples(_currentPlaybackSampleNumber, n, pgau); 1014 MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal; 1015 return errCode; 1016} 1017 1018int32 1019SampleTableAtom::getNextKeyMediaSample(uint32 inputtimestamp, uint32 &aKeySampleNum, uint32 *n, GAU *pgau) 1020{ 1021 if (_ptimeToSampleAtom == NULL) 1022 { 1023 return PV_ERROR; 1024 } 1025 1026 // Get sample number at timestamp 1027 _currentPlaybackSampleNumber = 1028 _ptimeToSampleAtom->getSampleNumberFromTimestamp(inputtimestamp); 1029 // Go far composition offset adjustment. 1030 _currentPlaybackSampleNumber = 1031 getSampleNumberAdjustedWithCTTS(inputtimestamp, _currentPlaybackSampleNumber); 1032 1033 // Check if sample is an I-frame. If not, need to find the sample number of the 1034 // first I-frame sample that follows ts 1035 // Need to check syncSampleAtom for this - if not present, all samples are synch samples 1036 // (i.e. all audio samples are synch samples) 1037 if (_psyncSampleAtom != NULL) 1038 { 1039 _currentPlaybackSampleNumber = 1040 getSyncSampleAtom()->getSyncSampleFollowing(_currentPlaybackSampleNumber); 1041 } 1042 1043 if (_currentPlaybackSampleNumber == PV_ERROR) 1044 { 1045 return PV_ERROR; 1046 } 1047 1048 aKeySampleNum = _currentPlaybackSampleNumber; 1049 1050 // Increment ts for current sample in this random access: No more correct incase CTTS exits 1051 if (_currentPlaybackSampleNumber != 0) 1052 { 1053 // ts for sample 0 is 0 1054 _currentPlaybackSampleTimestamp = 1055 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1056 } 1057 else 1058 { 1059 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 1060 } 1061 1062 int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 1063 if (retValA == PV_ERROR) 1064 { 1065 _currentPlaybackSampleNumber = 0; 1066 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1067 _ptimeToSampleAtom->resetStateVariables(); 1068 return 0; 1069 } 1070 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 1071 if (retValB == PV_ERROR) 1072 { 1073 _currentPlaybackSampleNumber = 0; 1074 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1075 _psampleToChunkAtom->resetStateVariables(); 1076 return 0; 1077 } 1078 if (NULL != _pcompositionOffsetAtom) 1079 { 1080 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 1081 if (PV_ERROR == retValC) 1082 { 1083 _currentPlaybackSampleNumber = 0; 1084 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1085 _pcompositionOffsetAtom->resetStateVariables(); 1086 return 0; 1087 } 1088 } 1089 1090 if (_currentPlaybackSampleNumber > 0) 1091 { 1092 _currentPlaybackSampleTimestamp = 1093 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1094 _currentPlaybackSampleTimestamp += _trackStartTSOffset; 1095 } 1096 else 1097 { 1098 _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0); 1099 } 1100 //Reset the file pointer to the correct location. In case of non-interleaved 1101 //pv content, we do not seek for every media sample. 1102 if (_oPVContentDownloadable) 1103 { 1104 int32 sampleSize = 1105 _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber); 1106 1107 // Find chunk 1108 int32 chunk = 1109 _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber); 1110 1111 // Find first sample in that chunk 1112 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 1113 1114 // Find chunk offset to file 1115 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 1116 1117 //uint32 offset to int32, possible error for large files 1118 if (offset == PV_ERROR) 1119 { 1120 _currentPlaybackSampleNumber = 0; 1121 return (READ_FAILED); 1122 } 1123 1124 // Need to add up all the sizes from the first sample in this run up to the 1125 // the requested sample (but not including it) 1126 int32 sampleSizeOffset = 0; 1127 int32 tempSize = 0; 1128 for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++) 1129 { 1130 // Check sample size from SampleSizeAtom 1131 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 1132 // Check for error condition 1133 if (tempSize == PV_ERROR) 1134 { 1135 _currentPlaybackSampleNumber = 0; 1136 return (READ_FAILED); 1137 } 1138 sampleSizeOffset += tempSize; 1139 } 1140 1141 // Find actual file offset to sample 1142 int32 sampleFileOffset = offset + sampleSizeOffset; 1143 1144 if (!_pinput->IsOpen()) 1145 { 1146#ifdef OPEN_FILE_ONCE_PER_TRACK 1147 // Check if file is already open 1148 // Opens file in binary mode with read sharing permissions 1149 // Return Error in case the file open fails. 1150 if (AtomUtils::OpenMP4File(_filename, 1151 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 1152 _pinput) != 0) 1153 { 1154 return FILE_OPEN_FAILED; 1155 } 1156#else 1157 _pinput->_fileSize = _commonFilePtr->_fileSize; 1158 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 1159 AtomUtils::Flush(_pinput); 1160 AtomUtils::seekFromStart(_pinput, 0); 1161#endif 1162 if (!_IsUpdateFileSize) 1163 { 1164 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 1165 { 1166 _currentPlaybackSampleNumber = 0; 1167 return (READ_FAILED); 1168 } 1169 } 1170 } 1171 1172 if (sampleFileOffset + sampleSize > (int32)_fileSize) 1173 { 1174 _currentPlaybackSampleNumber = 0; 1175 return (READ_FAILED); 1176 } 1177 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 1178 } 1179 1180 { 1181 int32 chunk = 1182 getMutableSampleToChunkAtom(). 1183 getChunkNumberForSampleGet(_currentPlaybackSampleNumber); 1184 1185 uint32 FirstSampleNumInChunk = 1186 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 1187 1188 uint32 offsetIntoRunOfChunks = 1189 (_currentPlaybackSampleNumber - FirstSampleNumInChunk); 1190 1191 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 1192 1193 if (offset == PV_ERROR) 1194 { 1195 _currentPlaybackSampleNumber = 0; 1196 return READ_FAILED; 1197 } 1198 1199 int32 sampleSizeOffset = 0; 1200 int32 tempSize = 0; 1201 1202 _currChunkOffset = 0; 1203 for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk + 1204 offsetIntoRunOfChunks; i++) 1205 { 1206 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 1207 if (tempSize == PV_ERROR) 1208 { 1209 _currentPlaybackSampleNumber = 0; 1210 return READ_FAILED; 1211 } 1212 sampleSizeOffset += tempSize; 1213 } 1214 _currChunkOffset = sampleSizeOffset; 1215 } 1216 1217 int32 retVal = getNextNSamples(_currentPlaybackSampleNumber, n, pgau); 1218 MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal; 1219 return errCode; 1220} 1221 1222// Returns next video frame 1223// Can optimize this by having the getNext()... use the seekg pointer to maintain the 1224// location where to read from 1225int32 1226SampleTableAtom::getNextSample(uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset) 1227{ 1228 int8 aFrameSizes[16] = {12, 13, 15, 17, 19, 20, 26, 31, 1229 5, 0, 0, 0, 0, 0, 0, 0 1230 }; 1231 1232 if (_ptimeToSampleAtom == NULL) 1233 { 1234 return READ_TIME_TO_SAMPLE_ATOM_FAILED; 1235 } 1236 1237 if (!_IsUpdateFileSize) 1238 { 1239 if (_pinput->IsOpen()) 1240 { 1241 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 1242 { 1243 return READ_FAILED; 1244 } 1245 } 1246 } 1247 1248 int32 tsDelta = 0; 1249 1250 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- _currentPlaybackSampleNumber =%d", _currentPlaybackSampleNumber)); 1251 if (_currentPlaybackSampleNumber != 0) 1252 { 1253 tsDelta = _ptimeToSampleAtom->getTimeDeltaForSampleNumberGet(_currentPlaybackSampleNumber); 1254 1255 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- tsDelta =%d", tsDelta)); 1256 1257 if (tsDelta == PV_ERROR) 1258 { 1259 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read Time to Sample Atom Failed")); 1260 return (READ_TIME_TO_SAMPLE_ATOM_FAILED); 1261 } 1262 1263 _currentPlaybackSampleTimestamp += (tsDelta + getCttsOffsetForSampleNumberGet(_currentPlaybackSampleNumber)); 1264 1265 } 1266 else 1267 { 1268 // Add TS offset to sample timestamps 1269 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1270 } 1271 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- _currentPlaybackSampleTimestamp =%d", _currentPlaybackSampleTimestamp)); 1272 if (_psampleDescriptionAtom->Is3GPPAMR()) 1273 { 1274 if (_amrSampleSize > 0) 1275 { 1276 uint8 frame_type = *(_pAMRTempBuffer + _amrTempBufferOffset); 1277 1278 frame_type = (uint8)((frame_type >> 3) & 0x0F); 1279 1280 _amrTempBufferOffset += 1; 1281 _amrSampleSize -= 1; 1282 1283 if ((frame_type > 9) && (frame_type != 15)) 1284 {//in fact, this should be "INVALID_AMR_FRAME_TYPE" 1285 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read AMR SAmple Entry Failed")); 1286 return (READ_AMR_SAMPLE_ENTRY_FAILED); 1287 } 1288 1289 int32 frame_size = aFrameSizes[(uint16)frame_type]; 1290 index = frame_type; 1291 1292 if (frame_size > size) 1293 { 1294 size = frame_size; 1295 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Insufficient Buffer Size")); 1296 return (INSUFFICIENT_BUFFER_SIZE); 1297 } 1298 1299 oscl_memcpy((void *)(buf), 1300 (void *)(_pAMRTempBuffer + _amrTempBufferOffset), 1301 frame_size); 1302 1303 _amrTempBufferOffset += frame_size; 1304 _amrSampleSize -= frame_size; 1305 1306 size = frame_size; 1307 return EVERYTHING_FINE; 1308 } 1309 else 1310 { 1311 _amrTempBufferOffset = 0; 1312 1313 _amrSampleSize = 512; 1314 int32 retval = getSample(_currentPlaybackSampleNumber, _pAMRTempBuffer, _amrSampleSize, index, SampleOffset); 1315 1316 if (retval != EVERYTHING_FINE) 1317 { 1318 // Reset Time Stamp 1319 _currentPlaybackSampleTimestamp -= (tsDelta + getCttsOffsetForSampleNumber(_currentPlaybackSampleNumber)); 1320 1321 return retval; 1322 } 1323 _currentPlaybackSampleNumber++; 1324 1325 _amrFrameTimeStamp = _currentPlaybackSampleTimestamp; 1326 1327 uint8 frame_type = *(_pAMRTempBuffer + _amrTempBufferOffset); 1328 1329 frame_type = (uint8)((frame_type >> 3) & 0x0F); 1330 1331 _amrTempBufferOffset += 1; 1332 _amrSampleSize -= 1; 1333 1334 if ((frame_type > 9) && (frame_type != 15)) 1335 {//in fact, this should be "INVALID_AMR_FRAME_TYPE" 1336 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read AMR SAmple Entry Failed")); 1337 return (READ_AMR_SAMPLE_ENTRY_FAILED); 1338 } 1339 1340 int32 frame_size = aFrameSizes[(uint16)frame_type]; 1341 1342 index = frame_type; 1343 1344 if (frame_size > size) 1345 { 1346 size = frame_size; 1347 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Insufficient Buffer Size")); 1348 return (INSUFFICIENT_BUFFER_SIZE); 1349 } 1350 1351 oscl_memcpy((void *)(buf), 1352 (void *)(_pAMRTempBuffer + _amrTempBufferOffset), 1353 frame_size); 1354 1355 _amrTempBufferOffset += frame_size; 1356 _amrSampleSize -= frame_size; 1357 1358 size = frame_size; 1359 return EVERYTHING_FINE; 1360 } 1361 } 1362 else 1363 { 1364 int32 retVal = getSample(_currentPlaybackSampleNumber, buf, size, index, SampleOffset); 1365 1366 if (retVal == EVERYTHING_FINE) 1367 { 1368 _currentPlaybackSampleNumber++; 1369 } 1370 else 1371 { 1372 // Reset Time Stamp 1373 _currentPlaybackSampleTimestamp -= (tsDelta + getCttsOffsetForSampleNumber(_currentPlaybackSampleNumber)); 1374 } 1375 1376 return retVal; 1377 } 1378} 1379 1380/*Reset PlayBack from Beginning*/ 1381void SampleTableAtom :: resetPlayBack() 1382{ 1383 _currentPlaybackSampleNumber = 0; 1384 _currentPlaybackSampleTimestamp = 0; 1385 _oResidualSample = false; 1386 _remainingFramesInSample = 0; 1387 _amrTempBufferOffset = 0; 1388 _ptimeToSampleAtom->resetStateVariables(); 1389 if (NULL != _pcompositionOffsetAtom) 1390 { 1391 _pcompositionOffsetAtom->resetStateVariables(); 1392 } 1393 _psampleToChunkAtom->resetStateVariables(); 1394 _currChunkOffset = 0; 1395} 1396 1397void SampleTableAtom ::resetTrackToEOT() 1398{ 1399 _currentPlaybackSampleNumber = getSampleSizeAtom().getSampleCount(); 1400} 1401int32 SampleTableAtom::queryRepositionTime(int32 time, bool oDependsOn, bool bBeforeRequestedTime) 1402{ 1403 int32 trueTS = 0; 1404 int32 currPlaybackSampleNum = 0; 1405 int32 currPlaybackSampleTS = 0; 1406 1407 if ((_psampleSizeAtom == NULL) || 1408 (_psampleToChunkAtom == NULL) || 1409 (_ptimeToSampleAtom == NULL) || 1410 (_pchunkOffsetAtom == NULL)) 1411 { 1412 return 0; 1413 } 1414 1415 if (time > (int32)_trackStartTSOffset) 1416 { 1417 currPlaybackSampleNum = 1418 getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset); 1419 // Go for composition offset adjustment. 1420 currPlaybackSampleNum = 1421 getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), currPlaybackSampleNum); 1422 } 1423 else 1424 { 1425 trueTS = _trackStartTSOffset; 1426 return (trueTS); 1427 } 1428 1429 if (currPlaybackSampleNum == PV_ERROR) 1430 { 1431 // SHOULD COME HERE ONLY IN CASE OF AUDIO & TEXT AND WE WANT TO SET THE 1432 // SAMPLE NUMBER IN THAT CASE TO THE LAST SAMPLE IN THE FILE 1433 if (getSampleSizeAtom().getSampleCount() > 0) 1434 { 1435 currPlaybackSampleNum = 1436 (getSampleSizeAtom().getSampleCount() - 1); 1437 1438 // This is to ensure that _currentPlaybackSampleTimestamp is set to the previous 1439 // sample, and not to the current sample, as this sample is yet to be read. 1440 if (currPlaybackSampleNum > 0) 1441 { 1442 currPlaybackSampleTS = 1443 getTimestampForSampleNumber(currPlaybackSampleNum - 1); 1444 1445 currPlaybackSampleTS += _trackStartTSOffset; 1446 } 1447 else // 1448 { 1449 currPlaybackSampleTS += getCttsOffsetForSampleNumber(0); 1450 } 1451 } 1452 else 1453 { 1454 currPlaybackSampleNum = 0; 1455 currPlaybackSampleTS = 0; 1456 } 1457 trueTS = currPlaybackSampleTS; 1458 return (trueTS); 1459 1460 } 1461 1462 //for video reset, we need to locate I frame 1463 if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_VISUAL) 1464 { 1465 //get the nearest I frame in front only for Base layer 1466 if (!oDependsOn) 1467 { 1468 1469 if (getSyncSampleAtom() != NULL) 1470 { 1471 if (getSyncSampleAtom()->getEntryCount() != 0) 1472 { 1473 if (bBeforeRequestedTime == true) 1474 { 1475 currPlaybackSampleNum = 1476 getSyncSampleAtom()->getSyncSampleBefore(currPlaybackSampleNum); 1477 } 1478 else 1479 { 1480 currPlaybackSampleNum = 1481 getSyncSampleAtom()->getSyncSampleFollowing(currPlaybackSampleNum); 1482 if (currPlaybackSampleNum == PV_ERROR) 1483 { 1484 currPlaybackSampleNum = 0; 1485 } 1486 } 1487 } 1488 else 1489 { 1490 // ZERO SYNC SAMPLE ENTRIES - ERROR CONDITION - RESET TO THR BEGINNING OF THE 1491 // CLIP 1492 currPlaybackSampleNum = 0; 1493 trueTS = _trackStartTSOffset; 1494 return (trueTS); 1495 } 1496 } 1497 else 1498 { 1499 // NO SYNC SAMPLE ATOM - ERROR CONDITION - RESET TO THR BEGINNING OF THE 1500 // CLIP 1501 currPlaybackSampleNum = 0; 1502 trueTS = _trackStartTSOffset; 1503 return (trueTS); 1504 } 1505 //get the timestamp based on the sample number 1506 } 1507 if (currPlaybackSampleNum != 0) 1508 { // ts for sample 0 is 0: No more correct incase CTTS exists 1509 currPlaybackSampleTS = 1510 getTimestampForSampleNumber(currPlaybackSampleNum); 1511 } 1512 else 1513 { 1514 currPlaybackSampleTS = getCttsOffsetForSampleNumber(0); 1515 } 1516 } 1517 else if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_AUDIO) 1518 { 1519 1520 1521 if (currPlaybackSampleNum > 0) 1522 { 1523 currPlaybackSampleTS = 1524 getTimestampForSampleNumber(currPlaybackSampleNum); 1525 1526 if (oDependsOn) 1527 { 1528 1529 /* 1530 * This check is required to ensure that audio track is positioned 1531 * ahead of the intra frame. This is 'cos the getSampleNumberFromTimestamp 1532 * returns the sample just before the passed time - This inturn is required 1533 * for video tracks where in the positioning has to be the closest intra frame 1534 * in the past. 1535 */ 1536 1537 if (currPlaybackSampleTS < time) 1538 { 1539 if ((currPlaybackSampleNum + 1) < (int32)getSampleSizeAtom().getSampleCount()) 1540 { 1541 currPlaybackSampleTS = 1542 getTimestampForSampleNumber(currPlaybackSampleNum); 1543 } 1544 } 1545 } 1546 } 1547 else 1548 { 1549 currPlaybackSampleTS = getCttsOffsetForSampleNumber(0); 1550 } 1551 } 1552 trueTS = currPlaybackSampleTS + _trackStartTSOffset; 1553 return trueTS; 1554} 1555 1556int32 SampleTableAtom::resetPlayBackbyTime(int32 time, bool oDependsOn) 1557{ 1558 int32 trueTS = 0; 1559 int32 retValA = 0 , retValB = 0; 1560 1561 if ((_psampleSizeAtom == NULL) || 1562 (_psampleToChunkAtom == NULL) || 1563 (_ptimeToSampleAtom == NULL) || 1564 (_pchunkOffsetAtom == NULL)) 1565 { 1566 return 0; 1567 } 1568 1569 _oResidualSample = false; 1570 _remainingFramesInSample = 0; 1571 _amrTempBufferOffset = 0; 1572 1573 if (time > (int32)_trackStartTSOffset) 1574 { 1575 int32 _tempSampleNumber = 1576 getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset); 1577 _tempSampleNumber = 1578 getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), _tempSampleNumber); 1579 1580 if (_currentPlaybackSampleNumber > _tempSampleNumber) 1581 { 1582 // In case of Backward Repos,the flag _SkipOldEntry in samplesizeatom.cpp is set to true to prevent 1583 // old entries from getting used. 1584 getSampleSizeAtom()._SkipOldEntry = true; 1585 } 1586 _currentPlaybackSampleNumber = 1587 getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset); 1588 1589 // Go for composition offset adjustment. 1590 _currentPlaybackSampleNumber = 1591 getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), _currentPlaybackSampleNumber); 1592 1593 } 1594 else 1595 { 1596 _currentPlaybackSampleNumber = 0; 1597 _currChunkOffset = 0; 1598 trueTS = _trackStartTSOffset; 1599 _ptimeToSampleAtom->resetStateVariables(); 1600 if (NULL != _pcompositionOffsetAtom) 1601 { 1602 _pcompositionOffsetAtom->resetStateVariables(); 1603 } 1604 _psampleToChunkAtom->resetStateVariables(); 1605 return (trueTS); 1606 } 1607 1608 if (_currentPlaybackSampleNumber == PV_ERROR) 1609 { 1610 // SHOULD COME HERE ONLY IN CASE OF AUDIO & TEXT AND WE WANT TO SET THE 1611 // SAMPLE NUMBER IN THAT CASE TO THE LAST SAMPLE IN THE FILE 1612 if (getSampleSizeAtom().getSampleCount() > 0) 1613 { 1614 _currentPlaybackSampleNumber = 1615 (getSampleSizeAtom().getSampleCount()); 1616 1617 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 1618 if (retValA == PV_ERROR) 1619 { 1620 _currentPlaybackSampleNumber = 0; 1621 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1622 _ptimeToSampleAtom->resetStateVariables(); 1623 return 0; 1624 } 1625 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 1626 if (retValB == PV_ERROR) 1627 { 1628 _currentPlaybackSampleNumber = 0; 1629 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1630 _psampleToChunkAtom->resetStateVariables(); 1631 return 0; 1632 } 1633 if (NULL != _pcompositionOffsetAtom) 1634 { 1635 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 1636 if (PV_ERROR == retValC) 1637 { 1638 _currentPlaybackSampleNumber = 0; 1639 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1640 _pcompositionOffsetAtom->resetStateVariables(); 1641 return 0; 1642 } 1643 } 1644 if (_currentPlaybackSampleNumber > 0) 1645 { 1646 _currentPlaybackSampleTimestamp = 1647 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1648 1649 _currentPlaybackSampleTimestamp += _trackStartTSOffset; 1650 } 1651 else 1652 { 1653 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 1654 } 1655 } 1656 else 1657 { 1658 _currentPlaybackSampleNumber = 0; 1659 _currentPlaybackSampleTimestamp = 0; 1660 } 1661 trueTS = _currentPlaybackSampleTimestamp; 1662 goto check_for_file_pointer_reset; 1663 } 1664 1665 //for video reset, we need to locate I frame 1666 if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_VISUAL) 1667 { 1668 //get the nearest I frame in front only for Base layer 1669 if (!oDependsOn) 1670 { 1671 if (getSyncSampleAtom() != NULL) 1672 { 1673 if (getSyncSampleAtom()->getEntryCount() != 0) 1674 { 1675 _currentPlaybackSampleNumber = 1676 getSyncSampleAtom()->getSyncSampleBefore(_currentPlaybackSampleNumber); 1677 } 1678 else 1679 { 1680 1681 // ZERO SYNC SAMPLE ENTRIES - ERROR CONDITION - RESET TO THR BEGINNING OF THE 1682 // CLIP 1683 _currentPlaybackSampleNumber = 0; 1684 trueTS = _trackStartTSOffset; 1685 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 1686 if (retValA == PV_ERROR) 1687 { 1688 _currentPlaybackSampleNumber = 0; 1689 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1690 _ptimeToSampleAtom->resetStateVariables(); 1691 return 0; 1692 } 1693 1694 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 1695 if (retValB == PV_ERROR) 1696 { 1697 _currentPlaybackSampleNumber = 0; 1698 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1699 _psampleToChunkAtom->resetStateVariables(); 1700 return 0; 1701 } 1702 1703 if (NULL != _pcompositionOffsetAtom) 1704 { 1705 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 1706 if (PV_ERROR == retValC) 1707 { 1708 _currentPlaybackSampleNumber = 0; 1709 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1710 _pcompositionOffsetAtom->resetStateVariables(); 1711 return 0; 1712 } 1713 } 1714 return (trueTS); 1715 } 1716 } 1717 else 1718 { 1719 // NO SYNC SAMPLE ATOM - ERROR CONDITION - RESET TO THR BEGINNING OF THE 1720 // CLIP 1721 _currentPlaybackSampleNumber = 0; 1722 trueTS = _trackStartTSOffset; 1723 _ptimeToSampleAtom->resetStateVariables(); 1724 if (NULL != _pcompositionOffsetAtom) 1725 { 1726 _pcompositionOffsetAtom->resetStateVariables(); 1727 } 1728 _psampleToChunkAtom->resetStateVariables(); 1729 return (trueTS); 1730 } 1731 } 1732 else 1733 { 1734 const uint32 totalnumSamples = getSampleSizeAtom().getSampleCount(); 1735 if ((uint32)_currentPlaybackSampleNumber < totalnumSamples) 1736 { 1737 // FOR ENHANCE LAYER GET THE SAMPLE CLOSEST TO THE CORRESPONDING BASE LAYER 1738 // AND INCREMENT IT BY ONE, AS THE SAMPLE CLOSEST ALWAYS RETURNS ONE PREVIOUS 1739 _currentPlaybackSampleNumber++; 1740 } 1741 } 1742 //get the timestamp based on the sample number 1743 if (_currentPlaybackSampleNumber != 0) 1744 { // ts for sample 0 is 0 1745 _currentPlaybackSampleTimestamp = 1746 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1747 } 1748 else 1749 { 1750 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 1751 } 1752 } 1753 else if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_AUDIO) 1754 { 1755 if (_currentPlaybackSampleNumber > 0) 1756 { 1757 _currentPlaybackSampleTimestamp = 1758 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1759 1760 if (oDependsOn) 1761 { 1762 /* 1763 * This check is required to ensure that audio tracks are positioned 1764 * ahead of the intra frame. This is 'cos the getSampleNumberFromTimestamp 1765 * returns the sample just before the passed time - This inturn is required 1766 * for video tracks where in the positioning has to be the closest intra frame 1767 * in the past. 1768 */ 1769 if (_currentPlaybackSampleTimestamp < (uint32)time) 1770 { 1771 if ((_currentPlaybackSampleNumber + 1) < (int32)getSampleSizeAtom().getSampleCount()) 1772 { 1773 _currentPlaybackSampleNumber++; 1774 _currentPlaybackSampleTimestamp = 1775 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1776 } 1777 } 1778 } 1779 } 1780 else 1781 { 1782 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 1783 } 1784 } 1785 else 1786 { 1787 if (_currentPlaybackSampleNumber > 0) 1788 { 1789 _currentPlaybackSampleTimestamp = 1790 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 1791 } 1792 else 1793 { 1794 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 1795 } 1796 } 1797 1798 trueTS = _currentPlaybackSampleTimestamp + _trackStartTSOffset; 1799 1800 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- _currentPlaybackSampleTimestamp =%d", _currentPlaybackSampleTimestamp)); 1801 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- _currentPlaybackSampleNumber =%d", _currentPlaybackSampleNumber)); 1802 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- trueTS =%d", trueTS)); 1803 1804 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 1805 if (retValA == PV_ERROR) 1806 { 1807 _currentPlaybackSampleNumber = 0; 1808 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1809 _ptimeToSampleAtom->resetStateVariables(); 1810 return 0; 1811 } 1812 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 1813 if (retValB == PV_ERROR) 1814 { 1815 _currentPlaybackSampleNumber = 0; 1816 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1817 _psampleToChunkAtom->resetStateVariables(); 1818 return 0; 1819 } 1820 if (NULL != _pcompositionOffsetAtom) 1821 { 1822 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 1823 if (PV_ERROR == retValC) 1824 { 1825 _currentPlaybackSampleNumber = 0; 1826 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 1827 _pcompositionOffsetAtom->resetStateVariables(); 1828 return 0; 1829 } 1830 } 1831 1832 { 1833 int32 chunk = 1834 getMutableSampleToChunkAtom(). 1835 getChunkNumberForSampleGet(_currentPlaybackSampleNumber); 1836 1837 uint32 FirstSampleNumInChunk = 1838 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 1839 1840 uint32 offsetIntoRunOfChunks = 1841 (_currentPlaybackSampleNumber - FirstSampleNumInChunk); 1842 1843 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 1844 1845 if (offset == PV_ERROR) 1846 { 1847 trueTS = 0; 1848 _currentPlaybackSampleNumber = 0; 1849 trueTS = _trackStartTSOffset; 1850 return (trueTS); 1851 } 1852 1853 int32 sampleSizeOffset = 0; 1854 int32 tempSize = 0; 1855 1856 _currChunkOffset = 0; 1857 for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk + 1858 offsetIntoRunOfChunks; i++) 1859 { 1860 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 1861 if (tempSize == PV_ERROR) 1862 { 1863 trueTS = 0; 1864 _currentPlaybackSampleNumber = 0; 1865 trueTS = _trackStartTSOffset; 1866 return (trueTS); 1867 } 1868 sampleSizeOffset += tempSize; 1869 } 1870 _currChunkOffset = sampleSizeOffset; 1871 } 1872 1873check_for_file_pointer_reset: 1874 //Reset the file pointer to the correct location. In case of non-interleaved 1875 //pv content, we do not seek for every media sample. 1876 if (_oPVContentDownloadable) 1877 { 1878 int32 sampleSize = 1879 _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber); 1880 1881 // Find chunk 1882 int32 chunk = 1883 _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber); 1884 1885 // Find first sample in that chunk 1886 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 1887 1888 // Find chunk offset to file 1889 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 1890 1891 //uint32 offset to int32, possible error for large files 1892 if (offset == PV_ERROR) 1893 { 1894 trueTS = 0; 1895 _currentPlaybackSampleNumber = 0; 1896 trueTS = _trackStartTSOffset; 1897 return (trueTS); 1898 } 1899 1900 // Need to add up all the sizes from the first sample in this run up to the 1901 // the requested sample (but not including it) 1902 int32 sampleSizeOffset = 0; 1903 int32 tempSize = 0; 1904 for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++) 1905 { 1906 // Check sample size from SampleSizeAtom 1907 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 1908 // Check for error condition 1909 if (tempSize == PV_ERROR) 1910 { 1911 trueTS = 0; 1912 _currentPlaybackSampleNumber = 0; 1913 trueTS = _trackStartTSOffset; 1914 return (trueTS); 1915 } 1916 sampleSizeOffset += tempSize; 1917 } 1918 1919 // Find actual file offset to sample 1920 int32 sampleFileOffset = offset + sampleSizeOffset; 1921 1922 if (!_pinput->IsOpen()) 1923 { 1924#ifdef OPEN_FILE_ONCE_PER_TRACK 1925 // Check if file is already open 1926 // Opens file in binary mode with read sharing permissions 1927 // Return Error in case the file open fails. 1928 if (AtomUtils::OpenMP4File(_filename, 1929 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 1930 _pinput) != 0) 1931 { 1932 return FILE_OPEN_FAILED; 1933 } 1934#else 1935 _pinput->_fileSize = _commonFilePtr->_fileSize; 1936 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 1937 AtomUtils::Flush(_pinput); 1938 AtomUtils::seekFromStart(_pinput, 0); 1939#endif 1940 if (!_IsUpdateFileSize) 1941 { 1942 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 1943 { 1944 trueTS = 0; 1945 _currentPlaybackSampleNumber = 0; 1946 trueTS = _trackStartTSOffset; 1947 return (trueTS); 1948 } 1949 } 1950 } 1951 1952 if (sampleFileOffset + sampleSize > (int32)_fileSize) 1953 { 1954 trueTS = 0; 1955 _currentPlaybackSampleNumber = 0; 1956 trueTS = _trackStartTSOffset; 1957 return (trueTS); 1958 } 1959 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 1960 } 1961 1962 return trueTS; 1963} 1964 1965//querySyncFrameBeforeTime 1966int32 SampleTableAtom::IsResetNeeded(int32 time) 1967{ 1968 if (_psyncSampleAtom != NULL) 1969 {//not all I frames 1970 if ((uint32)time > _currentPlaybackSampleTimestamp) 1971 {//forward 1972 int32 nextSyncNum = 1973 _psyncSampleAtom->getSyncSampleFollowing(_currentPlaybackSampleNumber); 1974 if ((PV_ERROR == nextSyncNum) 1975 || (time < (int32)getTimestampForSampleNumber(nextSyncNum))) 1976 {//1. past the last sync frame, no reset is needed 1977 //2. the sync frame is after the repositioning time, no reset is needed 1978 return DEFAULT_ERROR; 1979 } 1980 } 1981 } 1982 return EVERYTHING_FINE; 1983} 1984 1985int32 SampleTableAtom::getTimestampForRandomAccessPoints(uint32 *num, uint32 *tsBuf, uint32* numBuf, uint32* offsetBuf) 1986{ 1987 if (_psyncSampleAtom == NULL) 1988 { 1989 if (_psampleSizeAtom != NULL) 1990 { 1991 *num = _psampleSizeAtom->getSampleCount(); 1992 } 1993 return 2; //success : every sample is a random access point 1994 } 1995 1996 if (_ptimeToSampleAtom == NULL) 1997 { 1998 return 0; //fail 1999 } 2000 2001 uint32 tmp = _psyncSampleAtom->getEntryCount(); 2002 2003 if (*num == 0) 2004 { 2005 *num = tmp; 2006 return 1; //success. This is only the query mode. 2007 } 2008 if (*num > tmp) 2009 *num = tmp; 2010 2011 oscl_memcpy(numBuf, _psyncSampleAtom->getSampleNumberVector(), 2012 sizeof(uint32 *)*(*num)); 2013 2014 for (uint32 i = 0; i < *num; i++) 2015 {//it may crash if this buffer is not big enough 2016 tsBuf[i] = getTimestampForSampleNumber(numBuf[i] - 1); 2017 // Timestamps returned here should be presentation timestamps (must include 2018 // the ctts offset. Calling getTimestampForSampleNumber will take care of it. 2019 numBuf[i] = numBuf[i] - 1; 2020 int32 offset = 0; 2021 if (offsetBuf != NULL) 2022 { 2023 if (getOffsetByTime(tsBuf[i], &offset) != DEFAULT_ERROR) 2024 offsetBuf[i] = offset; 2025 } 2026 } 2027 return 1; //success 2028} 2029 2030 2031int32 SampleTableAtom::getTimestampForRandomAccessPointsBeforeAfter(uint32 ts, uint32 *tsBuf, uint32* numBuf, uint32& numsamplestoget, uint32 howManyKeySamples) 2032{ 2033 if (_psyncSampleAtom == NULL) 2034 { 2035 return 2; //success : every sample is a random access point 2036 } 2037 2038 if (_ptimeToSampleAtom == NULL) 2039 { 2040 return 0; //fail 2041 } 2042 2043 2044 uint32 numSyncSamples = _psyncSampleAtom->getEntryCount(); 2045 int32 SampleNumber = 2046 _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts); 2047 2048 // Go for composition offset adjustment. 2049 SampleNumber = 2050 getSampleNumberAdjustedWithCTTS(ts, SampleNumber); 2051 2052 if ((int32)SampleNumber == PV_ERROR) 2053 { 2054 return PV_ERROR; 2055 } 2056 2057 2058 int32 SampleNumberForTS = _psyncSampleAtom->getSyncSampleBefore(SampleNumber); 2059 if (SampleNumberForTS == PV_ERROR) 2060 { 2061 return PV_ERROR; 2062 } 2063 uint32 startIdx = 0, endIdx = 0, k = 0, idx = 0; 2064 for (idx = 0; idx < numSyncSamples; idx++) 2065 { 2066 int32 tempSampleNum = _psyncSampleAtom->getSampleNumberAt(idx); 2067 if (SampleNumberForTS == tempSampleNum) 2068 { 2069 startIdx = idx + 1; 2070 endIdx = numSyncSamples; 2071 break; 2072 } 2073 } 2074 2075 if ((startIdx + howManyKeySamples) <= numSyncSamples) 2076 endIdx = startIdx + howManyKeySamples; 2077 2078 if (startIdx >= howManyKeySamples) 2079 startIdx -= howManyKeySamples; 2080 else 2081 startIdx = 0; 2082 2083 idx = 0; 2084 for (idx = startIdx; idx < endIdx; idx++) 2085 { 2086 int32 keySampleNum = _psyncSampleAtom->getSampleNumberAt(idx); 2087 int32 keySampleTS = getTimestampForSampleNumber(keySampleNum); 2088 // Timestamps returned here should be presentation timestamps (must include 2089 // the ctts offset. Calling getTimestampForSampleNumber will take care of it. 2090 2091 if (keySampleNum != PV_ERROR && 2092 keySampleTS != PV_ERROR) 2093 { 2094 numBuf[k] = keySampleNum; 2095 tsBuf[k] = keySampleTS; 2096 k++; 2097 } 2098 } 2099 numsamplestoget = k; 2100 2101 return 1; //success 2102} 2103 2104uint32 SampleTableAtom::getTimestampForSampleNumber(uint32 sampleNumber) 2105{ 2106 if ((NULL != _ptimeToSampleAtom) && (NULL != _pcompositionOffsetAtom)) 2107 { 2108 return (_ptimeToSampleAtom->getTimestampForSampleNumber(sampleNumber) 2109 + _pcompositionOffsetAtom->getTimeOffsetForSampleNumber(sampleNumber)); 2110 } 2111 2112 else if (NULL != _ptimeToSampleAtom) 2113 { 2114 return _ptimeToSampleAtom->getTimestampForSampleNumber(sampleNumber); 2115 } 2116 2117 // It is not permitted that _pcompositionOffsetAtom without _ptimeToSampleAtom. Thus for any other 2118 // combination return 0. 2119 else 2120 { 2121 return 0; 2122 } 2123} 2124 2125int32 SampleTableAtom::getCttsOffsetForSampleNumberPeek(uint32 sampleNumber) 2126{ 2127 int32 tempCompositionOffset = 0; 2128 // compositionOffsetAtom adjustment if compositionOffsetAtom exits 2129 if (NULL != _pcompositionOffsetAtom) 2130 { 2131 tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumberPeek(sampleNumber); 2132 if (PV_ERROR != tempCompositionOffset) 2133 { 2134 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumberPeek- CTTS(%d) = %d", sampleNumber, tempCompositionOffset)); 2135 return tempCompositionOffset; 2136 } 2137 else 2138 { 2139 // It's not an issue if the CTTS is not present or not parsed correctly. 2140 return 0; 2141 } 2142 } 2143 return 0; 2144} 2145 2146// The difference between getCttsOffsetForSampleNumber and getCttsOffsetForSampleNumberGet 2147// is that the getCttsOffsetForSampleNumberGet is meant to be caled in a consequtive manner, 2148// However getCttsOffsetForSampleNumber could be called anywhere without past reference. 2149int32 SampleTableAtom::getCttsOffsetForSampleNumber(uint32 sampleNumber) 2150{ 2151 int32 tempCompositionOffset = 0; 2152 // compositionOffsetAtom adjustment if compositionOffsetAtom exits 2153 if (NULL != _pcompositionOffsetAtom) 2154 { 2155 tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumber(sampleNumber); 2156 if (PV_ERROR != tempCompositionOffset) 2157 { 2158 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumber- CTTS(%d) = %d", sampleNumber, tempCompositionOffset)); 2159 return tempCompositionOffset; 2160 } 2161 else 2162 { 2163 // It's not an issue if the CTTS is not present or not parsed correctly. 2164 return 0; 2165 } 2166 } 2167 return 0; 2168} 2169 2170int32 SampleTableAtom::getCttsOffsetForSampleNumberGet(uint32 sampleNumber) 2171{ 2172 int32 tempCompositionOffset = 0; 2173 // compositionOffsetAtom adjustment if compositionOffsetAtom exits 2174 if (NULL != _pcompositionOffsetAtom) 2175 { 2176 tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumberGet(sampleNumber); 2177 if (PV_ERROR != tempCompositionOffset) 2178 { 2179 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumberGet- CTTS(%d) = %d", sampleNumber, tempCompositionOffset)); 2180 return tempCompositionOffset; 2181 } 2182 else 2183 { 2184 // It's not an issue if the CTTS is not present or not parsed correctly. 2185 return 0; 2186 } 2187 } 2188 return 0; 2189} 2190 2191 2192// Returns next I-frame at time ts (in milliseconds) - or the very next I-frame in the stream 2193int32 2194SampleTableAtom::getNextSampleAtTime(uint32 ts, uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset) 2195{ 2196 if ((_ptimeToSampleAtom == NULL) || 2197 (_psyncSampleAtom == NULL)) 2198 { 2199 size = 0; 2200 return 0; 2201 } 2202 2203 // Get sample number at timestamp 2204 _currentPlaybackSampleNumber = 2205 _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts); 2206 2207 if (_currentPlaybackSampleNumber == PV_ERROR) 2208 { 2209 size = 0; 2210 return 0; 2211 } 2212 2213 // Go for composition offset adjustment. 2214 _currentPlaybackSampleNumber = 2215 getSampleNumberAdjustedWithCTTS(ts, _currentPlaybackSampleNumber); 2216 2217 // Check if sample is an I-frame. If not, need to find the sample number of the 2218 // first I-frame sample that follows ts 2219 // Need to check syncSampleAtom for this - if not present, all samples are synch samples 2220 // (i.e. all audio samples are synch samples) 2221 _currentPlaybackSampleNumber = 2222 _psyncSampleAtom->getSyncSampleFollowing(_currentPlaybackSampleNumber); 2223 2224 if (_currentPlaybackSampleNumber == PV_ERROR) 2225 { 2226 size = 0; 2227 return 0; 2228 } 2229 2230 // Increment ts for current sample in this random access; No more correct in case of CTTS presence 2231 if (_currentPlaybackSampleNumber != 0) 2232 { 2233 // ts for sample 0 is 0 2234 _currentPlaybackSampleTimestamp = 2235 getTimestampForSampleNumber(_currentPlaybackSampleNumber); 2236 } 2237 else 2238 { 2239 _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0); 2240 } 2241 2242 return getSample(_currentPlaybackSampleNumber++, buf, size, index, SampleOffset); 2243} 2244 2245 2246int32 2247SampleTableAtom::getNextBundledAccessUnits(uint32 *n, 2248 GAU *pgau) 2249{ 2250 int32 nReturn = -1; 2251 2252 if ((_psampleSizeAtom == NULL) || 2253 (_psampleToChunkAtom == NULL) || 2254 (_ptimeToSampleAtom == NULL) || 2255 (_pchunkOffsetAtom == NULL)) 2256 { 2257 return (nReturn); 2258 } 2259 2260 if (_currentPlaybackSampleNumber == 0) 2261 { 2262 // Add TS offset to sample timestamps 2263 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2264 } 2265 2266 uint32 numSamples = getSampleSizeAtom().getSampleCount(); 2267 2268 if (_currentPlaybackSampleNumber >= (int32)numSamples) 2269 { 2270 *n = 0; 2271 pgau->info[0].ts = 0; //_currentPlaybackSampleTimestamp; 2272 nReturn = END_OF_TRACK; 2273 return nReturn; 2274 } 2275 2276 nReturn = getNextNSamples(_currentPlaybackSampleNumber, n, pgau); 2277 2278 if (nReturn == INSUFFICIENT_BUFFER_SIZE) 2279 { 2280 return nReturn; 2281 } 2282 2283 /* 2284 * This check is intentionally not done in case of 3GPP AMR as there can 2285 * still be frames in the temp buffer, and they will be retrieved when 2286 * get N is called the next time. 2287 */ 2288 if (!_psampleDescriptionAtom->Is3GPPAMR()) 2289 { 2290 if (_currentPlaybackSampleNumber >= (int32)numSamples) 2291 { 2292 nReturn = END_OF_TRACK; 2293 return nReturn; 2294 } 2295 } 2296 2297 if ((nReturn == INVALID_SAMPLE_SIZE) || 2298 (nReturn == INVALID_CHUNK_OFFSET)) 2299 { 2300 nReturn = READ_FAILED; 2301 return nReturn; 2302 } 2303 return nReturn; 2304} 2305 2306int32 2307SampleTableAtom::peekNextBundledAccessUnits(uint32 *n, 2308 MediaMetaInfo *mInfo) 2309{ 2310 int32 nReturn = -1; 2311 2312 if ((_psampleSizeAtom == NULL) || 2313 (_psampleToChunkAtom == NULL) || 2314 (_ptimeToSampleAtom == NULL) || 2315 (_pchunkOffsetAtom == NULL)) 2316 { 2317 return -1; 2318 } 2319 2320 if (_currentPlaybackSampleNumber == 0) 2321 { 2322 // Add TS offset to sample timestamps 2323 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2324 } 2325 2326 nReturn = peekNextNSamples(_currentPlaybackSampleNumber, n, mInfo); 2327 2328 if ((nReturn == INVALID_SAMPLE_SIZE) || 2329 (nReturn == INVALID_CHUNK_OFFSET)) 2330 { 2331 nReturn = READ_FAILED; 2332 return nReturn; 2333 } 2334 2335 return nReturn; 2336} 2337 2338int32 2339SampleTableAtom::getNextNSamples(uint32 startSampleNum, 2340 uint32 *n, 2341 GAU *pgau) 2342{ 2343 uint32 chunk = 0; 2344 int32 numSamplesPerChunk = 0, currTSBase = 0; 2345 uint32 numChunksInRun = 0, FirstSampleNumInChunk = 0; 2346 uint32 offsetIntoRunOfChunks = 0, samplesLeftInChunk = 0; 2347 uint32 numSamples = 0; 2348 uint32 startSampleNumTSBase = 0; 2349 uint32 samplesYetToBeRead = *n; 2350 uint32 sampleNum = startSampleNum; 2351 bool oStoreOffset = false; 2352 int32 sampleBeforeGet = (int32)startSampleNum; 2353 2354 uint32 s = 0; 2355 uint32 end = 0; 2356 2357 uint32 i = 0, j = 0, k = 0; 2358 2359 int32 _mp4ErrorCode = EVERYTHING_FINE; 2360 2361 if (!_IsUpdateFileSize) 2362 { 2363 if (_pinput->IsOpen()) 2364 { 2365 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 2366 { 2367 *n = 0; 2368 _mp4ErrorCode = READ_FAILED; 2369 return _mp4ErrorCode; 2370 } 2371 } 2372 } 2373 2374 currTSBase = _currentPlaybackSampleTimestamp; 2375 startSampleNumTSBase = _currentPlaybackSampleTimestamp; 2376 end = pgau->buf.num_fragments; 2377 2378 GAU tempGau; 2379 tempGau = *pgau; 2380 GAU* tempgauPtr = &tempGau; 2381 2382 k = 0; 2383 2384 uint32 totalnumSamples = getSampleSizeAtom().getSampleCount(); 2385 2386 if (sampleNum >= totalnumSamples) 2387 { 2388 *n = 0; 2389 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - End Of Track")); 2390 _mp4ErrorCode = END_OF_TRACK; 2391 return (_mp4ErrorCode); 2392 } 2393 2394#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2395 uint32 totalTimeSTSC = 0; 2396 uint32 totalTimeSTSZ = 0; 2397 uint32 totalTimeSTTS = 0; 2398 uint32 totalTimeCTTS = 0; 2399 uint32 totalTimeFileSeek = 0; 2400 uint32 totalTimeFileRead = 0; 2401 2402 uint32 currticks, StartTime, EndTime; 2403#endif 2404 uint32 totalBytesRead = 0; 2405 while (samplesYetToBeRead) 2406 { 2407#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2408 currticks = OsclTickCount::TickCount(); 2409 StartTime = OsclTickCount::TicksToMsec(currticks); 2410#endif 2411 // Find chunk 2412 chunk = 2413 getMutableSampleToChunkAtom(). 2414 getChunkNumberForSampleGet(sampleNum); 2415 2416 //This method needs to be added to sample to chunk atom 2417 numChunksInRun = 2418 getSampleToChunkAtom().getNumChunksInRunofChunksGet(); 2419 2420 if (numChunksInRun == uint32(PV_ERROR)) 2421 { 2422 *n = 0; 2423 _mp4ErrorCode = READ_SAMPLE_TO_CHUNK_ATOM_FAILED; 2424 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Read Sample to Chunk Atom Failed")); 2425 return (_mp4ErrorCode); 2426 } 2427 2428 numSamplesPerChunk = 2429 getSampleToChunkAtom().getSamplesPerChunkCorrespondingToSampleGet(); 2430 2431 FirstSampleNumInChunk = 2432 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 2433#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2434 currticks = OsclTickCount::TickCount(); 2435 EndTime = OsclTickCount::TicksToMsec(currticks); 2436 totalTimeSTSC += (EndTime - StartTime); 2437#endif 2438 2439 offsetIntoRunOfChunks = 2440 (sampleNum - FirstSampleNumInChunk); 2441 2442 // All chunks in a run of chunks ARE NOT CONTIGUOUS!!!! 2443 samplesLeftInChunk = 2444 ((numSamplesPerChunk) - offsetIntoRunOfChunks); 2445 2446 if (samplesLeftInChunk > samplesYetToBeRead) 2447 { 2448 numSamples = samplesYetToBeRead; 2449 samplesYetToBeRead = 0; 2450 oStoreOffset = true; 2451 } 2452 else 2453 { 2454 samplesYetToBeRead -= samplesLeftInChunk; 2455 numSamples = samplesLeftInChunk; 2456 oStoreOffset = false; 2457 } 2458 2459 int32 SDIndex = getSampleToChunkAtom().getSDIndexGet(); 2460 2461 if (SDIndex > 0) 2462 { 2463 SDIndex -= 1; 2464 } 2465 2466 2467 // Find chunk offset to file 2468 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 2469 2470 2471 if (offset == PV_ERROR) 2472 { 2473 _mp4ErrorCode = INVALID_CHUNK_OFFSET; 2474 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Invalid Chunk Offset")); 2475 break; 2476 } 2477 2478 // Need to add up all the sizes from the first sample in this run up to the 2479 // the requested sample (but not including it) 2480 2481 int32 sampleSizeOffset = 0; 2482 int32 tempSize = 0; 2483 2484 uint32 sigmaSampleSize = 0; 2485 2486 for (j = sampleNum; 2487 j < (sampleNum + numSamples); 2488 j++) 2489 { 2490 // Check sample size from SampleSizeAtom 2491 tempSize = getSampleSizeAtom().getDefaultSampleSize(); 2492 2493 if (tempSize == 0) 2494 { 2495#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2496 currticks = OsclTickCount::TickCount(); 2497 StartTime = OsclTickCount::TicksToMsec(currticks); 2498#endif 2499 // Need to get specific sample size 2500 tempSize = getSampleSizeAtom().getSampleSizeAt(j); 2501#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2502 currticks = OsclTickCount::TickCount(); 2503 EndTime = OsclTickCount::TicksToMsec(currticks); 2504 totalTimeSTSZ += (EndTime - StartTime); 2505#endif 2506 } 2507 2508 // Check for error condition 2509 if (tempSize == -1) 2510 { 2511 *n = 0; 2512 _mp4ErrorCode = INVALID_SAMPLE_SIZE; 2513 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Invalid Sample Size")); 2514 return (_mp4ErrorCode); 2515 } 2516 2517 sigmaSampleSize += tempSize; 2518 2519 pgau->info[s].len = tempSize; 2520 2521 int32 tsDelta = 0; 2522 2523 if (j == 0) 2524 { 2525 // Add TS offset to sample timestamps if it is the first sample 2526 currTSBase = _trackStartTSOffset; 2527 } 2528 2529#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2530 currticks = OsclTickCount::TickCount(); 2531 StartTime = OsclTickCount::TicksToMsec(currticks); 2532#endif 2533 tsDelta = _ptimeToSampleAtom->getTimeDeltaForSampleNumberGet(j); 2534#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2535 currticks = OsclTickCount::TickCount(); 2536 EndTime = OsclTickCount::TicksToMsec(currticks); 2537 totalTimeSTTS += (EndTime - StartTime); 2538#endif 2539 2540 if (tsDelta == PV_ERROR) 2541 { 2542 *n = 0; 2543 _mp4ErrorCode = READ_FAILED; 2544 return (_mp4ErrorCode); 2545 } 2546 2547#ifdef OUTPUT_AMR_TOC 2548 uint8 objectType = getObjectTypeIndication(); 2549 if (objectType == AMR_AUDIO) 2550 { 2551 AMRDecoderSpecificInfo *pinfo = 2552 (AMRDecoderSpecificInfo *)(getDecoderSpecificInfoForSDI(SDIndex)); 2553 2554 if (pgau->info[s].sample_info != pinfo->getFrameType()) 2555 { 2556 pgau->info[s].sample_info = pinfo->getFrameType(); 2557 } 2558 else 2559 { 2560 pgau->info[s].sample_info = pinfo->getFrameType(); 2561 } 2562 2563 } 2564 else 2565 { 2566 pgau->info[s].sample_info = SDIndex; 2567 } 2568#else 2569 pgau->info[s].sample_info = SDIndex; 2570#endif 2571 2572 pgau->info[s].ts_delta = tsDelta; 2573 2574#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2575 currticks = OsclTickCount::TickCount(); 2576 StartTime = OsclTickCount::TicksToMsec(currticks); 2577#endif 2578 pgau->info[s].ts = currTSBase + getCttsOffsetForSampleNumberGet(j); 2579#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2580 currticks = OsclTickCount::TickCount(); 2581 EndTime = OsclTickCount::TicksToMsec(currticks); 2582 totalTimeCTTS += (EndTime - StartTime); 2583#endif 2584 2585 currTSBase += tsDelta; 2586 2587 2588 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].sample_info =%d", s, pgau->info[s].sample_info)); 2589 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].ts_delta =%d", s, pgau->info[s].ts_delta)); 2590 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].ts =%d", s, pgau->info[s].ts)); 2591 2592 2593 s++; 2594 } 2595 2596 // Find actual file offset to sample 2597 int32 sampleFileOffset = offset + _currChunkOffset; 2598 Oscl_Int64_Utils::set_uint64(pgau->SampleOffset, 0, (uint32)sampleFileOffset); 2599 2600 // Open file 2601 if (!_pinput->IsOpen()) 2602 { 2603#ifdef OPEN_FILE_ONCE_PER_TRACK 2604 // Check if file is already open 2605 // Opens file in binary mode with read sharing permissions 2606 // Return Error in case the file open fails. 2607 if (AtomUtils::OpenMP4File(_filename, 2608 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 2609 _pinput) != 0) 2610 { 2611 *n = 0; 2612 return FILE_OPEN_FAILED; 2613 } 2614#else 2615 _pinput->_fileSize = _commonFilePtr->_fileSize; 2616 _pinput->_pvfile.Copy(_commonFilePtr->_pvfile); 2617 AtomUtils::Flush(_pinput); 2618 AtomUtils::seekFromStart(_pinput, 0); 2619#endif 2620 if (!_IsUpdateFileSize) 2621 { 2622 if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false) 2623 { 2624 *n = 0; 2625 _mp4ErrorCode = READ_FAILED; 2626 return _mp4ErrorCode; 2627 } 2628 } 2629 } 2630 2631 uint32 bufStart = 0; 2632 uint32 bufEnd = _fileSize; 2633 uint32 bufCap = AtomUtils::getFileBufferingCapacity(_pinput); 2634 if (bufCap) 2635 { 2636 // progressive playback 2637 // MBDS contains only a range of bytes 2638 // first byte is not always 0 2639 AtomUtils::getCurrentByteRange(_pinput, bufStart, bufEnd); 2640 2641 // bufEnd is the offset of the last byte 2642 // need to turn it into a length, like _fileSize above 2643 bufEnd++; 2644 } 2645 2646 if (((uint32)sampleFileOffset < bufStart) || ((sigmaSampleSize + sampleFileOffset) > bufEnd)) 2647 { 2648 if ((uint32)_currentPlaybackSampleNumber != startSampleNum) 2649 { 2650 _currentPlaybackSampleNumber = startSampleNum; 2651 _currentPlaybackSampleTimestamp = startSampleNumTSBase; 2652 int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 2653 if (retValA == PV_ERROR) 2654 { 2655 _currentPlaybackSampleNumber = 0; 2656 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2657 _ptimeToSampleAtom->resetStateVariables(); 2658 return retValA; 2659 } 2660 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 2661 if (retValB == PV_ERROR) 2662 { 2663 _currentPlaybackSampleNumber = 0; 2664 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2665 _psampleToChunkAtom->resetStateVariables(); 2666 return retValB; 2667 } 2668 if (NULL != _pcompositionOffsetAtom) 2669 { 2670 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 2671 if (retValC == PV_ERROR) 2672 { 2673 _currentPlaybackSampleNumber = 0; 2674 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2675 _pcompositionOffsetAtom->resetStateVariables(); 2676 return retValC; 2677 } 2678 } 2679 chunk = 2680 getMutableSampleToChunkAtom(). 2681 getChunkNumberForSampleGet(_currentPlaybackSampleNumber); 2682 2683 //This method needs to be added to sample to chunk atom 2684 numChunksInRun = 2685 getSampleToChunkAtom().getNumChunksInRunofChunksGet(); 2686 2687 FirstSampleNumInChunk = 2688 getSampleToChunkAtom().getFirstSampleNumInChunkGet(); 2689 2690 offsetIntoRunOfChunks = 2691 (_currentPlaybackSampleNumber - FirstSampleNumInChunk); 2692 2693 sampleSizeOffset = 0; 2694 for (i = FirstSampleNumInChunk; i < FirstSampleNumInChunk + 2695 offsetIntoRunOfChunks; i++) 2696 { 2697 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 2698 sampleSizeOffset += tempSize; 2699 } 2700 _currChunkOffset = sampleSizeOffset; 2701 } 2702 2703 _mp4ErrorCode = INSUFFICIENT_DATA; 2704 if (bufCap) 2705 { 2706 // if MBDS, may need to kick of a http request 2707 uint32 contentLength = AtomUtils::getContentLength(_pinput); 2708 if ((0 != contentLength) && ((sigmaSampleSize + sampleFileOffset) > contentLength)) 2709 { 2710 // do not skip beyond end of clip 2711 // if content length is known 2712 _mp4ErrorCode = READ_FAILED; 2713 } 2714 else 2715 { 2716 AtomUtils::skipFromStart(_pinput, sampleFileOffset); 2717 } 2718 } 2719 2720 *n = 0; 2721 for (uint32 i = 0; i < pgau->numMediaSamples; i++) 2722 { 2723 pgau->info[i].len = 0; 2724 pgau->info[i].ts = 0; 2725 pgau->info[i].sample_info = 0; 2726 } 2727 2728 return (_mp4ErrorCode); 2729 } 2730 uint32 start = 0; 2731 uint32 rewindPos = 0; 2732 uint32 totalFragmentLength = 0; 2733 for (k = start; k < end; k++) 2734 { 2735 totalFragmentLength += tempgauPtr->buf.fragments[k].len; 2736 } 2737 2738 if (totalFragmentLength < sigmaSampleSize) 2739 { 2740 //INSUFFICIENT BUFFER SIZE 2741 _currentPlaybackSampleNumber = startSampleNum; 2742 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2743 int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber); 2744 if (retValA == PV_ERROR) 2745 { 2746 _currentPlaybackSampleNumber = 0; 2747 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2748 _ptimeToSampleAtom->resetStateVariables(); 2749 return retValA; 2750 } 2751 int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber); 2752 if (retValB == PV_ERROR) 2753 { 2754 _currentPlaybackSampleNumber = 0; 2755 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2756 _psampleToChunkAtom->resetStateVariables(); 2757 return retValB; 2758 } 2759 if (NULL != _pcompositionOffsetAtom) 2760 { 2761 int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber); 2762 if (retValC == PV_ERROR) 2763 { 2764 _currentPlaybackSampleNumber = 0; 2765 _currentPlaybackSampleTimestamp = _trackStartTSOffset; 2766 _pcompositionOffsetAtom->resetStateVariables(); 2767 return retValC; 2768 } 2769 } 2770 return INSUFFICIENT_BUFFER_SIZE; 2771 } 2772 2773 if (oStoreOffset) 2774 _currChunkOffset += sigmaSampleSize; 2775 else 2776 _currChunkOffset = 0; 2777#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2778 currticks = OsclTickCount::TickCount(); 2779 StartTime = OsclTickCount::TicksToMsec(currticks); 2780#endif 2781#ifdef OPEN_FILE_ONCE_PER_TRACK 2782 if (_oPVContentDownloadable) 2783 { 2784 if (_currentPlaybackSampleNumber == 0) 2785 { 2786 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 2787 } 2788 } 2789 else 2790 { 2791 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 2792 } 2793#else 2794 AtomUtils::seekFromStart(_pinput, sampleFileOffset); 2795#endif 2796#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2797 currticks = OsclTickCount::TickCount(); 2798 EndTime = OsclTickCount::TicksToMsec(currticks); 2799 totalTimeFileSeek += (EndTime - StartTime); 2800 2801 currticks = OsclTickCount::TickCount(); 2802 StartTime = OsclTickCount::TicksToMsec(currticks); 2803#endif 2804 start = 0; 2805 rewindPos = 0; 2806 for (k = start; k < end; k++) 2807 { 2808 uint32 tmpSize = 2809 (tempgauPtr->buf.fragments[k].len > sigmaSampleSize) ? sigmaSampleSize : tempgauPtr->buf.fragments[k].len; 2810 if (tmpSize) 2811 { 2812 if (!AtomUtils::readByteData(_pinput, tmpSize, 2813 (uint8 *)(tempgauPtr->buf.fragments[k].ptr))) 2814 { 2815 *n = 0; 2816 _mp4ErrorCode = READ_FAILED; 2817 return (_mp4ErrorCode); 2818 } 2819 tempgauPtr->buf.fragments[k].len -= tmpSize; 2820 2821 uint8* fragment_ptr = NULL; 2822 fragment_ptr = (uint8 *)(tempgauPtr->buf.fragments[k].ptr); 2823 fragment_ptr += tmpSize; 2824 tempgauPtr->buf.fragments[k].ptr = fragment_ptr; 2825 2826 sigmaSampleSize -= tmpSize; 2827 totalBytesRead += tmpSize; 2828 2829 } 2830 rewindPos += tmpSize; 2831 2832 if (sigmaSampleSize == 0) 2833 { 2834 break; 2835 } 2836 } 2837#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2838 currticks = OsclTickCount::TickCount(); 2839 EndTime = OsclTickCount::TicksToMsec(currticks); 2840 totalTimeFileRead += (EndTime - StartTime); 2841#endif 2842 2843 sampleNum = sampleNum + numSamples; 2844 2845 /* 2846 * This check is required to protect the FF lib from context 2847 * switching. 2848 */ 2849 if (_currentPlaybackSampleNumber == sampleBeforeGet) 2850 { 2851 _currentPlaybackSampleNumber += numSamples; 2852 sampleBeforeGet += numSamples; 2853 } 2854 else 2855 { 2856 break; 2857 } 2858 2859 if (_currentPlaybackSampleNumber >= (int32)totalnumSamples) 2860 { 2861 _mp4ErrorCode = END_OF_TRACK; 2862 break; 2863 } 2864 } 2865 2866 if (_currentPlaybackSampleNumber == sampleBeforeGet) 2867 { 2868 _currentPlaybackSampleTimestamp = currTSBase; 2869 *n = (*n - samplesYetToBeRead); 2870#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG) 2871 if (totalTimeSTSC > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2872 { 2873 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "PVMFMP4FFParserNode - SampleTableAtom::totalTimeSTSZ - NPT=%d, N=%d, Time=%d", 2874 currTSBase, 2875 *n, 2876 totalTimeSTSC)); 2877 } 2878 if (totalTimeSTSZ > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2879 { 2880 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeSTSZ - NPT=%d, N=%d, Time=%d", 2881 currTSBase, 2882 *n, 2883 totalTimeSTSZ)); 2884 } 2885 if (totalTimeSTTS > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2886 { 2887 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeSTTS - NPT=%d, N=%d, Time=%d", 2888 currTSBase, 2889 *n, 2890 totalTimeSTTS)); 2891 } 2892 if (totalTimeCTTS > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2893 { 2894 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeCTTS - NPT=%d, N=%d, Time=%d", 2895 currTSBase, 2896 *n, 2897 totalTimeCTTS)); 2898 } 2899 if (totalTimeFileSeek > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2900 { 2901 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeFileSeek - NPT=%d, N=%d, Time=%d", 2902 currTSBase, 2903 *n, 2904 totalTimeFileSeek)); 2905 } 2906 if (totalTimeFileRead > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS) 2907 { 2908 PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeFileRead - NPT=%d, N=%d, BytesRead=%d, Time=%d", 2909 currTSBase, 2910 *n, 2911 totalBytesRead, 2912 totalTimeFileRead)); 2913 } 2914#endif 2915 } 2916 else 2917 { 2918 if (_currentPlaybackSampleNumber > 0) 2919 { 2920 _currentPlaybackSampleTimestamp = 2921 getTimestampForSampleNumber(_currentPlaybackSampleNumber - 1); 2922 2923 _currentPlaybackSampleTimestamp += _trackStartTSOffset; 2924 } 2925 else 2926 { 2927 _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0); 2928 } 2929 2930 *n = 0; 2931 if (_mp4ErrorCode != INSUFFICIENT_BUFFER_SIZE) 2932 { 2933 _mp4ErrorCode = READ_FAILED; 2934 } 2935 } 2936 return (_mp4ErrorCode); 2937} 2938 2939int32 2940SampleTableAtom::peekNextNSamples(uint32 startSampleNum, 2941 uint32 *n, 2942 MediaMetaInfo *mInfo) 2943{//this API is only called in peekNextBundledAccessUnits(), which already check _psampleSizeAtom is NULL 2944 2945 2946 int32 currTSBase = _currentPlaybackSampleTimestamp; 2947 int32 i = 0; 2948 uint32 sampleNum = startSampleNum; 2949 int32 samplesToBePeeked = *n; 2950 2951 int32 _mp4ErrorCode = EVERYTHING_FINE; 2952 2953 if (_psampleToChunkAtom->getCurrPeekSampleCount() != 2954 (uint32)_currentPlaybackSampleNumber) 2955 { 2956 _psampleToChunkAtom->resetPeekwithGet(); 2957 } 2958 2959 if (_ptimeToSampleAtom->getCurrPeekSampleCount() != 2960 (uint32)_currentPlaybackSampleNumber) 2961 { 2962 _ptimeToSampleAtom->resetPeekwithGet(); 2963 } 2964 2965 2966 2967 // return NULL if sampleNum is past end of stream 2968 uint32 numSamples = _psampleSizeAtom->getSampleCount(); 2969 2970 if (startSampleNum + samplesToBePeeked >= numSamples) 2971 { 2972 _mp4ErrorCode = END_OF_TRACK; 2973 if (startSampleNum >= numSamples) 2974 { 2975 *n = 0; 2976 return (_mp4ErrorCode); // Past end of samples 2977 } 2978 samplesToBePeeked = numSamples - startSampleNum; 2979 *n = samplesToBePeeked; 2980 } 2981 2982 if ((_IsUpdateFileSize) 2983 && (_psampleDescriptionAtom->getMediaType() != MEDIA_TYPE_TEXT)) 2984 { 2985 //1. check if the data is available for PS 2986 //!!!!!!!!!!!!!!!!ASSUME the sample arranged in time order in the file!!!!!!!! 2987 // Find chunk 2988 uint32 lastSampleNum = startSampleNum + samplesToBePeeked - 1; 2989 2990 int32 chunk = _psampleToChunkAtom->getChunkNumberForSamplePeek(sampleNum); 2991 2992 if (chunk == PV_ERROR) 2993 { 2994 *n = 0; 2995 return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; 2996 } 2997 // Find first sample in that chunk 2998 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunkPeek(); 2999 3000 // Find chunk offset to file 3001 int32 sampleSizeOffset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 3002 if (sampleSizeOffset == PV_ERROR) 3003 { 3004 *n = 0; 3005 return READ_FAILED; 3006 } 3007 3008 int32 tempSize = 0; 3009 for (uint32 i = first; i < lastSampleNum; i++) 3010 { 3011 // Check sample size from SampleSizeAtom 3012 tempSize = _psampleSizeAtom->getSampleSizeAt(i); 3013 3014 // Check for error condition 3015 if (tempSize == -1) 3016 { 3017 *n = 0; 3018 return READ_SAMPLE_SIZE_ATOM_FAILED; 3019 } 3020 3021 sampleSizeOffset += tempSize; 3022 } 3023 if (sampleSizeOffset > (int32)_fileSize) 3024 { 3025 *n = 0; 3026 return READ_FAILED; 3027 } 3028 } 3029 3030 if (sampleNum == 0) 3031 { 3032 // Add TS offset to sample timestamps 3033 currTSBase = _trackStartTSOffset; 3034 } 3035 3036 for (i = 0; i < samplesToBePeeked; i++) 3037 { 3038 // Find chunk 3039 int32 chunk = _psampleToChunkAtom->getChunkNumberForSamplePeek(sampleNum); 3040 3041 if (chunk == PV_ERROR) 3042 { 3043 *n = (*n - samplesToBePeeked); 3044 return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; 3045 } 3046 3047 int32 SDIndex = _psampleToChunkAtom->getSDIndexPeek(); 3048 3049 if (SDIndex > 0) 3050 { 3051 SDIndex -= 1; 3052 } 3053 int32 tempSize = _psampleSizeAtom->getSampleSizeAt(sampleNum); 3054 3055 // Check for error condition 3056 if (tempSize == PV_ERROR) 3057 { 3058 *n = (*n - samplesToBePeeked); 3059 return INVALID_SAMPLE_SIZE; 3060 } 3061 3062 int32 tsDelta = 3063 _ptimeToSampleAtom->getTimeDeltaForSampleNumberPeek(sampleNum); 3064 3065 if (tsDelta == PV_ERROR) 3066 { 3067 *n = 0; 3068 return READ_TIME_TO_SAMPLE_ATOM_FAILED; 3069 } 3070 3071 3072 mInfo[i].sample_info = SDIndex; 3073 3074 //SET THE META INFO HERE 3075 mInfo[i].len = tempSize; 3076 mInfo[i].ts_delta = tsDelta; 3077 mInfo[i].ts = currTSBase + getCttsOffsetForSampleNumberPeek(sampleNum); 3078 currTSBase += tsDelta; 3079 3080 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].len =%d", i, mInfo[i].len)); 3081 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].ts_delta =%d", i, mInfo[i].ts_delta)); 3082 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].ts =%d", i, mInfo[i].ts)); 3083 3084 sampleNum ++; 3085 } 3086 return (_mp4ErrorCode); 3087} 3088 3089int32 SampleTableAtom::getOffsetByTime(uint32 ts, int32* sampleFileOffset) 3090{ 3091 3092 if ((_psampleSizeAtom == NULL) || 3093 (_psampleToChunkAtom == NULL) || 3094 (_ptimeToSampleAtom == NULL) || 3095 (_pchunkOffsetAtom == NULL)) 3096 { 3097 return DEFAULT_ERROR; 3098 } 3099 3100 int32 sampleNum = _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts, true); 3101 3102 if (sampleNum == PV_ERROR) 3103 { 3104 return DEFAULT_ERROR; 3105 } 3106 // Go for composition offset adjustment. 3107 sampleNum = 3108 getSampleNumberAdjustedWithCTTS(ts, sampleNum); 3109 3110 // return NULL if sampleNum is past end of stream 3111 uint32 numSamples = _psampleSizeAtom->getSampleCount(); 3112 3113 if (sampleNum >= (int32)numSamples) 3114 { 3115 sampleNum = numSamples - 1; 3116 } 3117 3118 int32 sampleSizeOffset = 0; 3119 if (ts != (uint32) getTimestampForSampleNumber(sampleNum)) 3120 { 3121 sampleSizeOffset = _psampleSizeAtom->getSampleSizeAt(sampleNum); 3122 if (sampleSizeOffset <= 0) 3123 { 3124 return DEFAULT_ERROR; 3125 } 3126 } 3127 3128 // Find chunk 3129 int32 chunk = getMutableSampleToChunkAtom().getChunkNumberForSample(sampleNum); 3130 // Find first sample in that chunk 3131 int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 3132 3133 // Find chunk offset to file 3134 int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 3135 if (offset == PV_ERROR) 3136 { 3137 return DEFAULT_ERROR; 3138 } 3139 3140 // Need to add up all the sizes from the first sample in this run up to the 3141 // the requested sample (but not including it) 3142 int32 tempSize = 0; 3143 3144 3145 for (int32 i = first; i < sampleNum; i++) 3146 { 3147 // Check sample size from SampleSizeAtom 3148 tempSize = _psampleSizeAtom->getSampleSizeAt(i);; 3149 if (tempSize <= 0) 3150 { 3151 return DEFAULT_ERROR; 3152 } 3153 3154 sampleSizeOffset += tempSize; 3155 } 3156 3157 // Find actual file offset to sample 3158 *sampleFileOffset = offset + sampleSizeOffset; 3159 getSampleSizeAtom()._SkipOldEntry = true; 3160 if (sampleNum == (int32)(numSamples - 1)) 3161 { 3162 return LAST_SAMPLE_IN_MOOV; 3163 } 3164 else 3165 { 3166 return EVERYTHING_FINE; 3167 } 3168} 3169 3170int32 SampleTableAtom::updateFileSize(uint32 filesize) 3171{ 3172 _fileSize = filesize; 3173 _IsUpdateFileSize = 1; 3174 if (_pinput->IsOpen()) 3175 { 3176 if (AtomUtils::Flush(_pinput)) 3177 { 3178 return DEFAULT_ERROR; //error 3179 } 3180 } 3181 return EVERYTHING_FINE; 3182} 3183 3184MP4_ERROR_CODE 3185SampleTableAtom::getMaxTrackTimeStamp(uint32 fileSize, uint32& timeStamp) 3186{ 3187 timeStamp = 0; 3188 3189 /* 3190 * Get the chunk that is closest to "fileSize" 3191 */ 3192 int32 chunk; 3193 3194 int32 retVal = 3195 _pchunkOffsetAtom->getChunkClosestToOffset(fileSize, chunk); 3196 3197 if (retVal == EVERYTHING_FINE) 3198 { 3199 /* 3200 * Get chunk offset for the chunk 3201 */ 3202 int32 chunkOffset = _pchunkOffsetAtom->getChunkOffsetAt(chunk); 3203 3204 /* 3205 * Find the first sample in chunk 3206 */ 3207 uint32 FirstSampleNumInChunk = 3208 _psampleToChunkAtom->getFirstSampleNumInChunk(chunk); 3209 3210 /* 3211 * Get number of samples in this chunk 3212 */ 3213 uint32 numSamplesPerChunk = 3214 getSampleToChunkAtom().getSamplesPerChunkCorrespondingToSampleGet(); 3215 3216 /* 3217 * Get the sample closest to the specified fileSize. 3218 * Need to add up all the sizes from the first sample in this run 3219 * up to the the closest sample 3220 */ 3221 int32 tempSize = 0; 3222 uint32 sampleNum = FirstSampleNumInChunk ? (FirstSampleNumInChunk - 1) : 0; 3223 3224 do 3225 { 3226 // Check sample size from SampleSizeAtom 3227 tempSize = getSampleSizeAtom().getDefaultSampleSize(); 3228 3229 if (tempSize == 0) 3230 { 3231 // Need to get specific sample size 3232 tempSize = getSampleSizeAtom().getSampleSizeAt(sampleNum); 3233 } 3234 sampleNum++; 3235 if (tempSize == PV_ERROR) 3236 { 3237 return READ_FAILED; 3238 } 3239 chunkOffset += tempSize; 3240 3241 if ((uint32)chunkOffset > fileSize) 3242 { 3243 sampleNum--; 3244 break; 3245 } 3246 } 3247 while (sampleNum < (FirstSampleNumInChunk + numSamplesPerChunk - 1)); 3248 3249 /* 3250 * Get time stamp corresponding to sampleNum 3251 */ 3252 int32 ts = getTimestampForSampleNumber(sampleNum); 3253 3254 if (ts == PV_ERROR) 3255 { 3256 return (READ_FAILED); 3257 } 3258 timeStamp = ts + getCttsOffsetForSampleNumber(sampleNum); 3259 } 3260 return (EVERYTHING_FINE); 3261} 3262 3263MP4_ERROR_CODE 3264SampleTableAtom::getSampleNumberClosestToTimeStamp(uint32 &sampleNumber, 3265 uint32 timeStamp, 3266 uint32 sampleOffset) 3267{ 3268 sampleNumber = 0; 3269 3270 if ((_psampleSizeAtom == NULL) || 3271 (_psampleToChunkAtom == NULL) || 3272 (_ptimeToSampleAtom == NULL) || 3273 (_pchunkOffsetAtom == NULL)) 3274 { 3275 return (READ_FAILED); 3276 } 3277 3278 uint32 totalNumSamplesInTrack = getSampleSizeAtom().getSampleCount(); 3279 3280 if (totalNumSamplesInTrack > 0) 3281 { 3282 if (timeStamp > _trackStartTSOffset) 3283 { 3284 sampleNumber = 3285 getTimeToSampleAtom().getSampleNumberFromTimestamp((timeStamp - _trackStartTSOffset), true); 3286 // Go for composition offset adjustment. 3287 sampleNumber = 3288 getSampleNumberAdjustedWithCTTS((timeStamp - _trackStartTSOffset), sampleNumber); 3289 3290 3291 if ((int32)sampleNumber == PV_ERROR) 3292 { 3293 return (READ_FAILED); 3294 } 3295 else if ((sampleNumber + sampleOffset) >= totalNumSamplesInTrack) 3296 { 3297 sampleNumber = (totalNumSamplesInTrack - 1); 3298 return (END_OF_TRACK); 3299 } 3300 } 3301 else 3302 { 3303 sampleNumber = 0; 3304 } 3305 sampleNumber += sampleOffset; 3306 return (EVERYTHING_FINE); 3307 } 3308 else 3309 { 3310 return (READ_FAILED); 3311 } 3312} 3313 3314 3315// This function takes the presentation time stamp and the sample number calculated 3316// referring stts api getSampleNumberFromTimestamp. 3317// We look for all the samples which has (decode time + ctts >= presentation timestamp) 3318// before this sample and return the most nearest to presentation timestamp. 3319int32 SampleTableAtom:: 3320getSampleNumberAdjustedWithCTTS(uint32 aTs, int32 aSampleNumber) 3321{ 3322 uint32 minimumTimestamp = 0; //stores minimum ts encountered 3323 int32 minimumTsFrameNum = 0; //stores frame num of minimum ts 3324 int32 curSampleParsed = 0; //stores number of sample currently parsed 3325 uint32 curSampleTs = 0; //stores timestamp of current sample 3326 3327 // CTTS not present do nothing. 3328 if (NULL == _pcompositionOffsetAtom) 3329 { 3330 return aSampleNumber; 3331 } 3332 3333 //initially we beleive that sample number that we have received is 3334 //minimum sample number available and ts corresponding to this sample number 3335 //is the minimum sample time(including its ctts offset as well) 3336 3337 minimumTsFrameNum = aSampleNumber; 3338 // getTimestampForSampleNumber has CTTS already adjusted 3339 minimumTimestamp = getTimestampForSampleNumber(minimumTsFrameNum); 3340 3341 //assign curSampleParsed the value of current minimumTsFrameNum 3342 curSampleParsed = minimumTsFrameNum; 3343 3344 for (int loopIndex = 0; loopIndex < BACK_TRAVERSE_FRAME_COUNT; loopIndex++) 3345 { 3346 if (0 == curSampleParsed) 3347 { 3348 // For loop termination 3349 return minimumTsFrameNum; 3350 } 3351 else 3352 { 3353 //get the timestamp of the current sample 3354 curSampleTs = getTimestampForSampleNumber(curSampleParsed); 3355 3356 //if curSampleTs = aTs then this is the sample we needed so return 3357 if (curSampleTs == aTs) 3358 { 3359 return curSampleParsed; 3360 } 3361 3362 //if curSampleTs > aTs and is less than minimumTimestamp 3363 //then this may be the minimum sample that we need to start with 3364 if ((curSampleTs > aTs) && (curSampleTs < minimumTimestamp)) 3365 { 3366 minimumTsFrameNum = curSampleParsed; 3367 minimumTimestamp = curSampleTs; 3368 } 3369 3370 //decrement the curSampleParsed to move back to the previous sample 3371 curSampleParsed--; 3372 } 3373 } 3374 return minimumTsFrameNum; 3375} 3376 3377// Returns the timestamp (in milliseconds) for the last sample returned 3378// This is mainly to be used when seeking in the bitstream - you request a frame at timestamp 3379// X, but the actual frame you get is Y, this method returns the timestamp for Y so you know which 3380// audio sample to request. 3381int32 SampleTableAtom:: 3382getTimestampForCurrentSample() 3383{ 3384 return _currentPlaybackSampleTimestamp; 3385} 3386 3387