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 CompositionOffsetAtom Class */ 21 /* ------------------------------------------------------------------- */ 22 /*********************************************************************************/ 23 24 /* 25 This atom gives difference between decoding time and composition time on each 26 sample basis. This atom is optional and must be present only if Decoding time 27 and Composition Time differ for any samples. As understood that Decoding time 28 is always less than composition time, the offsets are termed as unsigned 29 numbers such. 30 31 */ 32 33 34 #define IMPLEMENT_CompositionOffsetAtom 35 36 #include "compositionoffsetatom.h" 37 #include "atomutils.h" 38 39 #define CTTS_MIN_SAMPLE_TABLE_SIZE 4096 40 #define MT_SAMPLECOUNT_INCREMENT 100 //this has to be atleast 3 41 #define NUMBER_OF_SAMPLE_POPULATES_PER_RUNL 50 42 #define ENABLE_MT_LOGIC_ON_CTTS_ENTRY_COUNT_VALUE 512 43 44 // Stream-in ctor 45 CompositionOffsetAtom::CompositionOffsetAtom(MP4_FF_FILE *fp, 46 uint32 mediaType, 47 uint32 size, 48 uint32 type, 49 OSCL_wString& filename, 50 uint32 parsingMode): 51 FullAtom(fp, size, type), 52 OsclTimerObject(OsclActiveObject::EPriorityNominal, "CompositionOffsetAtom") 53 { 54 _psampleCountVec = NULL; 55 _psampleOffsetVec = NULL; 56 MT_SampleCount = NULL; 57 MT_EntryCount = NULL; 58 iMarkerTableCreation = false; 59 MT_Table_Size = 0; 60 61 _currGetSampleCount = 0; 62 _currGetIndex = -1; 63 _currGetTimeOffset = 0; 64 _currPeekSampleCount = 0; 65 _currPeekIndex = -1; 66 _currPeekTimeOffset = 0; 67 68 MT_Counter = 1; 69 addSampleCount = 0; 70 prevSampleCount = 0; 71 entrycountTraversed = 0; 72 refSample = MT_SAMPLECOUNT_INCREMENT; 73 MT_j = 1; 74 75 _mediaType = mediaType; 76 _parsed_entry_cnt = 0; 77 _fileptr = NULL; 78 _parsing_mode = 0; 79 _parsing_mode = parsingMode; 80 81 82 _stbl_buff_size = CTTS_MIN_SAMPLE_TABLE_SIZE; 83 _next_buff_number = 0; 84 _curr_buff_number = 0; 85 _curr_entry_point = 0; 86 _stbl_fptr_vec = NULL; 87 88 iLogger = PVLogger::GetLoggerObject("mp4ffparser"); 89 iStateVarLogger = PVLogger::GetLoggerObject("mp4ffparser_mediasamplestats"); 90 iParsedDataLogger = PVLogger::GetLoggerObject("mp4ffparser_parseddata"); 91 92 iMarkerTableCreation = false; 93 94 /* Add this AO to the scheduler */ 95 if (OsclExecScheduler::Current() != NULL) 96 { 97 if (!IsAdded()) 98 { 99 AddToScheduler(); 100 } 101 } 102 103 if (_success) 104 { 105 if (!AtomUtils::read32(fp, _entryCount)) 106 { 107 _success = false; 108 } 109 110 PVMF_MP4FFPARSER_LOGPARSEDINFO((0, "CompositionOffsetAtom::CompositionOffsetAtom- _entryCount =%d", _entryCount)); 111 uint32 dataSize = _size - (DEFAULT_FULL_ATOM_SIZE + 4); 112 113 uint32 entrySize = (4 + 4); 114 115 if ((_entryCount*entrySize) > dataSize) 116 { 117 _success = false; 118 } 119 120 if (_success) 121 { 122 if (_entryCount > 0) 123 { 124 if (parsingMode == 1) 125 { 126 // cache size is 4K so that optimization 127 // should work if entry_count is greater than 4K 128 if (_entryCount > _stbl_buff_size) 129 { 130 131 uint32 fptrBuffSize = (_entryCount / _stbl_buff_size) + 1; 132 133 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (fptrBuffSize), _stbl_fptr_vec); 134 if (_stbl_fptr_vec == NULL) 135 { 136 _success = false; 137 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 138 return; 139 } 140 141 142 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_stbl_buff_size), _psampleCountVec); 143 if (_psampleCountVec == NULL) 144 { 145 _success = false; 146 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 147 return; 148 } 149 150 151 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_stbl_buff_size), _psampleOffsetVec); 152 if (_psampleOffsetVec == NULL) 153 { 154 PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec); 155 _psampleOffsetVec = NULL; 156 _success = false; 157 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 158 return; 159 } 160 161 for (uint32 idx = 0; idx < _stbl_buff_size; idx++) //initialization 162 { 163 _psampleCountVec[idx] = 0; 164 _psampleOffsetVec[idx] = 0; 165 } 166 167 OsclAny* ptr = (MP4_FF_FILE *)(oscl_malloc(sizeof(MP4_FF_FILE))); 168 if (ptr == NULL) 169 { 170 _success = false; 171 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 172 return; 173 } 174 175 _fileptr = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE()); 176 _fileptr->_fileServSession = fp->_fileServSession; 177 _fileptr->_pvfile.SetCPM(fp->_pvfile.GetCPM()); 178 179 if (AtomUtils::OpenMP4File(filename, 180 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 181 _fileptr) != 0) 182 { 183 _success = false; 184 _mp4ErrorCode = FILE_OPEN_FAILED; 185 } 186 187 _fileptr->_fileSize = fp->_fileSize; 188 189 int32 _head_offset = AtomUtils::getCurrentFilePosition(fp); 190 AtomUtils::seekFromCurrPos(fp, dataSize); 191 AtomUtils::seekFromStart(_fileptr, _head_offset); 192 193 return; 194 } 195 else 196 { 197 _parsing_mode = 0; 198 _stbl_buff_size = _entryCount; 199 } 200 } 201 else 202 { 203 _stbl_buff_size = _entryCount; 204 } 205 206 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_entryCount), _psampleCountVec); 207 if (_psampleCountVec == NULL) 208 { 209 _success = false; 210 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 211 return; 212 } 213 214 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_entryCount), _psampleOffsetVec); 215 if (_psampleOffsetVec == NULL) 216 { 217 PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec); 218 _psampleOffsetVec = NULL; 219 _success = false; 220 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 221 return; 222 } 223 224 for (uint32 idx = 0; idx < _entryCount; idx++) //initialization 225 { 226 _psampleCountVec[idx] = 0; 227 _psampleOffsetVec[idx] = 0; 228 } 229 230 uint32 number = 0; 231 uint32 offset = 0; 232 for (_parsed_entry_cnt = 0; _parsed_entry_cnt < _entryCount; _parsed_entry_cnt++) 233 { 234 if (!AtomUtils::read32(fp, number)) 235 { 236 _success = false; 237 break; 238 } 239 if (!AtomUtils::read32(fp, offset)) 240 { 241 _success = false; 242 break; 243 } 244 _psampleCountVec[_parsed_entry_cnt] = (number); 245 _psampleOffsetVec[_parsed_entry_cnt] = (offset); 246 } 247 } 248 } 249 250 if (!_success) 251 { 252 _mp4ErrorCode = READ_TIME_TO_SAMPLE_ATOM_FAILED; 253 } 254 } 255 else 256 { 257 if (_mp4ErrorCode != ATOM_VERSION_NOT_SUPPORTED) 258 _mp4ErrorCode = READ_TIME_TO_SAMPLE_ATOM_FAILED; 259 } 260 } 261 262 void CompositionOffsetAtom::setSamplesCount(uint32 SamplesCount) 263 { 264 _iTotalNumSamplesInTrack = SamplesCount; 265 266 if (_entryCount > ENABLE_MT_LOGIC_ON_CTTS_ENTRY_COUNT_VALUE) 267 { 268 //Make this AO active so Run() will be called when scheduler is started 269 if (OsclExecScheduler::Current() != NULL) 270 { 271 RunIfNotReady(); 272 } 273 } 274 } 275 276 bool CompositionOffsetAtom::ParseEntryUnit(uint32 entry_cnt) 277 { 278 const uint32 threshold = 1024; 279 entry_cnt += threshold; 280 281 if (entry_cnt > _entryCount) 282 { 283 entry_cnt = _entryCount; 284 } 285 286 uint32 number = 0; 287 uint32 offset = 0; 288 while (_parsed_entry_cnt < entry_cnt) 289 { 290 _curr_entry_point = _parsed_entry_cnt % _stbl_buff_size; 291 _curr_buff_number = _parsed_entry_cnt / _stbl_buff_size; 292 293 if (_curr_buff_number == _next_buff_number) 294 { 295 uint32 currFilePointer = AtomUtils::getCurrentFilePosition(_fileptr); 296 _stbl_fptr_vec[_curr_buff_number] = currFilePointer; 297 _next_buff_number++; 298 } 299 300 if (!_curr_entry_point) 301 { 302 uint32 currFilePointer = _stbl_fptr_vec[_curr_buff_number]; 303 AtomUtils::seekFromStart(_fileptr, currFilePointer); 304 } 305 306 if (!AtomUtils::read32(_fileptr, number)) 307 { 308 return false; 309 } 310 311 if (!AtomUtils::read32(_fileptr, offset)) 312 { 313 return false; 314 } 315 _psampleCountVec[_curr_entry_point] = (number); 316 _psampleOffsetVec[_curr_entry_point] = (offset); 317 _parsed_entry_cnt++; 318 } 319 return true; 320 } 321 322 // Destructor 323 CompositionOffsetAtom::~CompositionOffsetAtom() 324 { 325 if (_psampleCountVec != NULL) 326 PV_MP4_ARRAY_DELETE(NULL, _psampleCountVec); 327 328 if (_psampleOffsetVec != NULL) 329 PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec); 330 331 if (_stbl_fptr_vec != NULL) 332 PV_MP4_ARRAY_DELETE(NULL, _stbl_fptr_vec); 333 334 deleteMarkerTable(); 335 336 if (_fileptr != NULL) 337 { 338 if (_fileptr->IsOpen()) 339 { 340 AtomUtils::CloseMP4File(_fileptr); 341 } 342 oscl_free(_fileptr); 343 } 344 345 if (IsAdded()) 346 { 347 RemoveFromScheduler(); 348 } 349 350 } 351 352 // Return the number of samples at index 353 uint32 354 CompositionOffsetAtom::getSampleCountAt(int32 index) 355 { 356 if (_psampleCountVec == NULL) 357 { 358 return (uint32) PV_ERROR; 359 } 360 361 if (index < (int32)_entryCount) 362 { 363 if (_parsing_mode == 1) 364 CheckAndParseEntry(index); 365 366 return (int32)(_psampleCountVec[index%_stbl_buff_size]); 367 } 368 else 369 { 370 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleCountAt index = %d", index)); 371 return (uint32) PV_ERROR; 372 } 373 } 374 375 // Return sample offset at index 376 int32 377 CompositionOffsetAtom::getSampleOffsetAt(int32 index) 378 { 379 if (_psampleOffsetVec == NULL) 380 { 381 return PV_ERROR; 382 } 383 384 if (index < (int32)_entryCount) 385 { 386 if (_parsing_mode == 1) 387 CheckAndParseEntry(index); 388 389 return (int32)(_psampleOffsetVec[index%_stbl_buff_size]); 390 } 391 else 392 { 393 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleOffsetAt index = %d", index)); 394 return PV_ERROR; 395 } 396 } 397 398 int32 399 CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek(uint32 sampleNum) 400 { 401 // It is assumed that sample 0 has a ts of 0 - i.e. the first 402 // entry in the table starts with the delta between sample 1 and sample 0 403 if ((_psampleOffsetVec == NULL) || 404 (_psampleCountVec == NULL) || 405 (_entryCount == 0)) 406 { 407 return PV_ERROR; 408 } 409 410 // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index 411 if (sampleNum < _currPeekSampleCount) 412 { 413 return (_currPeekTimeOffset); 414 } 415 else 416 { 417 do 418 { 419 _currPeekIndex++; 420 if (_parsing_mode) 421 CheckAndParseEntry(_currPeekIndex); 422 423 _currPeekSampleCount += _psampleCountVec[_currPeekIndex%_stbl_buff_size]; 424 _currPeekTimeOffset = _psampleOffsetVec[_currPeekIndex%_stbl_buff_size]; 425 } 426 while (_currPeekSampleCount == 0); 427 428 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekIndex =%d", _currPeekIndex)); 429 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekSampleCount =%d", _currPeekSampleCount)); 430 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekTimeOffset =%d", _currPeekTimeOffset)); 431 432 if (sampleNum < _currPeekSampleCount) 433 { 434 return (_currPeekTimeOffset); 435 } 436 else 437 { 438 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek sampleNum = %d", sampleNum)); 439 return (PV_ERROR); 440 } 441 } 442 443 } 444 445 // This is the most widely used API 446 // Returns the offset (ms) for the sample given by num. This is used when 447 // randomly accessing a frame and the timestamp has not been accumulated. 448 int32 CompositionOffsetAtom::getTimeOffsetForSampleNumberGet(uint32 sampleNum) 449 { 450 if ((_psampleOffsetVec == NULL) || 451 (_psampleCountVec == NULL) || 452 (_entryCount == 0)) 453 { 454 return PV_ERROR; 455 } 456 457 // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index 458 if (sampleNum < _currGetSampleCount) 459 { 460 return (_currGetTimeOffset); 461 } 462 else 463 { 464 465 do 466 { 467 _currGetIndex++; 468 if (_parsing_mode) 469 CheckAndParseEntry(_currGetIndex); 470 _currGetSampleCount += _psampleCountVec[_currGetIndex%_stbl_buff_size]; 471 _currGetTimeOffset = _psampleOffsetVec[_currGetIndex%_stbl_buff_size]; 472 } 473 while (_currGetSampleCount == 0); 474 475 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetIndex =%d", _currGetIndex)); 476 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetSampleCount =%d", _currGetSampleCount)); 477 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetTimeOffset =%d", _currGetTimeOffset)); 478 479 if (sampleNum < _currGetSampleCount) 480 { 481 return (_currGetTimeOffset); 482 } 483 else 484 { 485 PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getTimeDeltaForSampleNumberGet sampleNum = %d", sampleNum)); 486 return (PV_ERROR); 487 } 488 } 489 490 } 491 492 493 494 495 496 int32 CompositionOffsetAtom::getTimeOffsetFromMT(uint32 samplenum, uint32 currEC, uint32 currSampleCount) 497 { 498 if ((_psampleOffsetVec == NULL) || 499 (_psampleCountVec == NULL) || 500 (_entryCount == 0)) 501 { 502 return PV_ERROR; 503 } 504 505 if (samplenum < currSampleCount) 506 { // Sample num within current entry 507 if (_parsing_mode == 1) 508 CheckAndParseEntry(currEC); 509 510 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[currEC%_stbl_buff_size])); 511 return _psampleOffsetVec[currEC%_stbl_buff_size]; 512 } 513 else 514 { 515 516 for (uint32 i = currEC + 1; i < _entryCount; i++) 517 { 518 if (_parsing_mode == 1) 519 CheckAndParseEntry(i); 520 521 522 if (samplenum < (currSampleCount + _psampleCountVec[i%_stbl_buff_size])) 523 { 524 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size])); 525 return _psampleOffsetVec[i%_stbl_buff_size]; 526 } 527 else 528 { 529 currSampleCount += _psampleCountVec[i%_stbl_buff_size]; 530 } 531 } 532 } 533 534 // Went past end of list - not a valid sample number 535 return PV_ERROR; 536 } 537 538 int32 CompositionOffsetAtom::getTimeOffsetForSampleNumber(uint32 num) 539 { 540 uint32 currSample = 0; 541 uint32 currEC = 0; 542 543 if (iMarkerTableCreation == true) 544 { 545 uint32 MT_EC = num / (MT_SAMPLECOUNT_INCREMENT - 1); //where MT_SAMPLECOUNT_INCREMENT is the granuality of sample separation in Marker Table 546 547 if (MT_EC > ((_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1)) 548 { 549 //boundary check, MT_EC valid value will always be between 0 to (_samples_count/MT_SAMPLECOUNT_INCREMENT)-1 550 MT_EC = (_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1; 551 } 552 //assign the last marker entry count created till now to look for sample from this location onwards instead of from start 553 if (MT_EC > MT_Counter) 554 MT_EC = MT_Counter; 555 556 while ((num < MT_SampleCount[MT_EC]) && (MT_EC > 0)) 557 { 558 //This check was put keeping in mind that it may happen (due to rounding off error), 559 //that we choose a MT_EC greater than desired. So to avoid such a scenario. 560 MT_EC = MT_EC - 1; 561 currSample = MT_SampleCount[MT_EC]; 562 currEC = MT_EntryCount[MT_EC]; 563 } 564 565 currSample = MT_SampleCount[MT_EC]; 566 currEC = MT_EntryCount[MT_EC]; 567 568 569 570 return getTimeOffsetFromMT(num, currEC, currSample); 571 } 572 else 573 { 574 if ((_psampleOffsetVec == NULL) || 575 (_psampleCountVec == NULL) || 576 (_entryCount == 0)) 577 { 578 return PV_ERROR; 579 } 580 581 uint32 sampleCount = 0; 582 583 for (uint32 i = 0; i < _entryCount; i++) 584 { 585 if (_parsing_mode == 1) 586 CheckAndParseEntry(i); 587 588 if (num < (sampleCount + _psampleCountVec[i%_stbl_buff_size])) 589 { // Sample num within current entry 590 591 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size])); 592 return _psampleOffsetVec[i%_stbl_buff_size]; 593 } 594 else 595 { 596 sampleCount += _psampleCountVec[i%_stbl_buff_size]; 597 } 598 } 599 600 // Went past end of list - not a valid sample number 601 return PV_ERROR; 602 } 603 } 604 605 int32 606 CompositionOffsetAtom::resetStateVariables() 607 { 608 uint32 sampleNum = 0; 609 return (resetStateVariables(sampleNum)); 610 } 611 612 int32 613 CompositionOffsetAtom::resetStateVariables(uint32 sampleNum) 614 { 615 _currGetSampleCount = 0; 616 _currGetIndex = -1; 617 _currGetTimeOffset = 0; 618 _currPeekSampleCount = 0; 619 _currPeekIndex = -1; 620 _currPeekTimeOffset = 0; 621 622 // It is assumed that sample 0 has a ts of 0 - i.e. the first 623 // entry in the table starts with the delta between sample 1 and sample 0 624 if ((_psampleOffsetVec == NULL) || 625 (_psampleCountVec == NULL) || 626 (_entryCount == 0)) 627 { 628 return PV_ERROR; 629 } 630 631 if (_parsing_mode) 632 { 633 if (_parsed_entry_cnt == 0) 634 { 635 ParseEntryUnit(sampleNum); 636 } 637 } 638 639 for (uint32 i = 0; i < _entryCount; i++) 640 { 641 _currPeekIndex++; 642 _currPeekSampleCount += _psampleCountVec[i%_stbl_buff_size]; 643 _currPeekTimeOffset = _psampleOffsetVec[i%_stbl_buff_size]; 644 645 _currGetIndex++; 646 _currGetSampleCount += _psampleCountVec[i%_stbl_buff_size]; 647 _currGetTimeOffset = _psampleOffsetVec[i%_stbl_buff_size]; 648 649 if (sampleNum <= _currPeekSampleCount) 650 { 651 return (EVERYTHING_FINE); 652 } 653 654 } 655 656 // Went past end of list - not a valid sample number 657 return PV_ERROR; 658 } 659 660 int32 CompositionOffsetAtom::resetPeekwithGet() 661 { 662 _currPeekSampleCount = _currGetSampleCount; 663 _currPeekIndex = _currGetIndex; 664 _currPeekTimeOffset = _currGetTimeOffset; 665 return (EVERYTHING_FINE); 666 } 667 668 void CompositionOffsetAtom::CheckAndParseEntry(uint32 i) 669 { 670 if (i >= _parsed_entry_cnt) 671 { 672 ParseEntryUnit(i); 673 } 674 else 675 { 676 uint32 entryLoc = i / _stbl_buff_size; 677 if (_curr_buff_number != entryLoc) 678 { 679 _parsed_entry_cnt = entryLoc * _stbl_buff_size; 680 while (_parsed_entry_cnt <= i) 681 ParseEntryUnit(_parsed_entry_cnt); 682 } 683 } 684 } 685 686 void CompositionOffsetAtom::Run() 687 { 688 // Create it for the first time 689 if ((MT_SampleCount == NULL) && (MT_EntryCount == NULL)) 690 { 691 int32 status = createMarkerTable(); 692 if (status == PVMFFailure) 693 { 694 OSCL_LEAVE(OsclErrNoMemory); 695 } 696 iMarkerTableCreation = true; 697 } 698 699 populateMarkerTable(); 700 701 // check for entry count being exhausted.. table iterated completely 702 if ((entrycountTraversed < _entryCount) && (refSample < _iTotalNumSamplesInTrack) 703 && (MT_Counter < _iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT)) 704 { 705 RunIfNotReady(); 706 } 707 708 return; 709 710 } 711 //Populate the Marker Table with SampleCount and EntryCount values 712 //for every nth sample starting from n-1, where n=MT_SAMPLECOUNT_INCREMENT. 713 714 uint32 CompositionOffsetAtom::populateMarkerTable() 715 { 716 uint32 increment = MT_SAMPLECOUNT_INCREMENT; 717 uint32 numPopulated = 0; 718 719 720 721 for (uint32 i = entrycountTraversed; i < _entryCount; i++) 722 { 723 724 if (refSample < _iTotalNumSamplesInTrack) 725 { 726 727 if (i == 0) 728 { 729 if (_parsing_mode == 1) 730 CheckAndParseEntry(i); 731 732 MT_SampleCount[0] = _psampleCountVec[i%_stbl_buff_size]; 733 prevSampleCount = MT_SampleCount[0]; 734 addSampleCount = MT_SampleCount[0]; 735 } 736 else if (addSampleCount < refSample) 737 { 738 if (_parsing_mode == 1) 739 CheckAndParseEntry(MT_j); 740 741 prevSampleCount = addSampleCount; 742 addSampleCount += _psampleCountVec[MT_j%_stbl_buff_size]; 743 MT_j++; 744 } 745 else 746 { 747 entrycountTraversed = i - 1; 748 i = i - 1; 749 refSample += increment; 750 MT_SampleCount[MT_Counter] = prevSampleCount; 751 //Incase SampleCounts have same value for consecutive MT entries, 752 //even the same EntryCount should be mentioned in the Marker Table. 753 if (MT_SampleCount[MT_Counter] == MT_SampleCount[MT_Counter-1]) 754 { 755 MT_EntryCount[MT_Counter] = MT_EntryCount[MT_Counter-1]; 756 } 757 else 758 { 759 MT_EntryCount[MT_Counter] = MT_j - 2; 760 } 761 762 763 MT_Counter++; 764 numPopulated++; 765 if ((numPopulated == NUMBER_OF_SAMPLE_POPULATES_PER_RUNL) || 766 (MT_Counter >= _iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT)) 767 break; 768 } 769 } 770 else 771 { 772 break; 773 } 774 775 } 776 777 return numPopulated; 778 779 } 780 void CompositionOffsetAtom::deleteMarkerTable() 781 { 782 if (MT_SampleCount != NULL) 783 PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount); 784 785 if (MT_EntryCount != NULL) 786 PV_MP4_ARRAY_DELETE(NULL, MT_EntryCount); 787 } 788 // responsible for creation of data sturcture inside the table. 789 PVMFStatus CompositionOffsetAtom::createMarkerTable() 790 { 791 792 MT_Table_Size = (_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT); 793 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (MT_Table_Size), MT_SampleCount); 794 795 if (MT_SampleCount == NULL) 796 { 797 PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount); 798 MT_SampleCount = NULL; 799 _success = false; 800 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 801 return PVMFFailure; 802 } 803 804 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (MT_Table_Size), MT_EntryCount); 805 806 if (MT_EntryCount == NULL) 807 { 808 PV_MP4_ARRAY_DELETE(NULL, MT_EntryCount); 809 MT_EntryCount = NULL; 810 PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount); 811 MT_SampleCount = NULL; 812 _success = false; 813 _mp4ErrorCode = MEMORY_ALLOCATION_FAILED; 814 return PVMFFailure; 815 } 816 817 for (uint32 idx = 0; idx < MT_Table_Size; idx++) //initialization 818 { 819 820 MT_EntryCount[idx] = 0; 821 MT_SampleCount[idx] = 0; 822 } 823 824 return PVMFSuccess; 825 } 826 827 828