1 /* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18 /*********************************************************************************/ 19 /* ------------------------------------------------------------------- */ 20 /* MPEG-4 IMpeg4File Class */ 21 /* ------------------------------------------------------------------- */ 22 /*********************************************************************************/ 23 /* 24 The IMpeg4File Class is INTERFACE that exsposes only those necessary 25 methods of the underlying Mpeg4File class. 26 */ 27 28 #define IMPLEMENT_IMpeg4File_H__ 29 30 #define GENERIC_ATOM_SIZE 8 31 32 #ifndef OSCL_FILE_IO_H_INCLUDED 33 #include "oscl_file_io.h" 34 #endif 35 36 #include "atom.h" 37 #include "atomutils.h" 38 #include "atomdefs.h" 39 40 #include "pvuserdataatom.h" 41 #include "oscl_utf8conv.h" 42 #include "isucceedfail.h" 43 44 #include "impeg4file.h" 45 #include "mpeg4file.h" 46 47 #include "oscl_string.h" 48 49 50 // Use default DLL entry point for Symbian 51 #include "oscl_dll.h" 52 OSCL_DLL_ENTRY_POINT_DEFAULT() 53 54 55 /* ======================================================================== */ 56 OSCL_EXPORT_REF IMpeg4File *IMpeg4File::readMP4File(OSCL_wString& aFilename, 57 PVMFCPMPluginAccessInterfaceFactory* aCPMAccessFactory, 58 OsclFileHandle* aHandle, 59 uint32 aParsingMode, 60 Oscl_FileServer* aFileServSession) 61 { 62 //optimized mode is not supported if multiple file ptrs are not allowed 63 if (aParsingMode == 1) 64 { 65 #ifndef OPEN_FILE_ONCE_PER_TRACK 66 aParsingMode = 0; 67 #endif 68 } 69 70 MP4_FF_FILE fileStruct; 71 MP4_FF_FILE *fp = &fileStruct; 72 73 fp->_fileServSession = aFileServSession; 74 fp->_pvfile.SetCPM(aCPMAccessFactory); 75 fp->_pvfile.SetFileHandle(aHandle); 76 77 if (AtomUtils::OpenMP4File(aFilename, 78 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 79 fp) != 0) 80 { 81 return NULL; 82 } 83 84 uint32 fileSize; 85 AtomUtils::getCurrentFileSize(fp, fileSize); 86 fp->_fileSize = (int32)fileSize; 87 88 Mpeg4File *mp4 = NULL; 89 PV_MP4_FF_NEW(fp->auditCB, Mpeg4File, (fp, aFilename, aParsingMode), mp4); 90 91 #ifdef OPEN_FILE_ONCE_PER_TRACK 92 if (mp4 != NULL) 93 { 94 if (!mp4->IsMovieFragmentsPresent()) 95 { 96 if (fp->IsOpen()) 97 AtomUtils::CloseMP4File(fp); 98 } 99 } 100 #endif 101 102 return mp4; 103 } 104 105 //IsXXXable ******************************************* 106 /* 107 oMoovBeforeMdat: as input, 108 1: IsMobileMP4 check 109 2: IsPseudoStreamable() check 110 3: IsPlayable() check 111 as output, 112 1: moov atom is in front of the mdat atom 113 0: there is mdat atom in front of moov atom 114 115 metaDataSize : as input. It is the available data size 116 as output. It is the offset of the file where the full "moov" atom is available. 117 */ 118 119 OSCL_EXPORT_REF 120 int32 121 IMpeg4File::IsXXXable(OSCL_wString& filename, 122 int32 &metaDataSize, 123 int32 &oMoovBeforeMdat, 124 uint32 *pMajorBrand, 125 uint32 *pCompatibleBrands, 126 Oscl_FileServer* fileServSession) 127 { 128 const int ISMOBILEMP4 = 1, ISPSEUDOSTREMABLE = 2, ISPLAYABLE = 3; 129 130 if (metaDataSize <= DEFAULT_ATOM_SIZE) 131 return READ_FAILED; 132 133 if ((oMoovBeforeMdat < ISMOBILEMP4) || (oMoovBeforeMdat > ISPLAYABLE)) 134 return DEFAULT_ERROR; 135 136 int32 checkType = oMoovBeforeMdat; 137 int32 fileSize = metaDataSize; 138 139 MP4_FF_FILE fileStruct; 140 MP4_FF_FILE *fp = &fileStruct; 141 142 fp->_fileServSession = fileServSession; 143 144 if (AtomUtils::OpenMP4File(filename, 145 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 146 fp) != 0) 147 { 148 return (FILE_OPEN_FAILED); 149 } 150 151 fp->_fileSize = fileSize; 152 153 int32 mp4ErrorCode = DEFAULT_ERROR; 154 155 uint32 atomType = UNKNOWN_ATOM; 156 uint32 atomSize = 0; 157 158 AtomUtils::getNextAtomType(fp, atomSize, atomType); 159 160 if (atomType == FILE_TYPE_ATOM) 161 { 162 //"ftyp" 163 if (fileSize < (int32)atomSize) 164 { 165 AtomUtils::CloseMP4File(fp); 166 return READ_FAILED; 167 } 168 FileTypeAtom *_pFileTypeAtom = NULL; 169 PV_MP4_FF_NEW(fp->auditCB, FileTypeAtom, (fp, atomSize, atomType), _pFileTypeAtom); 170 171 if (!_pFileTypeAtom->MP4Success()) 172 { 173 PV_MP4_FF_DELETE(NULL, FileTypeAtom, _pFileTypeAtom); 174 AtomUtils::CloseMP4File(fp); 175 return READ_FILE_TYPE_ATOM_FAILED; 176 } 177 //get file type 178 { 179 *pMajorBrand = ENoFileType; 180 181 uint32 majorBrand = _pFileTypeAtom->getMajorBrand(); 182 183 //conversion 184 if (majorBrand == MOBILE_MP4) *pMajorBrand = EMMP4; 185 else if (majorBrand == BRAND_3GPP4) *pMajorBrand = E3GP4; 186 else if (majorBrand == BRAND_3GPP5) *pMajorBrand = E3GP5; 187 else if (majorBrand == BRAND_ISOM) *pMajorBrand = EISOM; 188 else if (majorBrand == BRAND_MP41) *pMajorBrand = EMP41; 189 else if (majorBrand == BRAND_MP42) *pMajorBrand = EMP42; 190 else if (majorBrand == WMF_BRAND) *pMajorBrand = EWMF; 191 // else .. set to ENoFileType above 192 193 Oscl_Vector<uint32, OsclMemAllocator> *compatibleBrandArray = 194 _pFileTypeAtom->getCompatibleBrand(); 195 196 *pCompatibleBrands = ENoFileType; 197 198 if (compatibleBrandArray != NULL) 199 { 200 for (uint32 i = 0; i < compatibleBrandArray->size(); i++) 201 { 202 uint32 compatibleBrand = (*compatibleBrandArray)[i]; 203 204 if (compatibleBrand == MOBILE_MP4) *pCompatibleBrands |= EMMP4; 205 else if (compatibleBrand == BRAND_3GPP4) *pCompatibleBrands |= E3GP4; 206 else if (compatibleBrand == BRAND_3GPP5) *pCompatibleBrands |= E3GP5; 207 else if (compatibleBrand == BRAND_ISOM) *pCompatibleBrands |= EISOM; 208 else if (compatibleBrand == BRAND_MP41) *pCompatibleBrands |= EMP41; 209 else if (compatibleBrand == BRAND_MP42) *pCompatibleBrands |= EMP42; 210 else if (compatibleBrand == WMF_BRAND) *pCompatibleBrands |= EWMF; 211 } 212 } 213 }//end of get file type 214 215 int32 fpos = _pFileTypeAtom->getSize(); 216 PV_MP4_FF_DELETE(NULL, FileTypeAtom, _pFileTypeAtom); 217 218 if (checkType == ISMOBILEMP4) 219 { 220 AtomUtils::CloseMP4File(fp); 221 return EVERYTHING_FINE; 222 } 223 224 oMoovBeforeMdat = true; 225 metaDataSize = 0; 226 227 if ((fpos + DEFAULT_ATOM_SIZE) > fileSize) 228 { 229 AtomUtils::CloseMP4File(fp); 230 return READ_FAILED; 231 } 232 233 while (fpos < fileSize) 234 { 235 uint32 atomType = UNKNOWN_ATOM; 236 uint32 atomSize = 0; 237 238 AtomUtils::getNextAtomType(fp, atomSize, atomType); 239 240 fpos += DEFAULT_ATOM_SIZE; 241 242 if ((atomType == FREE_SPACE_ATOM) 243 || (atomType == SKIP_ATOM) 244 || (atomType == USER_DATA_ATOM) 245 || (atomType == UUID_ATOM) 246 || (atomType == MOVIE_ATOM) 247 || (atomType == MEDIA_DATA_ATOM) 248 || (atomType == UNKNOWN_ATOM)) 249 { 250 if (atomSize < DEFAULT_ATOM_SIZE) 251 { 252 mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE; 253 break; 254 } 255 atomSize -= DEFAULT_ATOM_SIZE; 256 if (atomType == MOVIE_ATOM) 257 { 258 //this is an exit 259 //no check of the "size" validity 260 metaDataSize = fpos + atomSize; 261 mp4ErrorCode = EVERYTHING_FINE; 262 break; 263 } 264 else if (atomType == MEDIA_DATA_ATOM) 265 { 266 oMoovBeforeMdat = false; 267 if (checkType == ISPSEUDOSTREMABLE) 268 { 269 mp4ErrorCode = EVERYTHING_FINE; 270 break; 271 } 272 } 273 274 if ((int32)(fpos + atomSize) > fileSize) 275 { 276 mp4ErrorCode = READ_FAILED; 277 break; 278 } 279 AtomUtils::seekFromCurrPos(fp, atomSize); 280 fpos += atomSize; 281 282 } 283 else if (atomType == 0) 284 { 285 //return READ_FAILED; 286 //since extra check is put above, it should NEVER fall in this bracket 287 mp4ErrorCode = READ_FAILED; 288 break; 289 } 290 else 291 { //error: other atoms should not be in file level 292 mp4ErrorCode = DEFAULT_ERROR; 293 break; 294 } 295 } 296 } 297 AtomUtils::CloseMP4File(fp); 298 return (mp4ErrorCode); 299 } 300 301 OSCL_EXPORT_REF 302 int32 303 IMpeg4File::IsXXXable(MP4_FF_FILE_REFERENCE fileRef, 304 int32 &metaDataSize, 305 int32 &oMoovBeforeMdat, 306 uint32 *pMajorBrand, 307 uint32 *pCompatibleBrands) 308 { 309 const int ISMOBILEMP4 = 1, ISPSEUDOSTREMABLE = 2, ISPLAYABLE = 3; 310 311 if (metaDataSize <= DEFAULT_ATOM_SIZE) 312 return READ_FAILED; 313 314 if ((oMoovBeforeMdat < ISMOBILEMP4) || (oMoovBeforeMdat > ISPLAYABLE)) 315 return DEFAULT_ERROR; 316 317 int32 checkType = oMoovBeforeMdat; 318 int32 fileSize = metaDataSize; 319 320 MP4_FF_FILE fileStruct; 321 MP4_FF_FILE *fp = &fileStruct; 322 323 fp->_pvfile.SetFilePtr(fileRef); 324 325 AtomUtils::seekFromStart(fp, 0); 326 fp->_fileSize = fileSize; 327 328 int32 mp4ErrorCode = DEFAULT_ERROR; 329 330 uint32 atomType = UNKNOWN_ATOM; 331 uint32 atomSize = 0; 332 333 AtomUtils::getNextAtomType(fp, atomSize, atomType); 334 335 if (atomType == FILE_TYPE_ATOM) 336 { 337 //"ftyp" 338 if (fileSize < (int32)atomSize) 339 { 340 AtomUtils::CloseMP4File(fp); 341 return READ_FAILED; 342 } 343 FileTypeAtom *_pFileTypeAtom = NULL; 344 PV_MP4_FF_NEW(fp->auditCB, FileTypeAtom, (fp, atomSize, atomType), _pFileTypeAtom); 345 346 if (!_pFileTypeAtom->MP4Success()) 347 { 348 PV_MP4_FF_DELETE(NULL, FileTypeAtom, _pFileTypeAtom); 349 AtomUtils::CloseMP4File(fp); 350 return READ_FILE_TYPE_ATOM_FAILED; 351 } 352 //get file type 353 { 354 *pMajorBrand = ENoFileType; 355 356 uint32 majorBrand = _pFileTypeAtom->getMajorBrand(); 357 358 //conversion 359 if (majorBrand == MOBILE_MP4) *pMajorBrand = EMMP4; 360 else if (majorBrand == BRAND_3GPP4) *pMajorBrand = E3GP4; 361 else if (majorBrand == BRAND_3GPP5) *pMajorBrand = E3GP5; 362 else if (majorBrand == BRAND_ISOM) *pMajorBrand = EISOM; 363 else if (majorBrand == BRAND_MP41) *pMajorBrand = EMP41; 364 else if (majorBrand == BRAND_MP42) *pMajorBrand = EMP42; 365 else if (majorBrand == WMF_BRAND) *pMajorBrand = EWMF; 366 367 368 Oscl_Vector<uint32, OsclMemAllocator> *compatibleBrandArray = 369 _pFileTypeAtom->getCompatibleBrand(); 370 371 372 *pCompatibleBrands = ENoFileType; 373 374 if (compatibleBrandArray != NULL) 375 { 376 for (uint32 i = 0; i < compatibleBrandArray->size(); i++) 377 { 378 uint32 compatibleBrand = (*compatibleBrandArray)[i]; 379 380 if (compatibleBrand == MOBILE_MP4) *pCompatibleBrands |= EMMP4; 381 else if (compatibleBrand == BRAND_3GPP4) *pCompatibleBrands |= E3GP4; 382 else if (compatibleBrand == BRAND_3GPP5) *pCompatibleBrands |= E3GP5; 383 else if (compatibleBrand == BRAND_ISOM) *pCompatibleBrands |= EISOM; 384 else if (compatibleBrand == BRAND_MP41) *pCompatibleBrands |= EMP41; 385 else if (compatibleBrand == BRAND_MP42) *pCompatibleBrands |= EMP42; 386 else if (compatibleBrand == WMF_BRAND) *pCompatibleBrands |= EWMF; 387 } 388 } 389 }//end of get file type 390 391 int32 fpos = _pFileTypeAtom->getSize(); 392 PV_MP4_FF_DELETE(NULL, FileTypeAtom, _pFileTypeAtom); 393 394 if (checkType == ISMOBILEMP4) 395 { 396 AtomUtils::CloseMP4File(fp); 397 return EVERYTHING_FINE; 398 } 399 400 oMoovBeforeMdat = true; 401 metaDataSize = 0; 402 403 if ((fpos + DEFAULT_ATOM_SIZE) > fileSize) 404 { 405 AtomUtils::CloseMP4File(fp); 406 return READ_FAILED; 407 } 408 409 while (fpos < fileSize) 410 { 411 uint32 atomType = UNKNOWN_ATOM; 412 uint32 atomSize = 0; 413 414 AtomUtils::getNextAtomType(fp, atomSize, atomType); 415 416 fpos += DEFAULT_ATOM_SIZE; 417 418 if ((atomType == FREE_SPACE_ATOM) 419 || (atomType == SKIP_ATOM) 420 || (atomType == USER_DATA_ATOM) 421 || (atomType == UUID_ATOM) 422 || (atomType == MOVIE_ATOM) 423 || (atomType == MEDIA_DATA_ATOM) 424 || (atomType == UNKNOWN_ATOM)) 425 { 426 if (atomSize < DEFAULT_ATOM_SIZE) 427 { 428 mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE; 429 break; 430 } 431 atomSize -= DEFAULT_ATOM_SIZE; 432 if (atomType == MOVIE_ATOM) 433 { 434 //this is an exit 435 //no check of the "size" validity 436 metaDataSize = fpos + atomSize; 437 mp4ErrorCode = EVERYTHING_FINE; 438 break; 439 } 440 else if (atomType == MEDIA_DATA_ATOM) 441 { 442 oMoovBeforeMdat = false; 443 if (checkType == ISPSEUDOSTREMABLE) 444 { 445 mp4ErrorCode = EVERYTHING_FINE; 446 break; 447 } 448 } 449 450 if ((int32)(fpos + atomSize) > fileSize) 451 { 452 mp4ErrorCode = READ_FAILED; 453 break; 454 } 455 AtomUtils::seekFromCurrPos(fp, atomSize); 456 fpos += atomSize; 457 458 } 459 else if (atomType == 0) 460 { 461 //return READ_FAILED; 462 //since extra check is put above, it should NEVER fall in this bracket 463 mp4ErrorCode = READ_FAILED; 464 break; 465 } 466 else 467 { //error: other atoms should not be in file level 468 mp4ErrorCode = DEFAULT_ERROR; 469 break; 470 } 471 } 472 } 473 AtomUtils::CloseMP4File(fp); 474 return (mp4ErrorCode); 475 } 476 477 478 OSCL_EXPORT_REF MP4_ERROR_CODE 479 IMpeg4File::IsProgressiveDownloadable(MP4_FF_FILE_REFERENCE filePtr, 480 uint32 fileSize, 481 bool& oIsProgressiveDownloadable, 482 uint32& metaDataSize) 483 { 484 oIsProgressiveDownloadable = false; 485 metaDataSize = 0; 486 487 MP4_FF_FILE fileStruct; 488 MP4_FF_FILE *fp = &fileStruct; 489 490 fp->_pvfile.SetFilePtr(filePtr); 491 492 if (fileSize <= DEFAULT_ATOM_SIZE) 493 { 494 return INSUFFICIENT_DATA; 495 } 496 497 int32 filePointer = AtomUtils::getCurrentFilePosition(fp); 498 AtomUtils::seekFromStart(fp, 0); 499 500 fp->_fileSize = fileSize; 501 502 uint32 atomType = UNKNOWN_ATOM; 503 uint32 atomSize = 0; 504 bool oMovieAtomFound = false; 505 bool oMediaDataAtomFound = false; 506 507 int32 fpos = 0; 508 509 MP4_ERROR_CODE mp4ErrorCode = INSUFFICIENT_DATA; 510 511 while ((uint32)(fpos + DEFAULT_ATOM_SIZE) < fileSize) 512 { 513 AtomUtils::getNextAtomType(fp, atomSize, atomType); 514 if (atomSize < DEFAULT_ATOM_SIZE) 515 { 516 mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE; 517 break; 518 } 519 520 if ((atomType == FILE_TYPE_ATOM) || 521 (atomType == FREE_SPACE_ATOM) || 522 (atomType == SKIP_ATOM) || 523 (atomType == USER_DATA_ATOM) || 524 (atomType == UUID_ATOM) || 525 (atomType == UNKNOWN_ATOM)) 526 { 527 fpos += atomSize; 528 if ((uint32)fpos > fileSize) 529 { 530 break; 531 } 532 AtomUtils::seekFromStart(fp, fpos); 533 continue; 534 } 535 else if (atomType == MOVIE_ATOM) 536 { 537 fpos += atomSize; 538 oMovieAtomFound = true; 539 metaDataSize = fpos; 540 } 541 else if (atomType == MEDIA_DATA_ATOM) 542 { 543 fpos += atomSize; 544 oMediaDataAtomFound = true; 545 } 546 else 547 { 548 //error: should never get here 549 mp4ErrorCode = DEFAULT_ERROR; 550 } 551 break; 552 } 553 554 if (oMovieAtomFound || oMediaDataAtomFound) 555 { 556 //at most one of two can be true 557 oIsProgressiveDownloadable = oMovieAtomFound; 558 mp4ErrorCode = EVERYTHING_FINE; 559 } 560 561 AtomUtils::seekFromStart(fp, filePointer); 562 563 return (mp4ErrorCode); 564 } 565 566 OSCL_EXPORT_REF MP4_ERROR_CODE 567 IMpeg4File::GetMetaDataSize(PVMFCPMPluginAccessInterfaceFactory* aCPMAccessFactory, 568 bool& oIsProgressiveDownloadable, 569 uint32& metaDataSize) 570 { 571 oIsProgressiveDownloadable = false; 572 metaDataSize = 0; 573 574 /* use a dummy string for file name */ 575 OSCL_wHeapString<OsclMemAllocator> filename; 576 577 MP4_FF_FILE fileStruct; 578 MP4_FF_FILE *fp = &fileStruct; 579 fp->_pvfile.SetCPM(aCPMAccessFactory); 580 581 if (AtomUtils::OpenMP4File(filename, 582 Oscl_File::MODE_READ | Oscl_File::MODE_BINARY, 583 fp) != 0) 584 { 585 return FILE_OPEN_FAILED; 586 } 587 588 uint32 fileSize; 589 AtomUtils::getCurrentFileSize(fp, fileSize); 590 fp->_fileSize = (int32)fileSize; 591 592 AtomUtils::seekFromStart(fp, 0); 593 594 if (fileSize <= DEFAULT_ATOM_SIZE) 595 { 596 return INSUFFICIENT_DATA; 597 } 598 599 uint32 atomType = UNKNOWN_ATOM; 600 uint32 atomSize = 0; 601 bool oMovieAtomFound = false; 602 bool oMediaDataAtomFound = false; 603 604 int32 fpos = 0; 605 606 MP4_ERROR_CODE mp4ErrorCode = INSUFFICIENT_DATA; 607 608 while ((uint32)(fpos + DEFAULT_ATOM_SIZE) < fileSize) 609 { 610 AtomUtils::getNextAtomType(fp, atomSize, atomType); 611 if (atomSize < DEFAULT_ATOM_SIZE) 612 { 613 mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE; 614 break; 615 } 616 617 if ((atomType == FILE_TYPE_ATOM) || 618 (atomType == FREE_SPACE_ATOM) || 619 (atomType == SKIP_ATOM) || 620 (atomType == USER_DATA_ATOM) || 621 (atomType == UUID_ATOM) || 622 (atomType == UNKNOWN_ATOM)) 623 { 624 fpos += atomSize; 625 metaDataSize = fpos; 626 if ((uint32)fpos > fileSize) 627 { 628 break; 629 } 630 AtomUtils::seekFromStart(fp, fpos); 631 continue; 632 } 633 else if (atomType == MOVIE_ATOM) 634 { 635 fpos += atomSize; 636 oMovieAtomFound = true; 637 metaDataSize = fpos; 638 } 639 else if (atomType == MEDIA_DATA_ATOM) 640 { 641 fpos += atomSize; 642 oMediaDataAtomFound = true; 643 metaDataSize = fpos; 644 } 645 else 646 { 647 //error: should never get here 648 mp4ErrorCode = DEFAULT_ERROR; 649 } 650 break; 651 } 652 653 if (oMovieAtomFound || oMediaDataAtomFound) 654 { 655 //at most one of two can be true 656 oIsProgressiveDownloadable = oMovieAtomFound; 657 mp4ErrorCode = EVERYTHING_FINE; 658 } 659 660 if (!oMovieAtomFound && (0 != AtomUtils::getFileBufferingCapacity(fp))) 661 { 662 // can't support progressive playback if no movie atom found 663 mp4ErrorCode = NOT_PROGRESSIVE_STREAMABLE; 664 } 665 666 AtomUtils::CloseMP4File(fp); 667 668 return (mp4ErrorCode); 669 } 670 671 OSCL_EXPORT_REF void IMpeg4File::DestroyMP4FileObject(IMpeg4File* aMP4FileObject) 672 { 673 Mpeg4File* ptr = OSCL_STATIC_CAST(Mpeg4File*, aMP4FileObject); 674 PV_MP4_FF_DELETE(NULL, Mpeg4File, ptr); 675 } 676