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 This PVA_FF_MediaDataAtom Class contains the media data. This class can operate in 20 either one of two ways - 1. it can store all it's data in memory (such as 21 during the creation of PVA_FF_ObjectDescriptor streams), or 2. it can maintain all 22 it's data on disk (such as during the creation ofmedia streams - i.e. audio 23 and video). 24 25 Note that during reading in this atom from a file stream, the type fp forced 26 to MEDIA_DATA_ON_DISK thereby keeping all the object data in the physical 27 file. 28 */ 29 30 #define IMPLEMENT_MediaDataAtom 31 32 #include "mediadataatom.h" 33 #include "atomutils.h" 34 #include "a_atomdefs.h" 35 #include "oscl_byte_order.h" 36 #include "oscl_bin_stream.h" 37 38 #define TEMP_TO_TARGET_FILE_COPY_BLOCK_SIZE 1024 39 40 typedef Oscl_Vector<PVA_FF_Renderable*, OsclMemAllocator> PVA_FF_RenderableVecType; 41 typedef Oscl_Vector<PVA_FF_TrackAtom*, OsclMemAllocator> PVA_FF_TrackAtomVecType; 42 43 // Constructor 44 PVA_FF_MediaDataAtom::PVA_FF_MediaDataAtom(PVA_FF_UNICODE_STRING_PARAM outputPathString, 45 PVA_FF_UNICODE_STRING_PARAM postfixString, 46 int32 tempFileIndex, 47 int32 type, 48 void *osclFileServerSession, 49 uint32 aCacheSize) 50 : PVA_FF_Atom(MEDIA_DATA_ATOM) 51 { 52 _osclFileServerSession = osclFileServerSession; 53 54 _success = true; 55 _prenderables = NULL; 56 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_RenderableVecType, (), _prenderables); 57 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtomVecType, (), _ptrackReferencePtrVec); 58 59 // ADDED TO CHECK FOR ANY FILE WRITE FAILURES 60 _fileWriteError = false; 61 _targetFileWriteError = false; 62 _directRender = false; 63 _oIsFileOpen = false; 64 65 _fileSize = 0; 66 _fileOffsetForChunkStart = 0; 67 _fileOffsetForAtomStart = 0; 68 _type = type; 69 70 _pofstream._filePtr = NULL; 71 _ptrackReferencePtr = NULL; 72 _targetFileMediaStartOffset = 0; 73 _totalDataRenderedToTargetFile = 0; 74 75 _tempFilePostfix = postfixString; 76 77 _tempFilename = outputPathString; 78 79 _tempFileIndex = tempFileIndex; 80 81 recomputeSize(); 82 83 // Preparing the temp output file for rendering the atom data 84 if (_type == MEDIA_DATA_ON_DISK) 85 { 86 prepareTempFile(aCacheSize); 87 } 88 } 89 90 PVA_FF_MediaDataAtom::PVA_FF_MediaDataAtom(PVA_FF_UNICODE_STRING_PARAM targetFileName, 91 void *osclFileServerSession, uint32 aCacheSize) 92 : PVA_FF_Atom(MEDIA_DATA_ATOM) 93 { 94 _type = MEDIA_DATA_ON_DISK; 95 96 _osclFileServerSession = osclFileServerSession; 97 _targetFileMediaStartOffset = 0; 98 _totalDataRenderedToTargetFile = 0; 99 _prenderables = NULL; 100 _success = true; 101 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_RenderableVecType, (), _prenderables); 102 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtomVecType, (), _ptrackReferencePtrVec); 103 104 105 // ADDED TO CHECK FOR ANY FILE WRITE FAILURES 106 _fileWriteError = false; 107 _targetFileWriteError = false; 108 _fileSize = 0; 109 _fileOffsetForChunkStart = 0; 110 _fileOffsetForAtomStart = 0; 111 112 _directRender = true; 113 114 _ptrackReferencePtr = NULL; 115 116 recomputeSize(); 117 118 _pofstream._filePtr = NULL; 119 _pofstream._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _osclFileServerSession); 120 121 122 int retVal = PVA_FF_AtomUtils::openFile(&_pofstream, targetFileName, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, aCacheSize); 123 _oIsFileOpen = true; 124 125 if (_pofstream._filePtr == NULL) 126 { 127 _fileWriteError = true; 128 } 129 else if (retVal == 0) 130 { 131 _targetFileWriteError = true; 132 if (_pofstream._filePtr != NULL) 133 { 134 PVA_FF_AtomUtils::closeFile(&_pofstream); 135 _pofstream._filePtr = NULL; 136 } 137 } 138 } 139 140 PVA_FF_MediaDataAtom::PVA_FF_MediaDataAtom(MP4_AUTHOR_FF_FILE_HANDLE targetFileHandle, 141 void *osclFileServerSession, uint32 aCacheSize) 142 : PVA_FF_Atom(MEDIA_DATA_ATOM) 143 { 144 OSCL_UNUSED_ARG(aCacheSize); 145 _type = MEDIA_DATA_ON_DISK; 146 147 _osclFileServerSession = osclFileServerSession; 148 _targetFileMediaStartOffset = 0; 149 _totalDataRenderedToTargetFile = 0; 150 _prenderables = NULL; 151 152 _success = true; 153 // _ptrackReferencePtrVec = new Oscl_Vector<PVA_FF_TrackAtom*,OsclMemAllocator>(); 154 // _prenderables = new Oscl_Vector<PVA_FF_Renderable*,OsclMemAllocator>(); 155 156 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_RenderableVecType, (), _prenderables); 157 PV_MP4_FF_NEW(fp->auditCB, PVA_FF_TrackAtomVecType, (), _ptrackReferencePtrVec); 158 159 160 161 // ADDED TO CHECK FOR ANY FILE WRITE FAILURES 162 _fileWriteError = false; 163 _targetFileWriteError = false; 164 165 _fileSize = 0; 166 _fileOffsetForChunkStart = 0; 167 _fileOffsetForAtomStart = 0; 168 _oIsFileOpen = false; 169 _directRender = true; 170 171 _ptrackReferencePtr = NULL; 172 173 recomputeSize(); 174 175 _pofstream._filePtr = targetFileHandle; 176 177 if (_pofstream._filePtr == NULL) 178 { 179 _fileWriteError = true; 180 } 181 } 182 183 // Destructor 184 PVA_FF_MediaDataAtom::~PVA_FF_MediaDataAtom() 185 { 186 if (_pofstream._filePtr != NULL && true == _oIsFileOpen) 187 { 188 PVA_FF_AtomUtils::closeFile(&_pofstream); 189 _pofstream._filePtr = NULL; 190 } 191 192 // PVA_FF_TrackAtom *_ptrackReferencePtr - is taken care of by the movie atom 193 // Delete vector<PVA_FF_Renderable*> *_prenderables 194 if (_prenderables != NULL) 195 { 196 for (uint32 i = 0; i < _prenderables->size(); i++) 197 { 198 if ((*_prenderables)[i] != NULL) 199 { 200 OSCL_DELETE((*_prenderables)[i]); 201 //PV_MP4_FF_DELETE(NULL,PVA_FF_Renderable,(*_prenderables)[i]); 202 (*_prenderables)[i] = NULL; 203 } 204 } 205 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_RenderableVecType, Oscl_Vector, _prenderables); 206 _prenderables = NULL; 207 } 208 209 //Contents of this array are deleted in movie atom 210 //OSCL_DELETE(_ptrackReferencePtrVec); 211 212 PV_MP4_FF_TEMPLATED_DELETE(NULL, PVA_FF_TrackAtomVecType, Oscl_Vector, _ptrackReferencePtrVec); 213 214 Oscl_FileServer fileServ; 215 fileServ.Connect(); 216 fileServ.Oscl_DeleteFile(_tempFilename.get_cstr()); 217 fileServ.Close(); 218 } 219 220 // Create the atom temp file and the corresponding ofstream 221 void 222 PVA_FF_MediaDataAtom::prepareTempFile(uint32 aCacheSize) 223 { 224 if (_pofstream._filePtr == NULL && !_fileWriteError) 225 { 226 // 05/31/01 Generate temporary files into output path (the actual mp4 location) 227 // _tempFilename already contains the output path ("drive:\\...\\...\\") 228 // 229 _tempFilename += _STRLIT("temp"); 230 // Assign the rest of the temp filename - index plus suffix 231 _tempFilename += (uint16)(_tempFileIndex++); 232 233 // 03/21/01 Multiple instances support 234 _tempFilename += _STRLIT("_"); 235 _tempFilename += _tempFilePostfix; 236 // 237 238 _tempFilename += _STRLIT(".mdat"); 239 240 _pofstream._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _osclFileServerSession); 241 242 PVA_FF_AtomUtils::openFile(&_pofstream, _tempFilename, Oscl_File::MODE_READWRITE | Oscl_File::MODE_BINARY, aCacheSize); 243 244 if (_pofstream._filePtr == NULL) 245 { 246 _fileWriteError = true; 247 } 248 else 249 { 250 _oIsFileOpen = true; 251 } 252 253 // Render the atoms base members to the media data atom file 254 renderAtomBaseMembers(&_pofstream); 255 256 _fileOffsetForChunkStart = getDefaultSize(); 257 _fileSize = getDefaultSize(); 258 } 259 } 260 261 bool 262 PVA_FF_MediaDataAtom::prepareTargetFile(uint32 mediaStartOffset) 263 { 264 if (_directRender) 265 { 266 if ((_pofstream._filePtr != NULL) && (_fileWriteError != true)) 267 { 268 if (mediaStartOffset > 0) 269 { 270 // Write zeros to accomodate the user data upfront 271 uint8* tempBuffer = NULL; 272 PV_MP4_FF_ARRAY_NEW(NULL, uint8, mediaStartOffset, tempBuffer); 273 274 oscl_memset(tempBuffer, 0, mediaStartOffset); 275 276 if (!(PVA_FF_AtomUtils::renderByteData(&_pofstream, mediaStartOffset, tempBuffer))) 277 { 278 PV_MP4_ARRAY_DELETE(NULL, tempBuffer); 279 return false; 280 } 281 PV_MP4_ARRAY_DELETE(NULL, tempBuffer); 282 } 283 284 // Render the atoms base members to the media data atom file 285 renderAtomBaseMembers(&_pofstream); 286 287 _fileOffsetForChunkStart = getDefaultSize(); 288 _fileSize = getDefaultSize(); 289 290 _targetFileMediaStartOffset = mediaStartOffset; 291 292 return true; 293 } 294 } 295 return false; 296 } 297 298 299 uint32 300 PVA_FF_MediaDataAtom::prepareTargetFileForFragments(uint32 mediaStartOffset) 301 { 302 if (_directRender) 303 { 304 _targetFileMediaStartOffset = mediaStartOffset; 305 PVA_FF_AtomUtils::seekFromStart(&_pofstream, _targetFileMediaStartOffset); 306 307 renderAtomBaseMembers(&_pofstream); 308 _fileOffsetForChunkStart = getDefaultSize(); 309 310 _fileSize = getDefaultSize(); 311 312 return _fileOffsetForChunkStart; 313 } 314 315 return 0; 316 } 317 318 bool 319 PVA_FF_MediaDataAtom::closeTargetFile() 320 { 321 if (_directRender) 322 { 323 if ((_pofstream._filePtr != NULL) && (_fileWriteError != true)) 324 { 325 // Get current position of put pointer 326 _totalDataRenderedToTargetFile = 327 PVA_FF_AtomUtils::getCurrentFilePosition(&_pofstream); 328 329 // Go to the beginning of the media data 330 PVA_FF_AtomUtils::seekFromStart(&_pofstream, _targetFileMediaStartOffset); 331 332 // Update size field 333 if (!PVA_FF_AtomUtils::render32(&_pofstream, getSize())) 334 { 335 return false; 336 } 337 338 // Return the _pofstream's pointer to start 339 PVA_FF_AtomUtils::seekFromStart(&_pofstream, 0); 340 341 _fileOffsetForChunkStart = 342 _targetFileMediaStartOffset + getDefaultSize(); 343 344 return true; 345 } 346 } 347 return false; 348 } 349 350 Oscl_File* 351 PVA_FF_MediaDataAtom::getTargetFilePtr() 352 { 353 return (_pofstream._filePtr); 354 } 355 356 // Adds more data to the atom then update the atom size field (first 4 bytes) 357 bool 358 PVA_FF_MediaDataAtom::addRawSample(void *psample, uint32 length) 359 { 360 bool retVal = true; 361 362 if (_type == MEDIA_DATA_ON_DISK) 363 { 364 if (!_fileWriteError) 365 { 366 if (_pofstream._filePtr == NULL) 367 { 368 if (!_directRender) 369 { 370 // If initial file fp not opened 371 prepareTempFile(); 372 } 373 else 374 { 375 //File must have been prepared for direct render 376 return false; 377 } 378 } 379 380 bool ret = PVA_FF_AtomUtils::renderByteData(&_pofstream, length, (uint8 *)psample); 381 382 if (ret == false) 383 { 384 _fileWriteError = true; 385 retVal = false; 386 } 387 388 _fileSize += length; // Update the size of the atom 389 390 // Update the size of the atom 391 recomputeSize(); 392 } 393 else 394 { 395 retVal = false; 396 } 397 } 398 else 399 { 400 retVal = false; 401 } 402 403 return (retVal); 404 } 405 406 bool PVA_FF_MediaDataAtom::addRawSample(Oscl_Vector <OsclMemoryFragment, OsclMemAllocator>& fragmentList, 407 uint32 length, int32 mediaType, int32 codecType) 408 { 409 bool retVal = true; 410 bool ret = true; 411 uint32 ii = 0; 412 OsclBinIStreamBigEndian stream; 413 414 if (_type == MEDIA_DATA_ON_DISK) 415 { 416 if (!_fileWriteError) 417 { 418 if (_pofstream._filePtr == NULL) 419 { 420 if (!_directRender) 421 { 422 // If initial file fp not opened 423 prepareTempFile(); 424 } 425 else 426 { 427 //File must have been prepared for direct render 428 return false; 429 } 430 } 431 432 uint32 nalLength = 0; 433 if (mediaType == (int32)MEDIA_TYPE_VISUAL && codecType == CODEC_TYPE_AVC_VIDEO) 434 { 435 for (ii = 0; ii < fragmentList.size(); ii++) 436 { 437 // read NAL length in Big Endian format 438 stream.Attach((OsclAny*) &(fragmentList[ii].len), 4); 439 stream >> nalLength; 440 441 // compose nal length in two bytes 442 ret = PVA_FF_AtomUtils::renderByteData(&_pofstream, 4, (uint8 *) & nalLength); 443 if (ret == false) 444 { 445 _fileWriteError = true; 446 retVal = false; 447 } 448 449 // write NAL uint 450 ret = PVA_FF_AtomUtils::renderByteData(&_pofstream, fragmentList[ii].len, (uint8 *)fragmentList[ii].ptr); 451 if (ret == false) 452 { 453 _fileWriteError = true; 454 retVal = false; 455 } 456 } 457 } 458 else 459 { 460 for (ii = 0; ii < fragmentList.size(); ii++) 461 { 462 ret = PVA_FF_AtomUtils::renderByteData(&_pofstream, fragmentList[ii].len, (uint8 *)fragmentList[ii].ptr); 463 } 464 465 } 466 467 if (ret == false) 468 { 469 _fileWriteError = true; 470 retVal = false; 471 } 472 473 _fileSize += length; // Update the size of the atom 474 475 // Update the size of the atom 476 recomputeSize(); 477 } 478 else 479 { 480 retVal = false; 481 } 482 } 483 else 484 { 485 retVal = false; 486 } 487 488 return (retVal); 489 } 490 491 int32 492 PVA_FF_MediaDataAtom::addRenderableSample(PVA_FF_Renderable *psample) 493 { 494 if (_type == MEDIA_DATA_ON_DISK) 495 { 496 // Force renderables to 497 // be written to disk 498 uint32 length = psample->getSize(); 499 psample->renderToFileStream(&_pofstream); 500 _fileSize += length; 501 502 recomputeSize(); 503 return length; 504 } 505 else 506 { 507 // MEDIA_DATA_IN_MEMORY 508 PVA_FF_Renderable *prenderable = (PVA_FF_Renderable*) psample; 509 _prenderables->push_back(prenderable); 510 511 recomputeSize(); 512 return prenderable->getSize(); 513 } 514 } 515 516 517 // Allocates in-memory space for the media data 518 void 519 PVA_FF_MediaDataAtom::reserveBuffer(int32 size) 520 { 521 OSCL_UNUSED_ARG(size); 522 } 523 524 void 525 PVA_FF_MediaDataAtom::recomputeSize() 526 { 527 if (_type == MEDIA_DATA_ON_DISK) 528 { 529 // Entire atom size fp same as atom file size 530 if (_fileSize == 0) 531 { 532 _size = getDefaultSize(); 533 } 534 else 535 { 536 _size = _fileSize; 537 } 538 } 539 else 540 { // MEDIA_DATA_IN_MEMORY 541 542 uint32 size = getDefaultSize(); 543 544 // Include size from actual data payload 545 546 // From renderable data 547 for (uint32 i = 0; i < _prenderables->size(); i++) 548 { 549 size += (*_prenderables)[i]->getSize(); 550 } 551 552 _size = size; 553 } 554 } 555 556 uint32 557 PVA_FF_MediaDataAtom::getMediaDataSize() 558 { 559 recomputeSize(); 560 561 uint32 size = getSize(); 562 563 return (size); 564 } 565 566 // Rendering the PVA_FF_Atom in proper format (bitlengths, etc.) to an ostream 567 bool 568 PVA_FF_MediaDataAtom::renderToFileStream(MP4_AUTHOR_FF_FILE_IO_WRAP *fp) 569 { 570 571 int32 rendered = 0; // Keep track of number of bytes rendered 572 573 // Render the data 574 if (_type == MEDIA_DATA_IN_MEMORY) 575 { 576 577 // Render in-memory data directoy to disk 578 // From renderable data 579 580 // Render PVA_FF_Atom type and size 581 if (!renderAtomBaseMembers(fp)) 582 { 583 return false; 584 } 585 rendered += getDefaultSize(); 586 587 // BREAKING CONST RULES!!! 588 589 // Need to set the actual file offset where the actual chunk data begins 590 // so before rendering the ChunkOffetAtom, we can shift the PVA_FF_ChunkOffsetAtom 591 // table elements by this offset - the table elements are actual file offsets 592 // and NOT just offsets from the first chunk (i.e. zero) and we don't really 593 // know this offset until now. 594 PVA_FF_MediaDataAtom *This = const_cast<PVA_FF_MediaDataAtom*>(this); 595 This->setFileOffsetForChunkStart(PVA_FF_AtomUtils::getCurrentFilePosition(fp)); 596 597 for (uint32 i = 0; i < _prenderables->size(); i++) 598 { 599 if (!(*_prenderables)[i]->renderToFileStream(fp)) 600 { 601 return false; 602 } 603 rendered += (*_prenderables)[i]->getSize(); 604 } 605 } 606 else 607 { 608 // MEDIA_DATA_ON_DISK 609 // 05/30/01 CPU problem when the file fp big. 610 // We update the size at the end not for every sample. 611 // Need to update the atoms size field on disk 612 int32 currentPos = PVA_FF_AtomUtils::getCurrentFilePosition(&_pofstream); // Get current position of put pointer 613 PVA_FF_AtomUtils::seekFromStart(&_pofstream, 0); // Go to the beginning of the file 614 if (!PVA_FF_AtomUtils::render32(&_pofstream, getSize())) 615 { 616 return false; 617 } 618 // Update size field 619 PVA_FF_AtomUtils::seekFromStart(&_pofstream, currentPos); // Return the ostream's put pointer 620 621 // Cleanup and close temp data output file 622 if (_pofstream._filePtr != NULL) 623 { 624 PVA_FF_AtomUtils::closeFile(&_pofstream); 625 _pofstream._filePtr = NULL; 626 } 627 628 // Open the file in which this mdat atom was stored 629 MP4_AUTHOR_FF_FILE_IO_WRAP mdatFilePtr; 630 mdatFilePtr._filePtr = NULL; 631 mdatFilePtr._osclFileServerSession = OSCL_STATIC_CAST(Oscl_FileServer*, _osclFileServerSession); 632 PVA_FF_AtomUtils::openFile(&mdatFilePtr, _tempFilename, Oscl_File::MODE_READ | Oscl_File::MODE_BINARY); 633 634 // Seek to the offset in the file where the ATOM starts 635 PVA_FF_AtomUtils::seekFromStart(&mdatFilePtr, _fileOffsetForAtomStart); 636 637 // In the case where the mdat atom fp stored on disk file, 638 // the atom just gets directly copied - i.e. there fp no atom-specific 639 // rendering. We need to adjust the fileOffset by the size of the 640 // atom header (based on what the header "should" be). 641 642 // BREAKING CONST RULES!!! 643 644 // Need to set the actual file offset where the actual chunk data begins 645 // so before rendering the ChunkOffetAtom, we can shift the PVA_FF_ChunkOffsetAtom 646 // table elements by this offset - the table elements are actual file offsets 647 // and NOT just offsets from the first chunk (i.e. zero) and we don't really 648 // know this offset until now (during rendering). 649 PVA_FF_MediaDataAtom *This = const_cast<PVA_FF_MediaDataAtom*>(this); 650 This->setFileOffsetForChunkStart((uint32)(PVA_FF_AtomUtils::getCurrentFilePosition(fp)) + 651 (uint32)getDefaultSize()); 652 653 // Read in atom from separate file and copy byte-by-byte to new ofstream 654 // (including the mediaDataAtom header - 4 byte size ad 4 byte type) 655 656 uint32 readBlockSize = 0; 657 uint32 tempFileSize = getSize(); 658 659 uint8 *dataBuf = NULL; 660 661 PV_MP4_FF_ARRAY_NEW(NULL, uint8, TEMP_TO_TARGET_FILE_COPY_BLOCK_SIZE, dataBuf); 662 663 while (tempFileSize > 0) 664 { 665 if (tempFileSize < TEMP_TO_TARGET_FILE_COPY_BLOCK_SIZE) 666 { 667 readBlockSize = tempFileSize; 668 } 669 else 670 { 671 readBlockSize = TEMP_TO_TARGET_FILE_COPY_BLOCK_SIZE; 672 } 673 674 if (!(PVA_FF_AtomUtils::readByteData(&mdatFilePtr, readBlockSize, dataBuf))) 675 { 676 _targetFileWriteError = true; 677 return false; 678 } 679 680 if (!(PVA_FF_AtomUtils::renderByteData(fp, readBlockSize, dataBuf))) 681 { 682 _targetFileWriteError = true; 683 return false; 684 } 685 tempFileSize -= readBlockSize; 686 } 687 688 PV_MP4_FF_DELETE(NULL, uint8, dataBuf); 689 690 rendered += _fileSize; 691 692 PVA_FF_AtomUtils::closeFile(&mdatFilePtr); 693 694 } 695 696 return true; 697 } 698 699