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 The PVA_FF_Mpeg4File Class fp the class that will construct and maintain all the 20 mecessary data structures to be able to render a valid MP4 file to disk. 21 Format. 22 */ 23 24 25 #define IMPLEMENT_Mpeg4File 26 27 #ifndef OSCL_STRING_UTILS_H_INCLUDED 28 #include "oscl_string_utils.h" 29 #endif 30 31 #include "mpeg4file.h" 32 #include "a_atomdefs.h" 33 #include "atomutils.h" 34 35 #include "pv_gau.h" 36 #include "oscl_byte_order.h" 37 #include "oscl_bin_stream.h" 38 39 #include "pv_mp4ffcomposer_config.h" 40 41 const uint8 aAMRNBZeroSetMask[9] = 42 { 43 0xfe, 0xfe, 0xfc, 0xfc, 44 0xf0, 0xfe, 0xf0, 0xf0, 45 0xfe 46 }; 47 //IETF AMR WB Speech Frame Sizes (including zero byte padding but not including TOC) 48 //FT 0 (6.6 Kbps) - 17 bytes = 136 bits 49 //FT 1 (8.85 Kbps) - 23 bytes = 184 bits 50 //FT 2 (12.65 Kbps) - 32 bytes = 256 bits 51 //FT 3 (14.25 Kbps) - 36 bytes = 288 bits 52 //FT 4 (15.85 Kbps) - 40 bytes = 320 bits 53 //FT 5 (18.25 Kbps) - 46 bytes = 368 bits 54 //FT 6 (19.85 Kbps) - 50 bytes = 400 bits 55 //FT 7 (23.05 Kbps) - 58 bytes = 464 bits 56 //FT 8 (23.85 Kbps) - 60 bytes = 480 bits 57 //FT 9 (SID) - 5 bytes = 40 bits 58 //FT 10-13 - Reserved 59 //FT 14 (Lost frame) and FT 15 (NO DATA) - 0 bytes = 0 bits 60 61 //IETF AMR WB IF1 Speech Frame Sizes (just Class A, B & C speech bits, does not include FT or any other headers) 62 //FT 0 (6.6 Kbps) - 132 bits; num-bits-padded = 4 63 //FT 1 (8.85 Kbps) - 177 bits; num-bits-padded = 7 64 //FT 2 (12.65 Kbps) - 253 bits; num-bits-padded = 3 65 //FT 3 (14.25 Kbps) - 285 bits; num-bits-padded = 3 66 //FT 4 (15.85 Kbps) - 317 bits; num-bits-padded = 3 67 //FT 5 (18.25 Kbps) - 365 bits; num-bits-padded = 3 68 //FT 6 (19.85 Kbps) - 397 bits; num-bits-padded = 3 69 //FT 7 (23.05 Kbps) - 461 bits; num-bits-padded = 3 70 //FT 8 (23.85 Kbps) - 477 bits; num-bits-padded = 3 71 //FT 9 (SID) - 5 bytes = 40 bits; num-bits-padded = 0 72 //FT 10-13 - Reserved 73 //FT 14 (Lost frame) and FT 15 (NO DATA) - 0 bytes = 0 bits; num-bits-padded = 0 74 75 // Difference between IF1 bits and IETF storage bits is padded with zeros to byte align the frame 76 const uint8 aAMRWBZeroSetMask[9] = 77 { 78 0xf0, 0x80, 0xf8, 0xf8, 79 0xf8, 0xf8, 0xf8, 0xf8, 80 0xf8 81 }; 82 83 typedef Oscl_Vector<PVA_FF_MediaDataAtom*, OsclMemAllocator> PVA_FF_MediaDataAtomVecType; 84 typedef Oscl_Vector<PVA_FF_MovieFragmentAtom*, OsclMemAllocator> PVA_FF_MovieFragmentAtomVecType; 85 typedef Oscl_Vector<PVA_FF_InterLeaveBuffer*, OsclMemAllocator> PVA_FF_InterLeaveBufferVecType; 86 87 //common to both AMR and AMR-WB 88 const uint32 AMRModeSetMask[16] = 89 { 90 0x0001, 0x0002, 0x0004, 0x0008, 91 0x0010, 0x0020, 0x0040, 0x0080, 92 0x0100, 0x0200, 0x0400, 0x0800, 93 0x1000, 0x2000, 0x4000, 0x8000 94 }; 95 96 // Constructor 97 PVA_FF_Mpeg4File::PVA_FF_Mpeg4File(int32 mediaType) 98 { 99 OSCL_UNUSED_ARG(mediaType); 100 _success = true; 101 102 _tempFilePostfix = _STRLIT(""); 103 104 _tempOutputPath = _STRLIT(""); 105 106 _oUserDataPopulated = true; 107 _pmovieAtom = NULL; 108 _pmediaDataAtomVec = NULL; 109 _puserDataAtom = NULL; 110 _pFileTypeAtom = NULL; 111 _pCurrentMoofAtom = NULL; 112 _pCurrentMediaDataAtom = NULL; 113 iCacheSize = 0; 114 _oIsFileOpen = false; 115 _pInterLeaveBufferVec = NULL; 116 _oInterLeaveEnabled = false; 117 _aFs = NULL; 118 } 119 120 // Destructor 121 PVA_FF_Mpeg4File::~PVA_FF_Mpeg4File() 122 { 123 124 { 125 if (_oUserDataPopulated == false) 126 { 127 populateUserDataAtom(); 128 } 129 } 130 131 // Clean up atoms 132 if (_pmovieAtom != NULL) 133 { 134 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieAtom, _pmovieAtom); 135 } 136 137 int32 i; 138 139 // Delete all the atoms in the media data vec 140 if (_pmediaDataAtomVec != NULL) 141 { 142 int32 size = _pmediaDataAtomVec->size(); 143 for (i = 0; i < size; i++) 144 { 145 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, (*_pmediaDataAtomVec)[i]); 146 } 147 148 // Delete the vectors themselves 149 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_MediaDataAtomVecType, Oscl_Vector, _pmediaDataAtomVec); 150 } 151 152 153 if ((_oInterLeaveEnabled) && (NULL != _pInterLeaveBufferVec)) 154 { 155 // delete all interleave buffers 156 int32 size = _pInterLeaveBufferVec->size(); 157 for (i = 0; i < size; i++) 158 { 159 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, (*_pInterLeaveBufferVec)[i]); 160 } 161 162 // Delete the vectors themselves 163 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_InterLeaveBufferVecType, Oscl_Vector, _pInterLeaveBufferVec); 164 } 165 166 // in movie fragment mode delete MOOF and MFRA atoms 167 if (_oMovieFragmentEnabled == true) 168 { 169 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentAtom, _pCurrentMoofAtom); 170 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, _pCurrentMediaDataAtom); 171 172 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentRandomAccessAtom, _pMfraAtom); 173 } 174 175 // Delete user data if present 176 if (_puserDataAtom != NULL) 177 { 178 PV_MP4_FF_DELETE(NULL, PVA_FF_UserDataAtom, _puserDataAtom); 179 } 180 181 if (_pFileTypeAtom != NULL) 182 { 183 PV_MP4_FF_DELETE(NULL, PVA_FF_FileTypeAtom, _pFileTypeAtom); 184 } 185 if (_aFs) 186 { 187 PVA_FF_AtomUtils::closeFileSession(OSCL_STATIC_CAST(Oscl_FileServer*, _aFs)); 188 } 189 } 190 191 void PVA_FF_Mpeg4File::SetCacheSize(uint32 aCacheSize) 192 { 193 iCacheSize = aCacheSize; 194 } 195 bool 196 PVA_FF_Mpeg4File::init(int32 mediaType, 197 void *osclFileServerSession, 198 uint32 fileAuthoringFlags) 199 { 200 OSCL_UNUSED_ARG(mediaType); 201 _modifiable = true; // Allow addition of media samples 202 _firstFrameInLayer0 = true; 203 _firstFrameInLayer1 = true; 204 _fileWriteFailed = false; 205 206 _o3GPPTrack = true; 207 _oWMFTrack = false; 208 _oPVMMTrack = false; 209 _oMPEGTrack = false; 210 211 _oFileRenderCalled = false; 212 _oUserDataPopulated = false; 213 _oFtypPopulated = false; 214 215 _baseOffset = 0; 216 _oInterLeaveEnabled = false; 217 _oMovieAtomUpfront = false; 218 219 _oAuthorASSETINFOAtoms = false; 220 _oChunkStart = false; 221 222 // Movie Fragments flags initialised 223 _oMovieFragmentEnabled = false; 224 _oComposeMoofAtom = false; 225 _movieFragmentDuration = DEFAULT_MOVIE_FRAGMENT_DURATION_IN_MS; 226 _pCurrentMoofAtom = NULL; 227 _pCurrentMediaDataAtom = NULL; 228 _currentMoofOffset = 0; 229 _sequenceNumber = 0; 230 231 232 _aFs = osclFileServerSession; 233 234 _nextAvailableODID = 1; 235 _tempFileIndex = 'a'; 236 237 _pmediaDataAtomVec = NULL; 238 _pmovieAtom = NULL; 239 240 _puserDataAtom = NULL; 241 _pFileTypeAtom = NULL; 242 243 _initialUserDataSize = 0; 244 _oDirectRenderEnabled = false; 245 246 _oSetTitleDone = false; 247 _oSetAuthorDone = false; 248 _oSetCopyrightDone = false; 249 _oSetDescriptionDone = false; 250 _oSetRatingDone = false; 251 _oSetCreationDateDone = false; 252 _oSetPerformerDone = false; 253 _oSetRatingDone = false; 254 _oSetGenreDone = false; 255 _oSetClassificationDone = false; 256 _oSetLocationInfoDone = false; 257 _oSetAlbumDone = false; 258 _oSetRecordingYearDone = false; 259 260 261 _totalTempFileRemoval = false; 262 _oUserDataUpFront = true; 263 _oIsFileOpen = false; 264 _oFirstSampleEditMode = false; 265 266 _fileAuthoringFlags = fileAuthoringFlags; 267 268 if (fileAuthoringFlags & PVMP4FF_SET_MEDIA_INTERLEAVE_MODE) 269 { 270 _oInterLeaveEnabled = true; 271 } 272 273 if (fileAuthoringFlags & PVMP4FF_SET_META_DATA_UPFRONT_MODE) 274 { 275 _oMovieAtomUpfront = true; 276 } 277 278 if ((fileAuthoringFlags & PVMP4FF_3GPP_DOWNLOAD_MODE) == 279 (PVMP4FF_3GPP_DOWNLOAD_MODE)) 280 { 281 //Not possible to remove temp files, without output file name being set 282 if (_outputFileNameSet == false) 283 { 284 return false; 285 } 286 _oInterLeaveEnabled = true; 287 _totalTempFileRemoval = true; 288 _oUserDataUpFront = false; 289 } 290 291 if (fileAuthoringFlags & PVMP4FF_SET_FIRST_SAMPLE_EDIT_MODE) 292 { 293 /* Supported only if interleaving is enabled */ 294 if (!_oInterLeaveEnabled) 295 { 296 return false; 297 } 298 _oFirstSampleEditMode = true; 299 } 300 301 // Movie fragment mode 302 if ((fileAuthoringFlags & PVMP4FF_MOVIE_FRAGMENT_MODE) == PVMP4FF_MOVIE_FRAGMENT_MODE) 303 { 304 if (!_oInterLeaveEnabled) 305 { 306 return false; 307 } 308 _oMovieFragmentEnabled = true; 309 _totalTempFileRemoval = true; 310 _oUserDataUpFront = false; 311 } 312 313 // Create user data atom 314 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_UserDataAtom, (), _puserDataAtom); 315 316 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_FileTypeAtom, (), _pFileTypeAtom); 317 318 // Create the moov atom 319 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieAtom, (fileAuthoringFlags), _pmovieAtom); 320 321 // Movie fragment atom vectors initialised 322 if (_oMovieFragmentEnabled) 323 { 324 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentRandomAccessAtom, (), _pMfraAtom); 325 } 326 327 // IODS uses the first ODID, hence the increment here. 328 _nextAvailableODID++; 329 330 // Create miscellaneous vector of atoms 331 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtomVecType, (), _pmediaDataAtomVec); 332 333 _pparent = NULL; 334 335 /* 336 * In interleave mode, create only ONE media atom, to store 337 * all the media samples. 338 */ 339 if (_oInterLeaveEnabled) 340 { 341 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBufferVecType, (), _pInterLeaveBufferVec); 342 PVA_FF_MediaDataAtom *mda = NULL; 343 if (!_totalTempFileRemoval) 344 { 345 // Create PVA_FF_MediaDataAtom 346 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_tempOutputPath, 347 _tempFilePostfix, 348 _tempFileIndex, 349 MEDIA_DATA_ON_DISK, 350 _aFs, iCacheSize), 351 mda); 352 353 _tempFileIndex++; 354 } 355 else 356 { 357 if (_oFileOpenedOutsideAFFLib) 358 { 359 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_outputFileHandle, _aFs, iCacheSize), mda); 360 } 361 else 362 { 363 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_outputFileName, _aFs, iCacheSize), mda); 364 } 365 } 366 367 if (mda->_targetFileWriteError) 368 { 369 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, mda); 370 mda = NULL; 371 return false; 372 } 373 addMediaDataAtom(mda); 374 375 _interLeaveDuration = DEFAULT_INTERLEAVE_INTERVAL; 376 } 377 { 378 _pmovieAtom->createAssetInfoAtoms(); 379 } 380 recomputeSize(); 381 382 return true; 383 } 384 385 bool 386 PVA_FF_Mpeg4File::setOutputFileName(PVA_FF_UNICODE_STRING_PARAM outputFileName) 387 { 388 _targetFileName = (_STRLIT("")); 389 _oPartialTempFileRemoval = false; 390 _outputFileName = _STRLIT(""); 391 _outputFileNameSet = false; 392 _outputFileHandle = NULL; 393 _targetFileHandle = NULL; 394 _oFileOpenedOutsideAFFLib = false; 395 396 if (outputFileName.get_size() > 0) 397 { 398 _outputFileName += outputFileName; 399 _outputFileNameSet = true; 400 401 if (!_oPartialTempFileRemoval) 402 { 403 _targetFileName += outputFileName; 404 _oPartialTempFileRemoval = true; 405 } 406 return true; 407 } 408 return false; 409 } 410 411 bool 412 PVA_FF_Mpeg4File::setOutputFileHandle(MP4_AUTHOR_FF_FILE_HANDLE outputFileHandle) 413 { 414 _targetFileName = (_STRLIT("")); 415 _oPartialTempFileRemoval = false; 416 _outputFileName = _STRLIT(""); 417 _outputFileNameSet = false; 418 _outputFileHandle = NULL; 419 _targetFileHandle = NULL; 420 _oFileOpenedOutsideAFFLib = false; 421 422 if (outputFileHandle != NULL) 423 { 424 _outputFileHandle = outputFileHandle; 425 _outputFileNameSet = true; 426 427 if (!_oPartialTempFileRemoval) 428 { 429 _targetFileHandle = outputFileHandle; 430 _oPartialTempFileRemoval = true; 431 } 432 _oFileOpenedOutsideAFFLib = true; 433 return true; 434 } 435 return false; 436 } 437 438 uint32 439 PVA_FF_Mpeg4File::addTrack(int32 mediaType, 440 int32 codecType, 441 bool oDirectRender, 442 uint8 profile, 443 uint8 profileComp, 444 uint8 level) 445 { 446 uint32 TrackID = 0; 447 PVA_FF_TrackAtom *pmediatrack = NULL; 448 _codecType = codecType; 449 PVA_FF_MediaDataAtom *mda = NULL; 450 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = NULL; 451 452 if (!_oInterLeaveEnabled) 453 { 454 if (oDirectRender) 455 { 456 if (!_oDirectRenderEnabled) 457 { 458 if ((_oPartialTempFileRemoval) && 459 (_totalTempFileRemoval == false)) 460 { 461 _oDirectRenderEnabled = true; 462 463 if (_oFileOpenedOutsideAFFLib) 464 { 465 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), mda); 466 } 467 else 468 { 469 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileName, _aFs, iCacheSize), mda); 470 } 471 } 472 else 473 { 474 //Target File name not set 475 return (INVALID_TRACK_ID); 476 } 477 } 478 else 479 { 480 //Multiple Tracks cannot be directly rendered 481 return (INVALID_TRACK_ID); 482 } 483 } 484 else 485 { 486 //create new track - media will be stored in temp file 487 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_tempOutputPath, 488 _tempFilePostfix, 489 _tempFileIndex, 490 MEDIA_DATA_ON_DISK, 491 _aFs, iCacheSize), mda); 492 493 _tempFileIndex++; 494 } 495 addMediaDataAtom(mda); 496 } 497 else 498 { 499 mda = getMediaDataAtomForTrack(0); 500 } 501 502 if ((uint32) mediaType == MEDIA_TYPE_AUDIO) 503 { 504 // Create default audio track and add it to moov atom 505 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_AUDIO, 506 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(), 507 _fileAuthoringFlags, 508 codecType, 509 1, profile, profileComp, level), 510 pmediatrack); 511 512 if (mda) 513 mda->setTrackReferencePtr(pmediatrack); 514 _pmovieAtom->addTrackAtom(pmediatrack); 515 516 // add audio interleave buffer for track 517 if (_oInterLeaveEnabled) 518 { 519 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_AUDIO, 520 codecType, 521 pmediatrack->getTrackID()), 522 pInterLeaveBuffer); 523 524 addInterLeaveBuffer(pInterLeaveBuffer); 525 } 526 527 // Returns the index of the reference in the table to which this was 528 // just added (with a 1-based index NOT a zero-based index) 529 530 TrackID = pmediatrack->getTrackID(); 531 532 if ((codecType == CODEC_TYPE_AMR_AUDIO) || 533 (codecType == CODEC_TYPE_AMR_WB_AUDIO)) 534 { 535 _o3GPPTrack = true; 536 } 537 if (codecType == CODEC_TYPE_AAC_AUDIO) 538 { 539 _o3GPPTrack = true; 540 _oMPEGTrack = true; 541 } 542 } 543 544 if ((uint32) mediaType == MEDIA_TYPE_VISUAL) 545 { 546 if ((codecType == CODEC_TYPE_BASELINE_H263_VIDEO) || 547 (codecType == CODEC_TYPE_AVC_VIDEO)) 548 { 549 _o3GPPTrack = true; 550 } 551 else if (codecType == CODEC_TYPE_MPEG4_VIDEO) 552 { 553 _o3GPPTrack = true; 554 _oMPEGTrack = true; 555 } 556 557 // Create default video track and add it to moov atom 558 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_VISUAL, 559 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(), 560 _fileAuthoringFlags, 561 codecType, 562 1, profile, profileComp, level), 563 pmediatrack); 564 565 // add video interleave buffer for track 566 567 if (_oInterLeaveEnabled) 568 { 569 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_VISUAL, 570 codecType, 571 pmediatrack->getTrackID()), 572 pInterLeaveBuffer); 573 574 addInterLeaveBuffer(pInterLeaveBuffer); 575 } 576 577 if (mda) 578 mda->setTrackReferencePtr(pmediatrack); 579 _pmovieAtom->addTrackAtom(pmediatrack); 580 581 // Returns the index of the reference in the table to which this was 582 // just added (with a 1-based index NOT a zero-based index) 583 TrackID = pmediatrack->getTrackID(); 584 } 585 586 if ((uint32) mediaType == MEDIA_TYPE_TEXT)//added for the support of timed text track 587 { 588 if (codecType == CODEC_TYPE_TIMED_TEXT) 589 { 590 _o3GPPTrack = true; 591 } 592 // Create default video track and add it to moov atom 593 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtom, (MEDIA_TYPE_TEXT, 594 _pmovieAtom->getMutableMovieHeaderAtom().findNextTrackID(), 595 _fileAuthoringFlags, 596 codecType, 597 1, 598 profile, profileComp, level), 599 pmediatrack); 600 601 // add text interleave buffer for track 602 if (_oInterLeaveEnabled) 603 { 604 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_InterLeaveBuffer, (MEDIA_TYPE_TEXT, 605 codecType, 606 pmediatrack->getTrackID()), 607 pInterLeaveBuffer); 608 609 addInterLeaveBuffer(pInterLeaveBuffer); 610 } 611 612 mda->setTrackReferencePtr(pmediatrack); 613 _pmovieAtom->addTrackAtom(pmediatrack); 614 615 // Returns the index of the reference in the table to which this was 616 // just added (with a 1-based index NOT a zero-based index) 617 TrackID = pmediatrack->getTrackID(); 618 } 619 recomputeSize(); 620 return (TrackID); 621 } 622 623 void 624 PVA_FF_Mpeg4File::addTrackReference(uint32 currtrackID, int32 reftrackID) 625 { 626 PVA_FF_TrackAtom *pCurrTrack = _pmovieAtom->getMediaTrack(currtrackID); 627 pCurrTrack->addTrackReference(reftrackID); 628 return; 629 } 630 631 void 632 PVA_FF_Mpeg4File::setTargetBitrate(uint32 trackID, uint32 avgBitRate, uint32 maxBitRate, uint32 bufferSizeDB) 633 { 634 _pmovieAtom->setTargetBitrate(trackID, avgBitRate, maxBitRate, bufferSizeDB); 635 return; 636 } 637 638 void 639 PVA_FF_Mpeg4File::setTimeScale(uint32 trackID, uint32 rate) 640 { 641 // Set the sample rate for the specific video track 642 _pmovieAtom->setTimeScale(trackID, rate); 643 return; 644 } 645 646 //this will work same as the addsampletotrack but this 647 //will be called only for timed text file format 648 bool PVA_FF_Mpeg4File::addTextSampleToTrack(uint32 trackID, 649 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList, 650 uint32 ts, uint8 flags, int32 index, uint8* textsamplemodifier) 651 { 652 OSCL_UNUSED_ARG(textsamplemodifier); 653 PVA_FF_TrackAtom *mediaTrack; 654 uint32 mediaType; 655 int32 codecType; 656 bool retVal = true; 657 658 mediaTrack = _pmovieAtom->getMediaTrack(trackID); 659 mediaType = mediaTrack->getMediaType(); 660 codecType = _pmovieAtom->getCodecType(trackID); 661 662 // Create media sample buffer and size field 663 uint32 size = 0; 664 // temporary variables 665 uint32 ii = 0; 666 OsclBinIStreamBigEndian stream; 667 668 if (!fragmentList.empty()) 669 { 670 if (mediaType == MEDIA_TYPE_TEXT)//CALCULATES SIZE OF TIMED TEXT SAMPLE 671 { 672 for (ii = 0; ii < fragmentList.size(); ii++) 673 { 674 size += fragmentList[ii].len; 675 } 676 } 677 } 678 679 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 680 if (mediaType == MEDIA_TYPE_TEXT) 681 { 682 if (_modifiable) 683 { 684 // The layer in the flags byte indicates which video track to add to 685 // int32 trackNum = (int32)(flags & 0x70) >> 4; 686 687 if (mediaTrack) 688 { 689 // Add to mdat PVA_FF_Atom for the specified track 690 if (codecType == CODEC_TYPE_TIMED_TEXT) 691 { 692 if (_oInterLeaveEnabled) 693 { 694 if (!addTextMediaSampleInterleave(trackID, fragmentList, size, ts, flags, index)) 695 { 696 return false; 697 } 698 } 699 else 700 { 701 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType)) 702 { 703 retVal = false; 704 } 705 _pmovieAtom->addTextSampleToTrack(trackID, fragmentList, size, ts, flags, index); 706 } 707 } 708 } 709 else 710 { 711 return false; 712 } 713 } 714 else 715 { 716 return false; 717 } 718 } 719 720 return (retVal); 721 } 722 723 // Movie fragment Mode : APIs to set and get duration of each MOOF atom 724 void 725 PVA_FF_Mpeg4File::setMovieFragmentDuration(uint32 duration) 726 { 727 _movieFragmentDuration = duration; 728 return; 729 } 730 731 732 733 uint32 734 PVA_FF_Mpeg4File::getMovieFragmentDuration() 735 { 736 return _movieFragmentDuration; 737 } 738 739 740 bool 741 PVA_FF_Mpeg4File::addSampleToTrack(uint32 trackID, 742 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList, // vector which contains either NALs or a sample 743 uint32 ts, uint8 flags) 744 { 745 PVA_FF_TrackAtom *mediaTrack; 746 uint32 mediaType; 747 int32 codecType; 748 bool retVal = true; 749 //int32 flags; 750 751 mediaTrack = _pmovieAtom->getMediaTrack(trackID); 752 mediaType = mediaTrack->getMediaType(); 753 codecType = _pmovieAtom->getCodecType(trackID); 754 755 // Create media sample buffer and size field 756 uint32 size = 0; 757 // temporary variables 758 uint32 ii = 0; 759 OsclBinIStreamBigEndian stream; 760 OsclMemoryFragment fragment; 761 if (!fragmentList.empty()) 762 { 763 // calculate size of AVC sample 764 if (mediaType == MEDIA_TYPE_VISUAL && codecType == CODEC_TYPE_AVC_VIDEO) 765 { 766 // compose AVC sample 767 for (uint32 ii = 0; ii < fragmentList.size(); ii++) 768 { 769 size += (fragmentList[ii].len + 4); // length + '2' size of NAL unit length field 770 } 771 } 772 // all memory fragments in the vector combines into one sample 773 else 774 { 775 for (ii = 0; ii < fragmentList.size(); ii++) 776 { 777 size += fragmentList[ii].len; 778 } 779 } 780 } 781 782 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 783 if (mediaType == MEDIA_TYPE_AUDIO) 784 { 785 if (_modifiable) 786 { 787 if (mediaTrack != NULL) 788 { 789 if ((mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO) || 790 (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO)) 791 { 792 if (size >= 1) 793 { 794 PVA_FF_TrackAtom *track = _pmovieAtom->getMediaTrack(trackID); 795 if (track != NULL) 796 { 797 // FT is in the first byte that comes off the encoder 798 flags = *((uint8*)(fragmentList.front().ptr)); 799 uint32 mode_set = 0; 800 if (flags < 16) 801 { 802 mode_set = AMRModeSetMask[(flags&0x0f)]; 803 } 804 if (flags < 9) 805 { 806 // JUST TO ENSURE THAT THE PADDED BITS ARE ZERO 807 fragment = fragmentList.back(); 808 if (mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO) 809 { 810 ((uint8*)fragment.ptr)[ fragment.len - 1] &= aAMRNBZeroSetMask[(flags&0x0f)]; 811 } 812 else if (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO) 813 { 814 ((uint8*)fragment.ptr)[ fragment.len - 1] &= aAMRWBZeroSetMask[(flags&0x0f)]; 815 } 816 817 } 818 if (_oInterLeaveEnabled) 819 { 820 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags)) 821 { 822 return false; 823 } 824 } 825 else 826 { 827 // Add to mdat PVA_FF_Atom for the specified track 828 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType)) 829 { 830 retVal = false; 831 } 832 // Add to moov atom (in turn adds to tracks) 833 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size, 834 ts, flags); 835 } 836 } 837 } 838 else 839 { 840 return false; 841 } 842 } 843 else if (mediaTrack->getCodecType() == CODEC_TYPE_AAC_AUDIO) 844 { 845 if (size > 0) 846 { 847 if (_oInterLeaveEnabled) 848 { 849 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags)) 850 { 851 return false; 852 } 853 } 854 else 855 { 856 857 // Add to mdat PVA_FF_Atom for the specified track 858 859 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType)) 860 { 861 retVal = false; 862 } 863 864 flags = 0; 865 866 // Add to moov atom (in turn adds to tracks) 867 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size, 868 ts, flags); 869 } 870 } 871 } 872 } 873 else 874 { 875 return false; 876 } 877 } 878 else 879 { 880 return false; 881 } 882 } 883 884 if (mediaType == MEDIA_TYPE_VISUAL) 885 { 886 // For the first frame in each layer, pull off the VOL header. For the base layer 887 // (layer=0), this fp the first 28 bytes. For the enhancememnt(temporal) layer 888 // (layer=1), this fp the first 17 bytes (compact version with no repeate headers). 889 // 890 // Note that this fp making the assumption that the first frame of each layer will 891 // contain this VOL header information. In the current encoder (version 1.0), this 892 // fp true. 893 // 894 // Eventually strip the VOL headers from the first samples of each layer so that 895 // there fp no redundancy w.r.t. the VOL headers in the MP4 file. Currently the 896 // VOL headers are remaining in the first frame data 897 898 // uint8 layer = (uint8)((flags & 0x70) >> 4); 899 900 901 if (codecType == CODEC_TYPE_BASELINE_H263_VIDEO) 902 { 903 if (_firstFrameInLayer0) 904 { 905 _firstFrameInLayer0 = false; 906 } 907 } 908 909 if (_modifiable) 910 { 911 // The layer in the flags byte indicates which video track to add to 912 // int32 trackNum = (int32)(flags & 0x70) >> 4; 913 914 if (mediaTrack) 915 { 916 // Add to mdat PVA_FF_Atom for the specified track 917 if ((codecType == CODEC_TYPE_MPEG4_VIDEO) || 918 (codecType == CODEC_TYPE_BASELINE_H263_VIDEO) || 919 (codecType == CODEC_TYPE_AVC_VIDEO)) 920 { 921 if (_oInterLeaveEnabled) 922 { 923 if (!addMediaSampleInterleave(trackID, fragmentList, size, ts, flags)) 924 { 925 return false; 926 } 927 } 928 else 929 { 930 931 if (!mdatAtom->addRawSample((fragmentList), (size), mediaType, codecType)) 932 { 933 retVal = false; 934 } 935 _pmovieAtom->addSampleToTrack(trackID, fragmentList, size, ts, flags); 936 } 937 } 938 } 939 else 940 { 941 return false; 942 } 943 } 944 else 945 { 946 return false; 947 } 948 } 949 950 return (retVal); 951 } 952 953 // The following methods are used to set the user data 954 void 955 PVA_FF_Mpeg4File::setVersion(PVA_FF_UNICODE_STRING_PARAM version, uint16 langCode) 956 { 957 OSCL_UNUSED_ARG(version); 958 OSCL_UNUSED_ARG(langCode); 959 } 960 961 void 962 PVA_FF_Mpeg4File::setTitle(PVA_FF_UNICODE_STRING_PARAM title, uint16 langCode) 963 { 964 if (!_oSetTitleDone) 965 { 966 _oSetTitleDone = true; 967 _title = title; 968 if (_pmovieAtom != NULL) 969 { 970 _pmovieAtom->setTitleInfo(title, langCode); 971 } 972 } 973 } 974 975 void 976 PVA_FF_Mpeg4File::setAuthor(PVA_FF_UNICODE_STRING_PARAM author, uint16 langCode) 977 { 978 if (!_oSetAuthorDone) 979 { 980 _oSetAuthorDone = true; 981 _author = author; 982 if (_pmovieAtom != NULL) 983 { 984 _pmovieAtom->setAuthorInfo(author, langCode); 985 } 986 } 987 } 988 989 void 990 PVA_FF_Mpeg4File::setCopyright(PVA_FF_UNICODE_STRING_PARAM copyright, uint16 langCode) 991 { 992 if (!_oSetCopyrightDone) 993 { 994 _oSetCopyrightDone = true; 995 _copyright = copyright; 996 if (_pmovieAtom != NULL) 997 { 998 _pmovieAtom->setCopyRightInfo(copyright, langCode); 999 } 1000 } 1001 } 1002 1003 void 1004 PVA_FF_Mpeg4File::setDescription(PVA_FF_UNICODE_STRING_PARAM description, uint16 langCode) 1005 { 1006 if (!_oSetDescriptionDone) 1007 { 1008 _oSetDescriptionDone = true; 1009 _description = description; 1010 if (_pmovieAtom != NULL) 1011 { 1012 _pmovieAtom->setDescription(description, langCode); 1013 } 1014 } 1015 } 1016 1017 void 1018 PVA_FF_Mpeg4File::setRating(PVA_FF_UNICODE_STRING_PARAM ratingInfo, 1019 uint16 langCode, 1020 uint32 ratingEntity, 1021 uint32 ratingCriteria) 1022 { 1023 OSCL_UNUSED_ARG(langCode); 1024 1025 if (!_oSetRatingDone) 1026 { 1027 _oSetRatingDone = true; 1028 _ratingInfo = ratingInfo; 1029 _ratingEntity = ratingEntity; 1030 _ratingCriteria = ratingCriteria; 1031 if (_pmovieAtom != NULL) 1032 { 1033 _pmovieAtom->setRatingInfo(ratingInfo, ratingEntity, ratingCriteria, langCode); 1034 } 1035 1036 } 1037 } 1038 1039 void 1040 PVA_FF_Mpeg4File::setPerformer(PVA_FF_UNICODE_STRING_PARAM performer, uint16 langCode) 1041 { 1042 OSCL_UNUSED_ARG(langCode); 1043 1044 if (!_oSetPerformerDone) 1045 { 1046 _oSetPerformerDone = true; 1047 _performer = performer; 1048 1049 if (_pmovieAtom != NULL) 1050 { 1051 _pmovieAtom->setPerformerInfo(performer, langCode); 1052 } 1053 1054 } 1055 } 1056 1057 void 1058 PVA_FF_Mpeg4File::setGenre(PVA_FF_UNICODE_STRING_PARAM genre, uint16 langCode) 1059 { 1060 OSCL_UNUSED_ARG(langCode); 1061 1062 if (!_oSetGenreDone) 1063 { 1064 _oSetGenreDone = true; 1065 _genre = genre; 1066 1067 if (_pmovieAtom != NULL) 1068 { 1069 _pmovieAtom->setGenreInfo(genre, langCode); 1070 } 1071 1072 } 1073 } 1074 1075 void 1076 PVA_FF_Mpeg4File::setClassification(PVA_FF_UNICODE_STRING_PARAM classificationInfo, 1077 uint32 classificationEntity, uint16 classificationTable, 1078 uint16 langCode) 1079 { 1080 OSCL_UNUSED_ARG(langCode); 1081 1082 if (!_oSetClassificationDone) 1083 { 1084 _oSetClassificationDone = true; 1085 _classificationInfo = classificationInfo; 1086 _classificationEntity = classificationEntity; 1087 _classificationTable = classificationTable; 1088 1089 if (_pmovieAtom != NULL) 1090 { 1091 _pmovieAtom->setClassificationInfo(classificationInfo, classificationEntity, classificationTable, langCode); 1092 } 1093 } 1094 } 1095 1096 void 1097 PVA_FF_Mpeg4File::setKeyWord(uint8 keyWordSize, PVA_FF_UNICODE_HEAP_STRING keyWordInfo, uint16 langCode) 1098 { 1099 OSCL_UNUSED_ARG(langCode); 1100 1101 _keyWordSize = keyWordSize; 1102 _keyWordInfo = keyWordInfo; 1103 1104 if (_pmovieAtom != NULL) 1105 { 1106 _pmovieAtom->setKeyWordsInfo(keyWordSize, keyWordInfo, langCode); 1107 } 1108 } 1109 1110 void 1111 PVA_FF_Mpeg4File::setLocationInfo(PvmfAssetInfo3GPPLocationStruct *ptr_loc_struct) 1112 { 1113 if (!_oSetLocationInfoDone) 1114 { 1115 _oSetLocationInfoDone = true; 1116 _locationName = ptr_loc_struct->_location_name; 1117 _locationInfoAstrBody = ptr_loc_struct->_astronomical_body; 1118 _locationInfoAddNotes = ptr_loc_struct->_additional_notes; 1119 _locationInfoRole = ptr_loc_struct->_role; 1120 _locationInfoLongitude = ptr_loc_struct->_longitude; 1121 _locationInfoAltitude = ptr_loc_struct->_altitude; 1122 _locationInfoLatitude = ptr_loc_struct->_latitude; 1123 1124 if (_pmovieAtom != NULL) 1125 { 1126 _pmovieAtom->setLocationInfo(ptr_loc_struct); 1127 } 1128 } 1129 } 1130 1131 void 1132 PVA_FF_Mpeg4File::setAlbumInfo(PVA_FF_UNICODE_STRING_PARAM albumInfo, uint16 langCode) 1133 { 1134 if (!_oSetAlbumDone) 1135 { 1136 _oSetAlbumDone = true; 1137 _albumInfo = albumInfo; 1138 1139 if (_pmovieAtom != NULL) 1140 { 1141 _pmovieAtom->setAlbumInfo(albumInfo, langCode); 1142 } 1143 1144 } 1145 } 1146 1147 void 1148 PVA_FF_Mpeg4File::setAlbumTrackNumber(uint8 trackNumber) 1149 { 1150 if (_pmovieAtom != NULL) 1151 { 1152 _pmovieAtom->setAlbumTrackNumber(trackNumber); 1153 } 1154 } 1155 1156 void 1157 PVA_FF_Mpeg4File::setRecordingYear(uint16 recordingYear) 1158 { 1159 if (!_oSetRecordingYearDone) 1160 { 1161 _oSetRecordingYearDone = true; 1162 _recordingYear = recordingYear; 1163 1164 if (_pmovieAtom != NULL) 1165 { 1166 _pmovieAtom->setRecordingYearInfo(recordingYear); 1167 } 1168 1169 } 1170 } 1171 1172 void 1173 PVA_FF_Mpeg4File::setCreationDate(PVA_FF_UNICODE_STRING_PARAM creationDate) 1174 { 1175 if (!_oSetCreationDateDone) 1176 { 1177 _oSetCreationDateDone = true; 1178 _creationDate = creationDate; 1179 } 1180 } 1181 1182 void 1183 PVA_FF_Mpeg4File::setVideoParams(uint32 trackID, 1184 float frate, 1185 uint16 interval, 1186 uint32 frame_width, 1187 uint32 frame_height) 1188 { 1189 OSCL_UNUSED_ARG(frate); 1190 OSCL_UNUSED_ARG(interval); 1191 PVA_FF_TrackAtom *trackAtom; 1192 trackAtom = _pmovieAtom->getMediaTrack(trackID); 1193 1194 if (trackAtom != NULL) 1195 trackAtom->setVideoParams(frame_width, frame_height); 1196 1197 return; 1198 } 1199 1200 void 1201 PVA_FF_Mpeg4File::setH263ProfileLevel(uint32 trackID, 1202 uint8 profile, 1203 uint8 level) 1204 { 1205 PVA_FF_TrackAtom *trackAtom; 1206 trackAtom = _pmovieAtom->getMediaTrack(trackID); 1207 trackAtom->setH263ProfileLevel(profile, level); 1208 return; 1209 } 1210 1211 // Methods to get and set the sample rate (i.e. timescales) for the streams and 1212 // the overall Mpeg-4 presentation 1213 void 1214 PVA_FF_Mpeg4File::setPresentationTimescale(uint32 timescale) 1215 { // Set the overall timescale of the Mpeg-4 presentation 1216 _pmovieAtom->setTimeScale(timescale); 1217 } 1218 1219 void 1220 PVA_FF_Mpeg4File::addMediaDataAtom(PVA_FF_MediaDataAtom* atom) 1221 { 1222 if (_modifiable) 1223 { 1224 _pmediaDataAtomVec->push_back(atom); 1225 } 1226 } 1227 1228 //for timed text only 1229 void 1230 PVA_FF_Mpeg4File::setTextDecoderSpecificInfo(PVA_FF_TextSampleDescInfo *header, int32 trackID) 1231 { 1232 PVA_FF_TextSampleDescInfo *pinfo = NULL; 1233 pinfo = header; 1234 _pmovieAtom->addTextDecoderSpecificInfo(pinfo, trackID); 1235 return; 1236 } 1237 1238 1239 void 1240 PVA_FF_Mpeg4File::setDecoderSpecificInfo(uint8 * header, int32 size, int32 trackID) 1241 { 1242 PVA_FF_DecoderSpecificInfo *pinfo = NULL; 1243 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_DecoderSpecificInfo, (header, (uint32)size), pinfo); 1244 _pmovieAtom->addDecoderSpecificInfo(pinfo, trackID); 1245 PVA_FF_TrackAtom *track = _pmovieAtom->getMediaTrack(trackID); 1246 if (track->getMediaType() == MEDIA_TYPE_VISUAL) 1247 { 1248 if (track->getCodecType() == CODEC_TYPE_AVC_VIDEO) 1249 { 1250 PV_MP4_FF_DELETE(NULL, PVA_FF_DecoderSpecificInfo, pinfo); 1251 } 1252 } 1253 } 1254 1255 void 1256 PVA_FF_Mpeg4File::recomputeSize() 1257 { 1258 uint32 i; 1259 uint32 size = getMovieAtom().getSize(); 1260 1261 for (i = 0; i < getMediaDataAtomVec().size(); i++) 1262 { 1263 size += getMediaDataAtomVec()[i]->getSize(); 1264 } 1265 _size = size; 1266 } 1267 1268 // Rendering the PVA_FF_Mpeg4File in proper format (bitlengths, etc.) to an ostream 1269 bool 1270 PVA_FF_Mpeg4File::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp) 1271 { 1272 uint32 metaDataSize = 0; 1273 /* 1274 * Setting the major brand in ftyp atom 1275 */ 1276 if (!_oFtypPopulated) 1277 { 1278 if (_o3GPPTrack) 1279 { 1280 setMajorBrand(BRAND_3GPP4); 1281 setMajorBrandVersion(VERSION_3GPP4); 1282 } 1283 else if (_oMPEGTrack) 1284 { 1285 setMajorBrand(BRAND_MPEG4); 1286 setMajorBrandVersion(VERSION_MPEG4); 1287 } 1288 else if (_oPVMMTrack) 1289 { 1290 setMajorBrand(PVMM_BRAND); 1291 setMajorBrandVersion(PVMM_VERSION); 1292 } 1293 1294 /* 1295 * Add compatible brands 1296 */ 1297 if (_o3GPPTrack) 1298 { 1299 addCompatibleBrand(BRAND_3GPP4); 1300 } 1301 if (_oPVMMTrack) 1302 { 1303 addCompatibleBrand(PVMM_BRAND); 1304 } 1305 if (_oMPEGTrack) 1306 { 1307 addCompatibleBrand(BRAND_MPEG4); 1308 } 1309 addCompatibleBrand(BRAND_3GPP5); 1310 } 1311 1312 if( _oSetCreationDateDone ) 1313 { 1314 uint32 time = convertCreationTime(_creationDate); 1315 1316 _pmovieAtom->getMutableMovieHeaderAtom().setCreationTime(time); 1317 _pmovieAtom->getMutableMovieHeaderAtom().setModificationTime(time); 1318 } 1319 1320 if ((_o3GPPTrack == true) || (_oPVMMTrack == true) || (_oMPEGTrack == true)) 1321 { 1322 _pFileTypeAtom->renderToFileStream(fp); 1323 1324 metaDataSize += _pFileTypeAtom->getSize(); 1325 } 1326 { 1327 if (!_oDirectRenderEnabled) 1328 { 1329 populateUserDataAtom(); 1330 } 1331 } 1332 if (!_fileAuthoringFlags) 1333 { 1334 if (_oUserDataUpFront) 1335 { 1336 { 1337 if (!_puserDataAtom->renderToFileStream(fp)) 1338 { 1339 return false; 1340 } 1341 metaDataSize += _puserDataAtom->getSize(); 1342 } 1343 } 1344 } 1345 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval)) 1346 { 1347 PVA_FF_AtomUtils::seekFromStart(fp, _directRenderFileOffset); 1348 } 1349 1350 _oFileRenderCalled = true; 1351 1352 uint32 chunkFileOffset = 0; 1353 1354 int32 i; 1355 uint32 size = _pmediaDataAtomVec->size(); 1356 1357 _pmovieAtom->prepareToRender(); 1358 1359 if (_oMovieAtomUpfront) 1360 { 1361 metaDataSize += _pmovieAtom->getSize(); 1362 1363 chunkFileOffset = DEFAULT_ATOM_SIZE + metaDataSize; 1364 1365 // Update all chunk offsets 1366 for (i = size - 1; i >= 0; i--) 1367 { 1368 PVA_FF_MediaDataAtom *mdat = (*_pmediaDataAtomVec)[i]; 1369 1370 if (!(mdat->IsTargetRender())) 1371 { 1372 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 1373 (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec(); 1374 1375 if (trefVec != NULL) 1376 { 1377 for (uint32 trefVecIndex = 0; 1378 trefVecIndex < trefVec->size(); 1379 trefVecIndex++) 1380 { 1381 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset); 1382 } 1383 } 1384 chunkFileOffset += mdat->getMediaDataSize(); 1385 } 1386 else 1387 { 1388 // not supported - no direct render with media interleaving 1389 return false; 1390 } 1391 } 1392 1393 // Render the movie atom to the file stream 1394 if (!_pmovieAtom->renderToFileStream(fp)) 1395 { 1396 return false; 1397 } 1398 } 1399 1400 1401 // Render all mediaData atoms to the file stream 1402 for (i = size - 1; i >= 0; i--) 1403 { 1404 bool oRenderMdat = true; 1405 if (oRenderMdat) 1406 { 1407 if (!((*_pmediaDataAtomVec)[i]->IsTargetRender())) 1408 { 1409 if (!((*_pmediaDataAtomVec)[i]->renderToFileStream(fp))) 1410 { 1411 _fileWriteFailed = true; 1412 return false; 1413 } 1414 if ((*_pmediaDataAtomVec)[i]->_targetFileWriteError == true) 1415 { 1416 _fileWriteFailed = true; 1417 return false; 1418 } 1419 1420 if (!_oMovieAtomUpfront) 1421 { 1422 chunkFileOffset = 1423 (*_pmediaDataAtomVec)[i]->getFileOffsetForChunkStart(); 1424 if (chunkFileOffset != 0) 1425 { 1426 // Only true when fp a PVA_FF_MediaDataAtom 1427 1428 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 1429 (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec(); 1430 1431 1432 if (trefVec != NULL) 1433 { 1434 for (uint32 trefVecIndex = 0; 1435 trefVecIndex < trefVec->size(); 1436 trefVecIndex++) 1437 { 1438 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset); 1439 } 1440 } 1441 } 1442 } 1443 } 1444 else 1445 { 1446 if (!_oMovieAtomUpfront) 1447 { 1448 chunkFileOffset = 1449 (*_pmediaDataAtomVec)[i]->getFileOffsetForChunkStart(); 1450 1451 if (chunkFileOffset != 0) 1452 { 1453 // Only true when fp a PVA_FF_MediaDataAtom 1454 1455 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = (*_pmediaDataAtomVec)[i]->getTrackReferencePtrVec(); 1456 if (trefVec != NULL) 1457 { 1458 for (uint32 trefVecIndex = 0; 1459 trefVecIndex < trefVec->size(); 1460 trefVecIndex++) 1461 { 1462 (*trefVec)[trefVecIndex]->updateAtomFileOffsets(chunkFileOffset); 1463 } 1464 } 1465 } 1466 } 1467 } 1468 } 1469 } 1470 if (!_fileAuthoringFlags) 1471 { 1472 if (!_oUserDataUpFront) 1473 { 1474 { 1475 if (!_puserDataAtom->renderToFileStream(fp)) 1476 { 1477 return false; 1478 } 1479 } 1480 } 1481 } 1482 //Important: This needs to be done AFTER the user data has been rendered to file 1483 if (!_oMovieAtomUpfront) 1484 { 1485 // Render the movie atom to the file stream 1486 if (!_pmovieAtom->renderToFileStream(fp)) 1487 { 1488 return false; 1489 } 1490 } 1491 1492 _tempFileIndex = 'a'; 1493 1494 return true; 1495 } 1496 1497 // Rendering the MP4 file to disk 1498 bool 1499 PVA_FF_Mpeg4File::renderToFile(PVA_FF_UNICODE_STRING_PARAM filename) 1500 { 1501 MP4_AUTHOR_FF_FILE_IO_WRAP fp; 1502 fp._filePtr = NULL; 1503 fp._osclFileServerSession = NULL; 1504 bool status = true; 1505 1506 if (!(_oMovieFragmentEnabled && _oComposeMoofAtom)) 1507 { 1508 1509 _modifiable = false; // Only allow addition of samples BEFORE rendering to disk 1510 // After render to disk - cannot add more data 1511 1512 1513 //make sure to flush the interleave buffers, be it to temp files 1514 //or to target files 1515 uint32 k = 0; 1516 1517 for (k = 0; status && k < _pmediaDataAtomVec->size(); k++) 1518 { 1519 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 1520 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec(); 1521 1522 if (trefVec != NULL) 1523 { 1524 for (uint32 trefVecIndex = 0; 1525 status && trefVecIndex < trefVec->size(); 1526 trefVecIndex++) 1527 { 1528 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 1529 uint32 trackID = pTrack->getTrackID(); 1530 1531 if (_oInterLeaveEnabled) 1532 { 1533 if (!flushInterLeaveBuffer(trackID)) 1534 { 1535 status = false; 1536 } 1537 } 1538 1539 } 1540 } 1541 } 1542 1543 bool targetRender = false; 1544 _directRenderFileOffset = 0; 1545 1546 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval)) 1547 { 1548 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++) 1549 { 1550 bool tempVal = ((*_pmediaDataAtomVec)[k]->IsTargetRender()); 1551 1552 if (tempVal) 1553 { 1554 if (targetRender) 1555 { 1556 //Only one track is allowed to be rendered directly onto the target 1557 //file 1558 status = false; 1559 } 1560 else 1561 { 1562 targetRender = true; 1563 1564 if (!((*_pmediaDataAtomVec)[k]->closeTargetFile())) 1565 { 1566 status = false; 1567 } 1568 1569 fp._filePtr = ((*_pmediaDataAtomVec)[k]->getTargetFilePtr()); 1570 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 1571 _directRenderFileOffset = 1572 ((*_pmediaDataAtomVec)[k]->getTotalDataRenderedToTargetFileInDirectRenderMode()); 1573 } 1574 } 1575 } 1576 } 1577 else 1578 { 1579 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 1580 PVA_FF_AtomUtils::openFile(&fp, filename, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY); 1581 _oIsFileOpen = true; 1582 } 1583 1584 if (fp._filePtr == NULL) 1585 { 1586 status = false; 1587 } 1588 1589 if (!renderToFileStream(&fp)) 1590 { 1591 status = false; 1592 } 1593 1594 if (_oIsFileOpen) 1595 { 1596 PVA_FF_AtomUtils::closeFile(&fp); 1597 _oIsFileOpen = false; 1598 } 1599 1600 if (_fileWriteFailed) 1601 { 1602 status = false; 1603 } 1604 } 1605 else 1606 { 1607 // flush interleave buffers into last TRUN 1608 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++) 1609 { 1610 if ((*_pmediaDataAtomVec)[k]->IsTargetRender()) 1611 { 1612 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 1613 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec(); 1614 1615 if (trefVec != NULL) 1616 { 1617 for (uint32 trefVecIndex = 0; status && trefVecIndex < trefVec->size(); trefVecIndex++) 1618 { 1619 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 1620 uint32 trackID = pTrack->getTrackID(); 1621 1622 if (_oInterLeaveEnabled) 1623 { 1624 if (!flushInterLeaveBuffer(trackID)) 1625 { 1626 status = false; 1627 } 1628 } 1629 } 1630 } 1631 } 1632 } 1633 1634 fp._filePtr = _targetFileHandle; 1635 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 1636 1637 // write movie fragment duration in movie extends atom 1638 _pmovieAtom->writeMovieFragmentDuration(&fp); 1639 1640 if (!renderMovieFragments()) 1641 { 1642 status = false; 1643 } 1644 1645 fp._filePtr = _targetFileHandle; 1646 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 1647 _pMfraAtom->renderToFileStream(&fp); 1648 _pmovieAtom->writeMaxSampleSize(&fp); 1649 if (_oIsFileOpen) 1650 { 1651 PVA_FF_AtomUtils::closeFile(&fp); 1652 _oIsFileOpen = false; 1653 } 1654 } 1655 1656 return status; 1657 } 1658 1659 1660 // Access function to set the postfix string for PVA_FF_MediaDataAtom objects 1661 // Set the post fix string for the temporary file in order to support multiple instances, 1662 // the goal fp to create temporary files with different names 1663 void 1664 PVA_FF_Mpeg4File::SetTempFilePostFix(PVA_FF_UNICODE_STRING_PARAM postFix) 1665 { 1666 _tempFilePostfix = (_STRLIT("")); 1667 _tempFilePostfix += postFix; 1668 } 1669 1670 // Access function to set the output path string for PVA_FF_MediaDataAtom objects 1671 // Set the output path string for the temporary files in order to generate them at the same location 1672 // as the final mp4 file. 1673 void 1674 PVA_FF_Mpeg4File::SetTempOutputPath(PVA_FF_UNICODE_STRING_PARAM outputPath) 1675 { 1676 _tempOutputPath = (_STRLIT("")); 1677 _tempOutputPath += outputPath; 1678 } 1679 1680 PVA_FF_MediaDataAtom* 1681 PVA_FF_Mpeg4File::getMediaDataAtomForTrack(uint32 trackID) 1682 { 1683 if (_oInterLeaveEnabled) 1684 { 1685 if (_pmediaDataAtomVec != NULL) 1686 { 1687 if (_pmediaDataAtomVec->size() > MIN_NUM_MEDIA_TRACKS) 1688 { 1689 int32 index = MIN_NUM_MEDIA_TRACKS; 1690 return (*_pmediaDataAtomVec)[index]; 1691 } 1692 } 1693 } 1694 else 1695 { 1696 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++) 1697 { 1698 PVA_FF_TrackAtom *pTrack = (PVA_FF_TrackAtom *)((*_pmediaDataAtomVec)[k]->getTrackReferencePtr()); 1699 uint32 tID = pTrack->getTrackID(); 1700 1701 if (tID == trackID) 1702 { 1703 return (*_pmediaDataAtomVec)[k]; 1704 } 1705 } 1706 } 1707 return (NULL); 1708 } 1709 1710 bool 1711 PVA_FF_Mpeg4File::addMultipleAccessUnitsToTrack(uint32 trackID, GAU *pgau) 1712 { 1713 PVA_FF_TrackAtom *mediaTrack; 1714 uint32 mediaType; 1715 bool retVal = true; 1716 1717 mediaTrack = _pmovieAtom->getMediaTrack(trackID); 1718 1719 if (mediaTrack == NULL) 1720 { 1721 return false; 1722 } 1723 1724 mediaType = mediaTrack->getMediaType(); 1725 1726 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 1727 1728 if (mdatAtom == NULL) 1729 { 1730 return false; 1731 } 1732 1733 if (mediaType == MEDIA_TYPE_AUDIO) 1734 { 1735 if (_modifiable) 1736 { 1737 if ((mediaTrack->getCodecType() == CODEC_TYPE_AMR_AUDIO) || 1738 (mediaTrack->getCodecType() == CODEC_TYPE_AMR_WB_AUDIO)) 1739 { 1740 int32 index = 0; 1741 1742 uint8 *frag_ptr = (uint8 *)pgau->buf.fragments[index].ptr; 1743 int32 frag_len = pgau->buf.fragments[index].len; 1744 1745 for (uint32 k = 0; k < pgau->numMediaSamples; k++) 1746 { 1747 uint8 frame_type = (uint8)pgau->info[k].sample_info; 1748 1749 frame_type = (uint8)(frame_type << 3); 1750 frame_type |= 0x04; 1751 1752 // Add to mdat PVA_FF_Atom for the specified track 1753 if (!mdatAtom->addRawSample(&frame_type, 1)) 1754 { 1755 retVal = false; 1756 } 1757 1758 int32 frame_size = pgau->info[k].len; 1759 1760 while (frame_size) 1761 { 1762 if (frag_len >= frame_size) 1763 { 1764 // Add to mdat PVA_FF_Atom for the specified track 1765 if (!mdatAtom->addRawSample(frag_ptr, 1766 frame_size)) 1767 { 1768 retVal = false; 1769 } 1770 1771 frag_ptr += frame_size; 1772 frag_len -= frame_size; 1773 frame_size = 0; 1774 } 1775 else 1776 { 1777 // Add to mdat PVA_FF_Atom for the specified track 1778 if (!mdatAtom->addRawSample(frag_ptr, 1779 frag_len)) 1780 { 1781 retVal = false; 1782 } 1783 1784 frame_size -= frag_len; 1785 1786 index++; 1787 1788 if (index == pgau->buf.num_fragments) 1789 { 1790 return false; 1791 } 1792 1793 frag_ptr = (uint8 *)pgau->buf.fragments[index].ptr; 1794 frag_len = pgau->buf.fragments[index].len; 1795 } 1796 } 1797 // Add to moov atom (in turn adds to tracks) 1798 _pmovieAtom->addSampleToTrack(trackID, NULL, 1799 (pgau->info[k].len + 1), 1800 pgau->info[k].ts, 1801 (uint8)pgau->info[k].sample_info); 1802 } 1803 } 1804 else 1805 { 1806 for (int32 k = 0; k < pgau->buf.num_fragments; k++) 1807 { 1808 // Add to mdat PVA_FF_Atom for the specified track 1809 if (!mdatAtom->addRawSample(pgau->buf.fragments[k].ptr, 1810 pgau->buf.fragments[k].len)) 1811 { 1812 retVal = false; 1813 } 1814 } 1815 1816 for (uint32 j = 0; j < pgau->numMediaSamples; j++) 1817 { 1818 // Add to moov atom (in turn adds to tracks) 1819 _pmovieAtom->addSampleToTrack(trackID, NULL, 1820 pgau->info[j].len, 1821 pgau->info[j].ts, 1822 (uint8)pgau->info[j].sample_info); 1823 } 1824 } 1825 } 1826 } 1827 else if (mediaType == MEDIA_TYPE_VISUAL) 1828 { 1829 if (_modifiable) 1830 { 1831 for (int32 k = 0; k < pgau->buf.num_fragments; k++) 1832 { 1833 // Add to mdat PVA_FF_Atom for the specified track 1834 if (!mdatAtom->addRawSample(pgau->buf.fragments[k].ptr, 1835 pgau->buf.fragments[k].len)) 1836 { 1837 retVal = false; 1838 } 1839 } 1840 1841 for (uint32 j = 0; j < pgau->numMediaSamples; j++) 1842 { 1843 // Add to moov atom (in turn adds to tracks) 1844 _pmovieAtom->addSampleToTrack(trackID, NULL, 1845 pgau->info[j].len, 1846 pgau->info[j].ts, 1847 (uint8)pgau->info[j].sample_info); 1848 } 1849 } 1850 } 1851 else 1852 { 1853 return false; 1854 } 1855 1856 return (retVal); 1857 } 1858 1859 bool 1860 PVA_FF_Mpeg4File::renderTruncatedFile(PVA_FF_UNICODE_STRING_PARAM filename) 1861 { 1862 MP4_AUTHOR_FF_FILE_IO_WRAP fp; 1863 1864 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 1865 1866 PVA_FF_AtomUtils::openFile(&fp, filename, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY); 1867 1868 if (fp._filePtr == NULL) 1869 { 1870 return false; 1871 } 1872 /* 1873 * Setting the major brand in ftyp atom 1874 */ 1875 1876 if (_o3GPPTrack) 1877 { 1878 setMajorBrand(BRAND_3GPP4); 1879 setMajorBrandVersion(VERSION_3GPP4); 1880 } 1881 else if (_oMPEGTrack) 1882 { 1883 setMajorBrand(BRAND_MPEG4); 1884 setMajorBrandVersion(VERSION_MPEG4); 1885 } 1886 else if (_oPVMMTrack) 1887 { 1888 setMajorBrand(PVMM_BRAND); 1889 setMajorBrandVersion(PVMM_VERSION); 1890 } 1891 1892 /* 1893 * Add compatible brands 1894 */ 1895 if (_o3GPPTrack) 1896 { 1897 addCompatibleBrand(BRAND_3GPP4); 1898 } 1899 if (_oPVMMTrack) 1900 { 1901 addCompatibleBrand(PVMM_BRAND); 1902 } 1903 if (_oMPEGTrack) 1904 { 1905 addCompatibleBrand(BRAND_MPEG4); 1906 } 1907 addCompatibleBrand(BRAND_3GPP5); 1908 1909 if ((_o3GPPTrack == true) || (_oPVMMTrack == true) || (_oMPEGTrack == true)) 1910 { 1911 _pFileTypeAtom->renderToFileStream(&fp); 1912 } 1913 { 1914 populateUserDataAtom(); 1915 _puserDataAtom->renderToFileStream(&fp); 1916 } 1917 _oFileRenderCalled = true; 1918 1919 PVA_FF_AtomUtils::closeFile(&fp); 1920 1921 return true; 1922 } 1923 1924 uint32 1925 PVA_FF_Mpeg4File::convertCreationTime(PVA_FF_UNICODE_STRING_PARAM creationDate) 1926 { 1927 uint32 numSecs = 0; 1928 1929 uint32 numDaysInMonth[12] = 1930 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1931 1932 uint32 numDaysInLeapFeb = 29; 1933 uint32 refYear = 1904; 1934 1935 // (365*4 + 1) * 24 * 3600 1936 uint32 numSecsInABlkofFourYears = 126230400; 1937 1938 OSCL_TCHAR *date_ptr = (OSCL_TCHAR *)(creationDate.get_cstr()); 1939 1940 uint32 index = 0; 1941 uint32 currYear = 0; 1942 uint32 month = 0; 1943 uint32 day = 0; 1944 uint32 hour = 0; 1945 uint32 minutes = 0; 1946 uint32 seconds = 0; 1947 1948 bool nextChar = (date_ptr[index] == 0) ? false : true; 1949 1950 char *c = (char *)(oscl_malloc(5 * sizeof(char))); 1951 1952 uint8 s = 0; 1953 oscl_memset(c, 0, 5); 1954 1955 while (nextChar && (index < 4)) 1956 { 1957 c[s++] = (char)(date_ptr[index]); 1958 1959 index++; 1960 1961 nextChar = (date_ptr[index] == 0) ? false : true; 1962 } 1963 1964 PV_atoi(c, 'd', currYear); 1965 1966 if (currYear < refYear) 1967 { 1968 oscl_free(c); 1969 return 0; 1970 } 1971 1972 if (index != 4) 1973 { 1974 oscl_free(c); 1975 return 0; 1976 } 1977 1978 s = 0; 1979 oscl_memset(c, 0, 5); 1980 1981 while (nextChar && (index < 6)) 1982 { 1983 c[s++] = (char)(date_ptr[index]); 1984 1985 index++; 1986 1987 nextChar = (date_ptr[index] == 0) ? false : true; 1988 } 1989 1990 PV_atoi(c, 'd', month); 1991 1992 if (index != 6) 1993 { 1994 oscl_free(c); 1995 return 0; 1996 } 1997 1998 s = 0; 1999 oscl_memset(c, 0, 5); 2000 2001 while (nextChar && (index < 8)) 2002 { 2003 c[s++] = (char)(date_ptr[index]); 2004 2005 index++; 2006 2007 nextChar = (date_ptr[index] == 0) ? false : true; 2008 } 2009 2010 PV_atoi(c, 'd', day); 2011 2012 if (index != 8) 2013 { 2014 oscl_free(c); 2015 return 0; 2016 } 2017 2018 char val = (char)(date_ptr[index]); 2019 2020 if (val != 'T') 2021 { 2022 oscl_free(c); 2023 return 0; 2024 } 2025 else 2026 { 2027 index++; 2028 } 2029 2030 s = 0; 2031 oscl_memset(c, 0, 5); 2032 2033 while (nextChar && (index < 11)) 2034 { 2035 c[s++] = (char)(date_ptr[index]); 2036 2037 index++; 2038 2039 nextChar = (date_ptr[index] == 0) ? false : true; 2040 } 2041 2042 PV_atoi(c, 'd', hour); 2043 2044 if (index != 11) 2045 { 2046 oscl_free(c); 2047 return 0; 2048 } 2049 2050 s = 0; 2051 oscl_memset(c, 0, 5); 2052 2053 while (nextChar && (index < 13)) 2054 { 2055 c[s++] = (char)(date_ptr[index]); 2056 2057 index++; 2058 2059 nextChar = (date_ptr[index] == 0) ? false : true; 2060 } 2061 2062 PV_atoi(c, 'd', minutes); 2063 2064 if (index != 13) 2065 { 2066 oscl_free(c); 2067 return 0; 2068 } 2069 2070 s = 0; 2071 oscl_memset(c, 0, 5); 2072 2073 while (nextChar && (index < 15)) 2074 { 2075 c[s++] = (char)(date_ptr[index]); 2076 2077 index++; 2078 2079 nextChar = (date_ptr[index] == 0) ? false : true; 2080 } 2081 2082 PV_atoi(c, 'd', seconds); 2083 2084 uint32 deltaYears = currYear - refYear; 2085 2086 uint32 numBlks = (deltaYears / 4); 2087 2088 uint32 numLeftOverYears = (deltaYears - (numBlks * 4)); 2089 2090 numSecs = (numBlks * numSecsInABlkofFourYears); 2091 2092 uint32 numDays = 0; 2093 2094 if (numLeftOverYears > 1) 2095 { 2096 // Acct for leap year 2097 numDays = ((numLeftOverYears * 365) + 1); 2098 2099 for (uint32 i = 0; i < month; i++) 2100 { 2101 numDays += numDaysInMonth[i]; 2102 } 2103 2104 numDays += day; 2105 2106 uint32 numHours = (numDays * 24); 2107 2108 numHours += hour; 2109 2110 uint32 numMins = (numHours * 60); 2111 2112 numMins += minutes; 2113 2114 numSecs += ((numMins * 60) + seconds); 2115 } 2116 else 2117 { 2118 for (uint32 i = 0; i < month; i++) 2119 { 2120 if (i != 1) 2121 numDays += numDaysInMonth[i]; 2122 else 2123 numDays += numDaysInLeapFeb; 2124 } 2125 2126 numDays += day; 2127 2128 uint32 numHours = (numDays * 24); 2129 2130 numHours += hour; 2131 2132 uint32 numMins = (numHours * 60); 2133 2134 numMins += minutes; 2135 2136 numSecs += ((numMins * 60) + seconds); 2137 } 2138 2139 oscl_free(c); 2140 2141 return (numSecs); 2142 } 2143 2144 bool 2145 PVA_FF_Mpeg4File::checkInterLeaveDuration(uint32 trackID, uint32 ts) 2146 { 2147 // get the interleave buffer for the track 2148 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 2149 2150 PVA_FF_TrackAtom* mediaTrack = _pmovieAtom->getMediaTrack(trackID); 2151 2152 uint32 lastChunkEndTime = pInterLeaveBuffer->getLastChunkEndTime(); 2153 2154 uint32 timescale = mediaTrack->getMediaTimeScale(); 2155 2156 uint32 interLeaveDurationInTrackTimeScale = 2157 (uint32)((_interLeaveDuration) * (timescale / 1000.0f)); 2158 2159 if ((ts - lastChunkEndTime) >= interLeaveDurationInTrackTimeScale) 2160 { 2161 pInterLeaveBuffer->setLastChunkEndTime(ts); 2162 return true; 2163 } 2164 2165 return false; 2166 } 2167 2168 bool 2169 PVA_FF_Mpeg4File::flushInterLeaveBuffer(uint32 trackID) 2170 { 2171 uint32 mediaType; 2172 int32 codecType; 2173 2174 2175 PVA_FF_TrackAtom* mediaTrack = _pmovieAtom->getMediaTrack(trackID); 2176 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 2177 if ((NULL == mediaTrack) || (NULL == pInterLeaveBuffer)) 2178 { 2179 // Returning true here might sound strange, however this is a valid case 2180 // where by tracks like odsm or sdsm might not have a valid mediaTrack 2181 // However if false is returned here, the function renderToFile will 2182 // break the for loops and return back. 2183 return true; 2184 } 2185 if (!(_oMovieFragmentEnabled && _oComposeMoofAtom)) 2186 { 2187 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 2188 2189 mediaType = mediaTrack->getMediaType(); 2190 codecType = _pmovieAtom->getCodecType(trackID); 2191 2192 _oChunkStart = true; 2193 2194 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = pInterLeaveBuffer->getTimeStampVec(); 2195 2196 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = pInterLeaveBuffer->getSampleSizeVec(); 2197 2198 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = pInterLeaveBuffer->getFlagsVec(); 2199 2200 Oscl_Vector<int32, OsclMemAllocator> *indexVec = NULL; 2201 2202 if (mediaType == MEDIA_TYPE_TEXT && codecType == CODEC_TYPE_TIMED_TEXT) 2203 { 2204 indexVec = pInterLeaveBuffer->getTextIndexVec(); 2205 } 2206 2207 int32 numBufferedSamples = tsVec->size(); 2208 2209 if (numBufferedSamples > 0) 2210 { 2211 for (int32 i = 0; i < numBufferedSamples; i++) 2212 { 2213 if (mediaType == MEDIA_TYPE_TEXT && codecType == CODEC_TYPE_TIMED_TEXT) 2214 { 2215 uint32 sampleTS = (*tsVec)[i]; 2216 uint32 sampleSize = (*sizeVec)[i]; 2217 uint8 sampleFlag = (*flagsVec)[i]; 2218 int32 sampleIndex = (*indexVec)[i]; 2219 2220 // Add to moov atom (in turn adds to tracks) 2221 _pmovieAtom->addTextSampleToTrack(trackID, 2222 NULL, 2223 sampleSize, 2224 sampleTS, 2225 sampleFlag, 2226 sampleIndex, 2227 _baseOffset, 2228 _oChunkStart); 2229 2230 } 2231 else 2232 { 2233 uint32 sampleTS = (*tsVec)[i]; 2234 uint32 sampleSize = (*sizeVec)[i]; 2235 uint8 sampleFlag = (*flagsVec)[i]; 2236 2237 // Add to moov atom (in turn adds to tracks) 2238 _pmovieAtom->addSampleToTrack(trackID, 2239 NULL, 2240 sampleSize, 2241 sampleTS, 2242 sampleFlag, 2243 _baseOffset, 2244 _oChunkStart); 2245 } 2246 2247 2248 _oChunkStart = false; 2249 } 2250 2251 //Render chunk 2252 uint32 chunkSize = 0; 2253 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize); 2254 2255 if (!mdatAtom->addRawSample(ptr, chunkSize)) 2256 { 2257 return false; 2258 } 2259 _baseOffset += chunkSize; 2260 } 2261 } 2262 else 2263 { 2264 // add remaining samples as last TRUN in current track fragment 2265 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment; 2266 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID); 2267 2268 // Set trun end time to the last sample TS 2269 // in the interleave buffer 2270 2271 _oTrunStart = true; 2272 2273 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = pInterLeaveBuffer->getTimeStampVec(); 2274 2275 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = pInterLeaveBuffer->getSampleSizeVec(); 2276 2277 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = pInterLeaveBuffer->getFlagsVec(); 2278 2279 int32 numBufferedSamples = tsVec->size(); 2280 2281 int32 ii = 0; 2282 2283 for (ii = 0; ii < numBufferedSamples; ii++) 2284 { 2285 uint32 sampleTS = (*tsVec)[ii]; 2286 uint32 sampleSize = (*sizeVec)[ii]; 2287 uint8 sampleFlag = (*flagsVec)[ii]; 2288 uint32 mediaType = mediaTrack->getMediaType(); 2289 2290 // Add to moof atom (in turn adds to tracks) 2291 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS, 2292 sampleFlag, 2293 _baseOffset, // update data offset for each new trun 2294 _oTrunStart); // determine to add new trun or not 2295 2296 // update movie duration in MVEX atom 2297 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS); 2298 2299 if (mediaType == MEDIA_TYPE_VISUAL) 2300 { 2301 // make entry for every sync sample 2302 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03); 2303 if (codingType == CODING_TYPE_I) 2304 { 2305 // add video key frame as random sample entry 2306 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2307 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2308 pCurrentTrackFragment->getTrunNumber(), 2309 (ii + 1)); 2310 } 2311 } 2312 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true) 2313 { 2314 // add first audio sample in each TRUN as random sample entry 2315 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2316 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2317 pCurrentTrackFragment->getTrunNumber(), 2318 (ii + 1)); 2319 2320 } 2321 2322 _oTrunStart = false; 2323 } 2324 2325 // update the last TS entry only if there is 1 sample in buffer 2326 2327 if (numBufferedSamples == 1) 2328 { 2329 uint32 lastSampleTS = pInterLeaveBuffer->getLastSampleTS(); 2330 uint32 ts = pInterLeaveBuffer->getLastChunkEndTime(); 2331 pCurrentTrackFragment->updateLastTSEntry(ts + (ts - lastSampleTS)); 2332 _pmovieAtom->updateMovieFragmentDuration(trackID, ts + (ts - lastSampleTS)); 2333 } 2334 // make entry for last sample same as duration of second to last sample 2335 else 2336 { 2337 if (tsVec->size() > 1) 2338 { 2339 uint32 delta = (*tsVec)[ii -1] - (*tsVec)[ii -2]; 2340 uint32 ts = (*tsVec)[ii -1]; 2341 pCurrentTrackFragment->updateLastTSEntry(ts + delta); 2342 _pmovieAtom->updateMovieFragmentDuration(trackID, ts + delta); 2343 } 2344 } 2345 2346 2347 if (numBufferedSamples > 0) 2348 { 2349 //Render chunk 2350 uint32 trunSize = 0; 2351 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize); 2352 2353 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize)) 2354 { 2355 return false; 2356 } 2357 _baseOffset += trunSize; 2358 } 2359 } 2360 2361 return true; 2362 } 2363 2364 bool 2365 PVA_FF_Mpeg4File::getTargetFileSize(uint32 &metaDataSize, uint32 &mediaDataSize) 2366 { 2367 metaDataSize = 0; 2368 mediaDataSize = 0; 2369 2370 for (uint32 k = 0; k < _pmediaDataAtomVec->size(); k++) 2371 { 2372 mediaDataSize += (*_pmediaDataAtomVec)[k]->getMediaDataSize(); 2373 2374 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 2375 (*_pmediaDataAtomVec)[k]->getTrackReferencePtrVec(); 2376 2377 if (trefVec != NULL) 2378 { 2379 for (uint32 trefVecIndex = 0; 2380 trefVecIndex < trefVec->size(); 2381 trefVecIndex++) 2382 { 2383 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 2384 2385 /* 2386 * Account for media data that is remaining in the interleave 2387 * buffers 2388 */ 2389 if (_oInterLeaveEnabled) 2390 { 2391 uint32 trackID = pTrack->getTrackID(); 2392 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 2393 if (pInterLeaveBuffer) 2394 { 2395 uint32 currInterLeaveBufferSize = pInterLeaveBuffer->getCurrentInterLeaveBufferSize(); 2396 2397 mediaDataSize += currInterLeaveBufferSize; 2398 } 2399 } 2400 } 2401 } 2402 } 2403 2404 2405 if (_pFileTypeAtom != NULL) 2406 { 2407 metaDataSize += _pFileTypeAtom->getSize(); 2408 } 2409 2410 if (_pmovieAtom != NULL) 2411 { 2412 metaDataSize += _pmovieAtom->getSize(); 2413 } 2414 2415 metaDataSize += 1024; //Gaurd Band 2416 2417 return true; 2418 } 2419 2420 bool 2421 PVA_FF_Mpeg4File::prepareToEncode() 2422 { 2423 if (_oInterLeaveEnabled) 2424 { 2425 if (!_totalTempFileRemoval) 2426 { 2427 return true; 2428 } 2429 } 2430 2431 /* 2432 * Setting the major brand in ftyp atom 2433 */ 2434 if (_o3GPPTrack) 2435 { 2436 if (_oMovieFragmentEnabled) 2437 { 2438 setMajorBrand(BRAND_3GPP6); 2439 setMajorBrandVersion(VERSION_3GPP6); 2440 } 2441 else 2442 { 2443 setMajorBrand(BRAND_3GPP4); 2444 setMajorBrandVersion(VERSION_3GPP4); 2445 } 2446 } 2447 else if (_oMPEGTrack) 2448 { 2449 setMajorBrand(BRAND_MPEG4); 2450 setMajorBrandVersion(VERSION_MPEG4); 2451 } 2452 else if (_oPVMMTrack) 2453 { 2454 setMajorBrand(PVMM_BRAND); 2455 setMajorBrandVersion(PVMM_VERSION); 2456 } 2457 2458 /* 2459 * Add compatible brands 2460 */ 2461 if (_o3GPPTrack) 2462 { 2463 if (_oMovieFragmentEnabled) 2464 addCompatibleBrand(BRAND_3GPP6); 2465 else 2466 addCompatibleBrand(BRAND_3GPP4); 2467 } 2468 if (_oPVMMTrack) 2469 { 2470 addCompatibleBrand(PVMM_BRAND); 2471 } 2472 if (_oMPEGTrack) 2473 { 2474 addCompatibleBrand(BRAND_MPEG4); 2475 } 2476 2477 if (!_oMovieFragmentEnabled) 2478 { 2479 addCompatibleBrand(BRAND_3GPP6); 2480 } 2481 2482 _initialUserDataSize += _pFileTypeAtom->getSize(); 2483 2484 _oFtypPopulated = true; 2485 2486 if (_oDirectRenderEnabled) 2487 { 2488 if ((_oSetTitleDone == false) || 2489 (_oSetAuthorDone == false) || 2490 (_oSetCopyrightDone == false) || 2491 (_oSetDescriptionDone == false) || 2492 (_oSetRatingDone == false) || 2493 (_pmediaDataAtomVec->size() == 0)) 2494 { 2495 // Requirements for this API not met 2496 return false; 2497 } 2498 2499 /* 2500 * If VOL Header had not been set, use the pre defined 2501 * value. 2502 */ 2503 for (uint32 j = 0; j < _pmediaDataAtomVec->size(); j++) 2504 { 2505 PVA_FF_TrackAtom *pTrack = 2506 (PVA_FF_TrackAtom *)((*_pmediaDataAtomVec)[j]->getTrackReferencePtr()); 2507 2508 uint32 codecType = pTrack->getCodecType(); 2509 // uint32 trackID = pTrack->getTrackID(); 2510 uint32 mediaType = pTrack->getMediaType(); 2511 2512 if (mediaType == MEDIA_TYPE_VISUAL) 2513 { 2514 if (codecType == CODEC_TYPE_MPEG4_VIDEO) 2515 { 2516 if (!pTrack->IsDecoderSpecificInfoSet()) 2517 { 2518 _initialUserDataSize += 2519 MAX_PV_BASE_SIMPLE_PROFILE_VOL_HEADER_SIZE; 2520 } 2521 } 2522 } 2523 } 2524 { 2525 populateUserDataAtom(); 2526 _initialUserDataSize += _puserDataAtom->getSize(); 2527 } 2528 } 2529 2530 bool targetRender = false; 2531 2532 for (uint32 j = 0; j < _pmediaDataAtomVec->size(); j++) 2533 { 2534 bool tempVal = ((*_pmediaDataAtomVec)[j]->IsTargetRender()); 2535 2536 if (tempVal) 2537 { 2538 if (targetRender) 2539 { 2540 //Only one track is allowed to be rendered directly onto the target 2541 //file 2542 return false; 2543 } 2544 else 2545 { 2546 targetRender = true; 2547 ((*_pmediaDataAtomVec)[j]->prepareTargetFile(_initialUserDataSize)); 2548 } 2549 } 2550 } 2551 2552 return true; 2553 } 2554 2555 void 2556 PVA_FF_Mpeg4File::populateUserDataAtom() 2557 { 2558 _oUserDataPopulated = true; 2559 } 2560 2561 bool 2562 PVA_FF_Mpeg4File::addMediaSampleInterleave(uint32 trackID, 2563 Oscl_Vector < OsclMemoryFragment, 2564 OsclMemAllocator > & fragmentList, 2565 uint32 size, uint32 ts, uint8 flags) 2566 { 2567 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID); 2568 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 2569 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 2570 int32 codecType = _pmovieAtom->getCodecType(trackID); 2571 uint32 mediaType = mediaTrack->getMediaType(); 2572 int32 index = 0; 2573 if (true == _oComposeMoofAtom) 2574 _pmovieAtom->SetMaxSampleSize(trackID, size); 2575 if (_oFirstSampleEditMode) 2576 { 2577 _oChunkStart = true; 2578 /* 2579 * In this mode very first sample in each track is authored 2580 * in a separate chunk. It is easier to go back and edit the 2581 * sample meta data if we authored it in a seperate chunk by 2582 * itself. 2583 */ 2584 if (mediaTrack->IsFirstSample()) 2585 { 2586 // Add to moov atom (in turn adds to tracks) 2587 _pmovieAtom->addSampleToTrack(trackID, 2588 fragmentList, 2589 size, 2590 ts, 2591 flags, 2592 _baseOffset, 2593 _oChunkStart); 2594 _oChunkStart = false; 2595 2596 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType)) 2597 { 2598 return false; 2599 } 2600 _baseOffset += size; 2601 return true; 2602 } 2603 } 2604 2605 /* Movie Fragment : check if fragment duration reached for MOOV atom. If yes, allocate new 2606 movie fragment (MOOF) and write data in new media data atom. 2607 */ 2608 if (_oMovieFragmentEnabled == true && _oComposeMoofAtom == false) 2609 { 2610 uint32 duration = _pmovieAtom->getDuration(); 2611 uint32 duration_msec = (uint)((((float)duration / _pmovieAtom->getTimeScale()) * 1000.0f)); 2612 2613 if (duration_msec >= _movieFragmentDuration) 2614 { 2615 // render MOOV and MDAT atoms 2616 renderMoovAtom(); 2617 2618 _oComposeMoofAtom = true; 2619 2620 // allocate Moof movie fragments 2621 PVA_FF_MovieFragmentAtom *pMoofAtom; 2622 _sequenceNumber++; 2623 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentAtom, (_sequenceNumber, 2624 _movieFragmentDuration, 2625 _interLeaveDuration), 2626 pMoofAtom); 2627 2628 _pCurrentMoofAtom = pMoofAtom; 2629 2630 // set Movie fragment duration 2631 _pmovieAtom->setMovieFragmentDuration(); 2632 2633 // add track fragments 2634 for (uint32 kk = 0; kk < _pmediaDataAtomVec->size(); kk++) 2635 { 2636 // add track fragments from MDAT with interleaved data 2637 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender()) 2638 { 2639 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 2640 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec(); 2641 2642 if (trefVec != NULL) 2643 { 2644 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++) 2645 { 2646 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 2647 2648 _pCurrentMoofAtom->addTrackFragment(pTrack->getMediaType(), 2649 pTrack->getCodecType(), 2650 pTrack->getTrackID(), 2651 pTrack->getMediaTimeScale()); 2652 2653 // add random access atom for each track 2654 _pMfraAtom->addTrackFragmentRandomAccessAtom(pTrack->getTrackID()); 2655 } 2656 } 2657 } 2658 } 2659 2660 // form new MDAT atom 2661 PVA_FF_MediaDataAtom *pMdatAtom = NULL; 2662 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), pMdatAtom); 2663 2664 _pCurrentMediaDataAtom = pMdatAtom; 2665 2666 // current moof offset set at start of mdat, (later updated by size of mdat atom) 2667 _currentMoofOffset = _baseOffset; 2668 2669 // base offset set to start of mdat (after fourcc code) as base data offset 2670 _baseOffset += _pCurrentMediaDataAtom->prepareTargetFileForFragments(_directRenderFileOffset); 2671 2672 } 2673 2674 } 2675 2676 if (_oMovieFragmentEnabled == false || _oComposeMoofAtom == false) 2677 { 2678 2679 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size)) 2680 { 2681 // Set Chunk end time to the last sample TS 2682 // in the interleave buffer 2683 pInterLeaveBuffer->setLastChunkEndTime(ts); 2684 2685 _oChunkStart = true; 2686 2687 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 2688 pInterLeaveBuffer->getTimeStampVec(); 2689 2690 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 2691 pInterLeaveBuffer->getSampleSizeVec(); 2692 2693 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 2694 pInterLeaveBuffer->getFlagsVec(); 2695 2696 int32 numBufferedSamples = tsVec->size(); 2697 2698 for (int32 ii = 0; ii < numBufferedSamples; ii++) 2699 { 2700 uint32 sampleTS = (*tsVec)[ii]; 2701 uint32 sampleSize = (*sizeVec)[ii]; 2702 uint8 sampleFlag = (*flagsVec)[ii]; 2703 2704 // Add to moov atom (in turn adds to tracks) 2705 _pmovieAtom->addSampleToTrack(trackID, 2706 fragmentList, 2707 sampleSize, 2708 sampleTS, 2709 sampleFlag, 2710 _baseOffset, 2711 _oChunkStart); 2712 2713 _oChunkStart = false; 2714 } 2715 2716 if (numBufferedSamples > 0) 2717 { 2718 //Render chunk 2719 uint32 chunkSize = 0; 2720 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize); 2721 2722 if (!mdatAtom->addRawSample(ptr, chunkSize)) 2723 { 2724 return false; 2725 } 2726 _baseOffset += chunkSize; 2727 } 2728 2729 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, 2730 size, ts, flags, index))) 2731 { 2732 return false; 2733 } 2734 } 2735 else 2736 { 2737 if (checkInterLeaveDuration(trackID, ts)) 2738 { 2739 _oChunkStart = true; 2740 2741 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 2742 pInterLeaveBuffer->getTimeStampVec(); 2743 2744 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 2745 pInterLeaveBuffer->getSampleSizeVec(); 2746 2747 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 2748 pInterLeaveBuffer->getFlagsVec(); 2749 2750 int32 numBufferedSamples = tsVec->size(); 2751 2752 for (int32 ii = 0; ii < numBufferedSamples; ii++) 2753 { 2754 uint32 sampleTS = (*tsVec)[ii]; 2755 uint32 sampleSize = (*sizeVec)[ii]; 2756 uint8 sampleFlag = (*flagsVec)[ii]; 2757 2758 // Add to moov atom (in turn adds to tracks) 2759 _pmovieAtom->addSampleToTrack(trackID, 2760 fragmentList, 2761 sampleSize, 2762 sampleTS, 2763 sampleFlag, 2764 _baseOffset, 2765 _oChunkStart); 2766 2767 _oChunkStart = false; 2768 } 2769 2770 if (numBufferedSamples > 0) 2771 { 2772 //Render chunk 2773 uint32 chunkSize = 0; 2774 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize); 2775 2776 if (!mdatAtom->addRawSample(ptr, chunkSize)) 2777 { 2778 return false; 2779 } 2780 _baseOffset += chunkSize; 2781 } 2782 } 2783 else 2784 { 2785 _oChunkStart = false; 2786 } 2787 2788 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, 2789 size, ts, flags, index))) 2790 { 2791 return false; 2792 } 2793 } 2794 } 2795 else 2796 { 2797 // add data in movie fragment 2798 uint32 trackFragmentDuration = _pCurrentMoofAtom->getTrackFragmentDuration(trackID); 2799 2800 // check if Movie Fragment duration is reached for current fragment 2801 if (trackFragmentDuration < _movieFragmentDuration) 2802 { 2803 // add fragment to the current track fragment 2804 2805 //check for interleaving in current track fragment 2806 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment; 2807 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID); 2808 2809 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size)) 2810 { 2811 // Set trun end time to the last sample TS 2812 // in the interleave buffer 2813 pInterLeaveBuffer->setLastChunkEndTime(ts); 2814 2815 _oTrunStart = true; 2816 2817 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 2818 pInterLeaveBuffer->getTimeStampVec(); 2819 2820 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 2821 pInterLeaveBuffer->getSampleSizeVec(); 2822 2823 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 2824 pInterLeaveBuffer->getFlagsVec(); 2825 2826 int32 numBufferedSamples = tsVec->size(); 2827 2828 2829 for (int32 ii = 0; ii < numBufferedSamples; ii++) 2830 { 2831 uint32 sampleTS = (*tsVec)[ii]; 2832 uint32 sampleSize = (*sizeVec)[ii]; 2833 uint8 sampleFlag = (*flagsVec)[ii]; 2834 2835 // Add to moof atom (in turn adds to tracks) 2836 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS, 2837 sampleFlag, 2838 _baseOffset, // update data offset for each new trun 2839 _oTrunStart); // determine to add new trun or not 2840 2841 // update movie duration in MVEX atom 2842 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS); 2843 2844 if (mediaType == MEDIA_TYPE_VISUAL) 2845 { 2846 // make entry for every sync sample 2847 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03); 2848 if (codingType == CODING_TYPE_I) 2849 { 2850 // add video key frame as random sample entry 2851 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2852 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2853 pCurrentTrackFragment->getTrunNumber(), 2854 (ii + 1)); 2855 } 2856 } 2857 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true) 2858 { 2859 // add first audio sample in each TRUN as random sample entry 2860 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2861 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2862 pCurrentTrackFragment->getTrunNumber(), 2863 (ii + 1)); 2864 2865 } 2866 2867 _oTrunStart = false; 2868 } 2869 2870 pCurrentTrackFragment->updateLastTSEntry(ts); 2871 2872 if (numBufferedSamples > 0) 2873 { 2874 //Render chunk 2875 uint32 trunSize = 0; 2876 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize); 2877 2878 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize)) 2879 { 2880 return false; 2881 } 2882 _baseOffset += trunSize; 2883 } 2884 2885 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, ts, flags, index))) 2886 { 2887 return false; 2888 } 2889 } 2890 else 2891 { 2892 if (checkInterLeaveDuration(trackID, ts)) 2893 { 2894 _oTrunStart = true; 2895 2896 2897 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 2898 pInterLeaveBuffer->getTimeStampVec(); 2899 2900 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 2901 pInterLeaveBuffer->getSampleSizeVec(); 2902 2903 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 2904 pInterLeaveBuffer->getFlagsVec(); 2905 2906 int32 numBufferedSamples = tsVec->size(); 2907 2908 for (int32 ii = 0; ii < numBufferedSamples; ii++) 2909 { 2910 uint32 sampleTS = (*tsVec)[ii]; 2911 uint32 sampleSize = (*sizeVec)[ii]; 2912 uint8 sampleFlag = (*flagsVec)[ii]; 2913 2914 // update movie duration in MVEX atom 2915 _pmovieAtom->updateMovieFragmentDuration(trackID, sampleTS); 2916 2917 // Add to moov atom (in turn adds to tracks) 2918 _pCurrentMoofAtom->addSampleToFragment(trackID, sampleSize, sampleTS, 2919 sampleFlag, 2920 _baseOffset, 2921 _oTrunStart); 2922 2923 if (mediaType == MEDIA_TYPE_VISUAL) 2924 { 2925 // make entry for every sync sample 2926 uint8 codingType = (uint8)((sampleFlag >> 2) & 0x03); 2927 if (codingType == CODING_TYPE_I) 2928 { 2929 // add video key frame as random sample entry 2930 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2931 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2932 pCurrentTrackFragment->getTrunNumber(), 2933 (ii + 1)); 2934 } 2935 } 2936 else if (mediaType == MEDIA_TYPE_AUDIO && _oTrunStart == true) 2937 { 2938 // add first audio sample in each TRUN as random sample entry 2939 _pMfraAtom->addSampleEntry(trackID, sampleTS, _currentMoofOffset, 2940 _pCurrentMoofAtom->getTrackFragmentNumber(trackID), 2941 pCurrentTrackFragment->getTrunNumber(), 2942 (ii + 1)); 2943 2944 } 2945 2946 2947 _oTrunStart = false; 2948 } 2949 2950 pCurrentTrackFragment->updateLastTSEntry(ts); 2951 2952 if (numBufferedSamples > 0) 2953 { 2954 //Render chunk 2955 uint32 trunSize = 0; 2956 uint8* ptr = pInterLeaveBuffer->resetInterLeaveBuffer(trunSize); 2957 2958 if (!_pCurrentMediaDataAtom->addRawSample(ptr, trunSize)) 2959 { 2960 return false; 2961 } 2962 _baseOffset += trunSize; 2963 } 2964 } 2965 else 2966 { 2967 _oTrunStart = false; 2968 } 2969 2970 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, 2971 ts, flags, index))) 2972 { 2973 return false; 2974 } 2975 } 2976 } 2977 else 2978 { 2979 2980 // add sample 2981 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, 2982 ts, flags, index))) 2983 { 2984 return false; 2985 } 2986 2987 uint32 kk = 0; 2988 2989 // update last sample TS entry 2990 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++) 2991 { 2992 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender()) 2993 { 2994 2995 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 2996 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec(); 2997 2998 if (trefVec != NULL) 2999 { 3000 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++) 3001 { 3002 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 3003 uint32 trackID = pTrack->getTrackID(); 3004 3005 PVA_FF_TrackFragmentAtom *pCurrentTrackFragment; 3006 pCurrentTrackFragment = _pCurrentMoofAtom->getTrackFragment(trackID); 3007 3008 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 3009 uint32 ts = pInterLeaveBuffer->getFirstTSEntry(); 3010 pCurrentTrackFragment->updateLastTSEntry(ts); 3011 } 3012 } 3013 } 3014 } 3015 3016 // close MDAT atom and render current fragment 3017 if (!renderMovieFragments()) 3018 { 3019 _fileWriteFailed = true; 3020 return false; 3021 } 3022 3023 // delete current moof atom 3024 PV_MP4_FF_DELETE(NULL, PVA_FF_MovieFragmentAtom, _pCurrentMoofAtom); 3025 3026 // allocate new fragment 3027 PVA_FF_MovieFragmentAtom *pMoofAtom; 3028 _sequenceNumber++; 3029 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MovieFragmentAtom, (_sequenceNumber, 3030 _movieFragmentDuration, 3031 _interLeaveDuration), 3032 pMoofAtom); 3033 _pCurrentMoofAtom = pMoofAtom; 3034 3035 // add track fragments 3036 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++) 3037 { 3038 if ((*_pmediaDataAtomVec)[kk]->IsTargetRender()) 3039 { 3040 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 3041 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec(); 3042 3043 if (trefVec != NULL) 3044 { 3045 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++) 3046 { 3047 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 3048 3049 _pCurrentMoofAtom->addTrackFragment(pTrack->getMediaType(), 3050 pTrack->getCodecType(), 3051 pTrack->getTrackID(), 3052 pTrack->getMediaTimeScale()); 3053 3054 } 3055 } 3056 } 3057 } 3058 3059 // delete current MDAT atom for movie fragment 3060 PV_MP4_FF_DELETE(NULL, PVA_FF_MediaDataAtom, _pCurrentMediaDataAtom); 3061 3062 // form new MDAT atom 3063 PVA_FF_MediaDataAtom *pMdatAtom = NULL; 3064 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_MediaDataAtom, (_targetFileHandle, _aFs, iCacheSize), pMdatAtom); 3065 3066 _pCurrentMediaDataAtom = pMdatAtom; 3067 3068 // current moof offset set at start of mdat, (later updated by size of mdat atom) 3069 _currentMoofOffset = _baseOffset; 3070 3071 // base offset set to start of mdat (after fourcc code) as base data offset 3072 _baseOffset += _pCurrentMediaDataAtom->prepareTargetFileForFragments(_directRenderFileOffset); 3073 3074 } 3075 3076 } 3077 return true; 3078 3079 } 3080 3081 bool 3082 PVA_FF_Mpeg4File::addTextMediaSampleInterleave(uint32 trackID, 3083 Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList, 3084 uint32 size, uint32 ts, uint8 flags, int32 index) 3085 { 3086 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID); 3087 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 3088 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 3089 int32 codecType = _pmovieAtom->getCodecType(trackID); 3090 uint32 mediaType = mediaTrack->getMediaType(); 3091 3092 if (_oFirstSampleEditMode) 3093 { 3094 _oChunkStart = true; 3095 /* 3096 * In this mode very first sample in each track is authored 3097 * in a separate chunk. It is easier to go back and edit the 3098 * sample meta data if we authored it in a seperate chunk by 3099 * itself. 3100 */ 3101 if (mediaTrack->IsFirstSample()) 3102 { 3103 // Add to moov atom (in turn adds to tracks) 3104 _pmovieAtom->addTextSampleToTrack(trackID, 3105 fragmentList, 3106 size, 3107 ts, 3108 flags, 3109 index, 3110 _baseOffset, 3111 _oChunkStart); 3112 _oChunkStart = false; 3113 3114 if (!mdatAtom->addRawSample(fragmentList, size, mediaType, codecType)) 3115 { 3116 return false; 3117 } 3118 _baseOffset += size; 3119 return true; 3120 } 3121 } 3122 3123 if (!pInterLeaveBuffer->checkInterLeaveBufferSpace(size)) 3124 { 3125 // Set Chunk end time to the last sample TS 3126 // in the interleave buffer 3127 pInterLeaveBuffer->setLastChunkEndTime(); 3128 3129 _oChunkStart = true; 3130 3131 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 3132 pInterLeaveBuffer->getTimeStampVec(); 3133 3134 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 3135 pInterLeaveBuffer->getSampleSizeVec(); 3136 3137 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 3138 pInterLeaveBuffer->getFlagsVec(); 3139 3140 Oscl_Vector<int32, OsclMemAllocator> *indexVec = 3141 pInterLeaveBuffer->getTextIndexVec(); 3142 3143 int32 numBufferedSamples = tsVec->size(); 3144 3145 for (int32 i = 0; i < numBufferedSamples; i++) 3146 { 3147 uint32 sampleTS = (*tsVec)[i]; 3148 uint32 sampleSize = (*sizeVec)[i]; 3149 uint8 sampleFlag = (*flagsVec)[i]; 3150 int32 sampleIndex = (*indexVec)[i]; 3151 3152 // Add to moov atom (in turn adds to tracks) 3153 _pmovieAtom->addTextSampleToTrack(trackID, 3154 fragmentList, 3155 sampleSize, 3156 sampleTS, 3157 sampleFlag, 3158 sampleIndex, 3159 _baseOffset, 3160 _oChunkStart); 3161 3162 _oChunkStart = false; 3163 } 3164 3165 if (numBufferedSamples > 0) 3166 { 3167 //Render chunk 3168 uint32 chunkSize = 0; 3169 uint8* ptr = 3170 pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize); 3171 3172 if (!mdatAtom->addRawSample(ptr, chunkSize)) 3173 { 3174 return false; 3175 } 3176 _baseOffset += chunkSize; 3177 } 3178 3179 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, 3180 size, ts, flags, index))) 3181 { 3182 return false; 3183 } 3184 } 3185 else 3186 { 3187 if (checkInterLeaveDuration(trackID, ts)) 3188 { 3189 _oChunkStart = true; 3190 3191 Oscl_Vector<uint32, OsclMemAllocator> *tsVec = 3192 pInterLeaveBuffer->getTimeStampVec(); 3193 3194 Oscl_Vector<uint32, OsclMemAllocator> *sizeVec = 3195 pInterLeaveBuffer->getSampleSizeVec(); 3196 3197 Oscl_Vector<uint8, OsclMemAllocator> *flagsVec = 3198 pInterLeaveBuffer->getFlagsVec(); 3199 3200 Oscl_Vector<int32, OsclMemAllocator> *indexVec = 3201 pInterLeaveBuffer->getTextIndexVec(); 3202 3203 int32 numBufferedSamples = tsVec->size(); 3204 3205 for (int32 i = 0; i < numBufferedSamples; i++) 3206 { 3207 uint32 sampleTS = (*tsVec)[i]; 3208 uint32 sampleSize = (*sizeVec)[i]; 3209 uint8 sampleFlag = (*flagsVec)[i]; 3210 int32 sampleIndex = (*indexVec)[i]; 3211 3212 // Add to moov atom (in turn adds to tracks) 3213 _pmovieAtom->addTextSampleToTrack(trackID, 3214 fragmentList, 3215 sampleSize, 3216 sampleTS, 3217 sampleFlag, 3218 sampleIndex, 3219 _baseOffset, 3220 _oChunkStart); 3221 3222 3223 3224 _oChunkStart = false; 3225 } 3226 3227 if (numBufferedSamples > 0) 3228 { 3229 //Render chunk 3230 uint32 chunkSize = 0; 3231 uint8* ptr = 3232 pInterLeaveBuffer->resetInterLeaveBuffer(chunkSize); 3233 3234 if (!mdatAtom->addRawSample(ptr, chunkSize)) 3235 { 3236 return false; 3237 } 3238 _baseOffset += chunkSize; 3239 } 3240 } 3241 else 3242 { 3243 _oChunkStart = false; 3244 } 3245 3246 if (!(pInterLeaveBuffer->addSampleToInterLeaveBuffer(fragmentList, size, ts, flags , index))) 3247 { 3248 return false; 3249 } 3250 } 3251 3252 return true; 3253 } 3254 3255 bool 3256 PVA_FF_Mpeg4File::reAuthorFirstSampleInTrack(uint32 trackID, 3257 uint8 *psample, 3258 uint32 size) 3259 { 3260 bool retVal = false; 3261 if (_oInterLeaveEnabled) 3262 { 3263 PVA_FF_TrackAtom *mediaTrack = _pmovieAtom->getMediaTrack(trackID); 3264 PVA_FF_MediaDataAtom *mdatAtom = getMediaDataAtomForTrack(trackID); 3265 3266 mediaTrack = _pmovieAtom->getMediaTrack(trackID); 3267 3268 // Add to moov atom (in turn adds to tracks) 3269 retVal = 3270 _pmovieAtom->reAuthorFirstSampleInTrack(trackID, 3271 size, 3272 _baseOffset); 3273 3274 if (!mdatAtom->addRawSample(psample, size)) 3275 { 3276 retVal = false; 3277 } 3278 else 3279 { 3280 _baseOffset += size; 3281 } 3282 } 3283 return retVal; 3284 } 3285 3286 3287 bool 3288 PVA_FF_Mpeg4File::renderMoovAtom() 3289 { 3290 MP4_AUTHOR_FF_FILE_IO_WRAP fp; 3291 fp._filePtr = NULL; 3292 fp._osclFileServerSession = NULL; 3293 3294 //make sure to flush the interleave buffers, be it to temp files 3295 //or to target files 3296 uint32 kk = 0; 3297 3298 for (kk = 0; kk < _pmediaDataAtomVec->size(); kk++) 3299 { 3300 Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> *trefVec = 3301 (*_pmediaDataAtomVec)[kk]->getTrackReferencePtrVec(); 3302 3303 if (trefVec != NULL) 3304 { 3305 for (uint32 trefVecIndex = 0; trefVecIndex < trefVec->size(); trefVecIndex++) 3306 { 3307 PVA_FF_TrackAtom* pTrack = (*trefVec)[trefVecIndex]; 3308 uint32 trackID = pTrack->getTrackID(); 3309 PVA_FF_InterLeaveBuffer *pInterLeaveBuffer = getInterLeaveBuffer(trackID); 3310 if (pInterLeaveBuffer != NULL) 3311 { 3312 uint32 ts = pInterLeaveBuffer->getFirstTSEntry(); 3313 pTrack->updateLastTSEntry(ts); 3314 } 3315 } 3316 } 3317 } 3318 3319 bool targetRender = false; 3320 _directRenderFileOffset = 0; 3321 3322 if ((_oDirectRenderEnabled) || (_totalTempFileRemoval)) 3323 { 3324 for (uint32 kk = 0; kk < _pmediaDataAtomVec->size(); kk++) 3325 { 3326 bool tempVal = ((*_pmediaDataAtomVec)[kk]->IsTargetRender()); 3327 3328 if (tempVal) 3329 { 3330 if (targetRender) 3331 { 3332 //Only one track is allowed to be rendered directly onto the target 3333 //file 3334 return false; 3335 } 3336 else 3337 { 3338 targetRender = true; 3339 3340 if (!((*_pmediaDataAtomVec)[kk]->closeTargetFile())) 3341 { 3342 return false; 3343 } 3344 3345 fp._filePtr = ((*_pmediaDataAtomVec)[kk]->getTargetFilePtr()); 3346 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 3347 3348 _directRenderFileOffset = 3349 ((*_pmediaDataAtomVec)[kk]->getTotalDataRenderedToTargetFileInDirectRenderMode()); 3350 } 3351 } 3352 } 3353 } 3354 3355 if (fp._filePtr == NULL) 3356 { 3357 return false; 3358 } 3359 3360 if (!renderToFileStream(&fp)) 3361 { 3362 return false; 3363 } 3364 _directRenderFileOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp); // hereafter movie fragments are written 3365 _baseOffset = _directRenderFileOffset; // base offset is used to set base data offset of Moof 3366 3367 3368 // store target file handle used to write further movie fragments 3369 _targetFileHandle = fp._filePtr; 3370 3371 return true; 3372 } 3373 3374 bool 3375 PVA_FF_Mpeg4File::renderMovieFragments() 3376 { 3377 uint32 size; 3378 3379 uint32 fileWriteOffset; 3380 3381 MP4_AUTHOR_FF_FILE_IO_WRAP fp; 3382 3383 fp._filePtr = _pCurrentMediaDataAtom->getTargetFilePtr(); 3384 fp._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _aFs); 3385 3386 fileWriteOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp); 3387 3388 _pCurrentMediaDataAtom->closeTargetFile(); 3389 3390 size = _pCurrentMediaDataAtom->getMediaDataSize(); 3391 3392 _pMfraAtom->updateMoofOffset(size); 3393 3394 PVA_FF_AtomUtils::seekFromStart(&fp, fileWriteOffset); 3395 3396 3397 if (!(_pCurrentMoofAtom->renderToFileStream(&fp))) 3398 { 3399 return false; 3400 } 3401 3402 _directRenderFileOffset = PVA_FF_AtomUtils::getCurrentFilePosition(&fp); // hereafter further movie fragments are written 3403 _baseOffset = _directRenderFileOffset; // base offset is used to set base data offset of Moof 3404 3405 return true; 3406 } 3407 3408 3409 void 3410 PVA_FF_Mpeg4File::addInterLeaveBuffer(PVA_FF_InterLeaveBuffer *pInterLeaveBuffer) 3411 { 3412 if (_oInterLeaveEnabled) 3413 { 3414 if (_modifiable) 3415 { 3416 _pInterLeaveBufferVec->push_back(pInterLeaveBuffer); 3417 } 3418 } 3419 } 3420 3421 3422 3423 PVA_FF_InterLeaveBuffer* 3424 PVA_FF_Mpeg4File::getInterLeaveBuffer(uint32 trackID) 3425 { 3426 if (_pInterLeaveBufferVec->size() > 0) 3427 { 3428 for (uint32 ii = 0; ii < _pInterLeaveBufferVec->size(); ii++) 3429 { 3430 if ((*_pInterLeaveBufferVec)[ii]->getTrackID() == trackID) 3431 return (*_pInterLeaveBufferVec)[ii]; 3432 } 3433 } 3434 return NULL; 3435 } 3436 3437 void 3438 PVA_FF_Mpeg4File::setAudioEncodeParams(uint32 trackId, 3439 PVMP4FFComposerAudioEncodeParams &audioParams) 3440 { 3441 PVA_FF_TrackAtom *trackAtom; 3442 trackAtom = _pmovieAtom->getMediaTrack(trackId); 3443 3444 if (trackAtom != NULL) 3445 trackAtom->setAudioEncodeParams(audioParams); 3446 3447 return; 3448 } 3449 3450 3451 3452 3453