1/* 2 * Copyright (c) 2005, David McPaul 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 23 * OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25#include <stdio.h> 26 27#include <DataIO.h> 28#include <SupportKit.h> 29#include <MediaFormats.h> 30 31#ifdef __HAIKU__ 32#include <libs/zlib/zlib.h> 33#else 34#include <zlib.h> 35#endif 36 37#include "MOVParser.h" 38 39//static 40AtomBase *getAtom(BPositionIO *pStream) 41{ 42 uint32 aAtomType; 43 uint32 aAtomSize; 44 uint64 aRealAtomSize; 45 off_t aStreamOffset; 46 47 aStreamOffset = pStream->Position(); 48 49 // Get Size uint32 50 pStream->Read(&aAtomSize,4); 51 aAtomSize = B_BENDIAN_TO_HOST_INT32(aAtomSize); 52 // Get Type uint32 53 pStream->Read(&aAtomType,4); 54 aAtomType = B_BENDIAN_TO_HOST_INT32(aAtomType); 55 // Check for extended size 56 if (aAtomSize == 1) { 57 // Handle extended size 58 pStream->Read(&aRealAtomSize,4); 59 aRealAtomSize = B_BENDIAN_TO_HOST_INT64(aRealAtomSize); 60 } else { 61 aRealAtomSize = aAtomSize; 62 } 63 64 if (aAtomType == uint32('moov')) { 65 return new MOOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 66 } 67 68 if (aAtomType == uint32('mvhd')) { 69 return new MVHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 70 } 71 72 if (aAtomType == uint32('trak')) { 73 return new TRAKAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 74 } 75 76 if (aAtomType == uint32('tkhd')) { 77 return new TKHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 78 } 79 80 if (aAtomType == uint32('free')) { 81 return new FREEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 82 } 83 84 if (aAtomType == uint32('skip')) { 85 return new SKIPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 86 } 87 88 if (aAtomType == uint32('wide')) { 89 return new WIDEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 90 } 91 92 if (aAtomType == uint32('mdat')) { 93 return new MDATAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 94 } 95 96 if (aAtomType == uint32('mdia')) { 97 return new MDIAAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 98 } 99 100 if (aAtomType == uint32('mdhd')) { 101 return new MDHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 102 } 103 104 if (aAtomType == uint32('hdlr')) { 105 return new HDLRAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 106 } 107 108 if (aAtomType == uint32('minf')) { 109 return new MINFAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 110 } 111 112 if (aAtomType == uint32('vmhd')) { 113 return new VMHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 114 } 115 116 if (aAtomType == uint32('smhd')) { 117 return new SMHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 118 } 119 120 if (aAtomType == uint32('dinf')) { 121 return new DINFAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 122 } 123 124 if (aAtomType == uint32('stbl')) { 125 return new STBLAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 126 } 127 128 if (aAtomType == uint32('stsd')) { 129 return new STSDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 130 } 131 132 if (aAtomType == uint32('tmcd')) { 133 return new TMCDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 134 } 135 136 if (aAtomType == uint32('wave')) { 137 return new WAVEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 138 } 139 140 if (aAtomType == uint32('stts')) { 141 return new STTSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 142 } 143 144 if (aAtomType == uint32('pnot')) { 145 return new PNOTAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 146 } 147 148 if (aAtomType == uint32('stsc')) { 149 return new STSCAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 150 } 151 152 if (aAtomType == uint32('stco')) { 153 return new STCOAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 154 } 155 156 if (aAtomType == uint32('stss')) { 157 return new STSSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 158 } 159 160 if (aAtomType == uint32('stsz')) { 161 return new STSZAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 162 } 163 164 if (aAtomType == uint32('cmov')) { 165 return new CMOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 166 } 167 168 if (aAtomType == uint32('dcom')) { 169 return new DCOMAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 170 } 171 172 if (aAtomType == uint32('cmvd')) { 173 return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 174 } 175 176 if (aAtomType == uint32('esds')) { 177 return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 178 } 179 180 if (aAtomType == uint32('avcC')) { 181 return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 182 } 183 184 if (aAtomType == uint32('ftyp')) { 185 return new FTYPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); 186 } 187 188 return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize); 189 190} 191 192MOOVAtom::MOOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 193{ 194 theMVHDAtom = NULL; 195} 196 197MOOVAtom::~MOOVAtom() 198{ 199 theMVHDAtom = NULL; 200} 201 202void MOOVAtom::OnProcessMetaData() 203{ 204} 205 206char *MOOVAtom::OnGetAtomName() 207{ 208 return "Quicktime Movie"; 209} 210 211CMOVAtom::CMOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 212{ 213 theUncompressedStream = NULL; 214} 215 216CMOVAtom::~CMOVAtom() 217{ 218} 219 220BPositionIO *CMOVAtom::OnGetStream() 221{ 222 // Use the decompressed stream instead of file stream 223 if (theUncompressedStream) { 224 return theUncompressedStream; 225 } 226 227 return theStream; 228} 229 230void CMOVAtom::OnProcessMetaData() 231{ 232 BMallocIO *theUncompressedData; 233 uint8 *outBuffer; 234 CMVDAtom *aCMVDAtom = NULL; 235 uint32 compressionID = 0; 236 uint64 descBytesLeft; 237 uint32 Size; 238 239 descBytesLeft = getAtomSize(); 240 241 // Check for Compression Type 242 while (descBytesLeft > 0) { 243 AtomBase *aAtomBase = getAtom(theStream); 244 245 aAtomBase->OnProcessMetaData(); 246 printf("%s [%Ld]\n",aAtomBase->getAtomName(),aAtomBase->getAtomSize()); 247 248 if (aAtomBase->getAtomSize() > 0) { 249 descBytesLeft = descBytesLeft - aAtomBase->getAtomSize(); 250 } else { 251 printf("Invalid Atom found when reading Compressed Headers\n"); 252 descBytesLeft = 0; 253 } 254 255 if (dynamic_cast<DCOMAtom *>(aAtomBase)) { 256 // DCOM atom 257 compressionID = dynamic_cast<DCOMAtom *>(aAtomBase)->getCompressionID(); 258 delete aAtomBase; 259 } else { 260 if (dynamic_cast<CMVDAtom *>(aAtomBase)) { 261 // CMVD atom 262 aCMVDAtom = dynamic_cast<CMVDAtom *>(aAtomBase); 263 descBytesLeft = 0; 264 } 265 } 266 } 267 268 // Decompress data 269 if (compressionID == 'zlib') { 270 Size = aCMVDAtom->getUncompressedSize(); 271 272 outBuffer = (uint8 *)(malloc(Size)); 273 274 printf("Decompressing %ld bytes to %ld bytes\n",aCMVDAtom->getBufferSize(),Size); 275 int result = uncompress(outBuffer, &Size, aCMVDAtom->getCompressedData(), aCMVDAtom->getBufferSize()); 276 277 if (result != Z_OK) { 278 printf("Failed to decompress headers uncompress returned "); 279 switch (result) { 280 case Z_MEM_ERROR: 281 DEBUGGER("Lack of Memory Error\n"); 282 break; 283 case Z_BUF_ERROR: 284 DEBUGGER("Lack of Output buffer space Error\n"); 285 break; 286 case Z_DATA_ERROR: 287 DEBUGGER("Input Data is corrupt or not a compressed set Error\n"); 288 break; 289 } 290 } 291 292 // Copy uncompressed data into BMAllocIO 293 theUncompressedData = new BMallocIO(); 294 theUncompressedData->SetSize(Size); 295 theUncompressedData->WriteAt(0L,outBuffer,Size); 296 297 free(outBuffer); 298 delete aCMVDAtom; 299 300 // reset position on BMAllocIO 301 theUncompressedData->Seek(SEEK_SET,0L); 302 // Assign to Stream 303 theUncompressedStream = theUncompressedData; 304 305 // All subsequent reads should use theUncompressedStream 306 } 307 308} 309 310void CMOVAtom::OnChildProcessingComplete() 311{ 312 // revert back to file stream once all children have finished 313 if (theUncompressedStream) { 314 delete theUncompressedStream; 315 } 316 theUncompressedStream = NULL; 317} 318 319char *CMOVAtom::OnGetAtomName() 320{ 321 return "Compressed Quicktime Movie"; 322} 323 324DCOMAtom::DCOMAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 325{ 326} 327 328DCOMAtom::~DCOMAtom() 329{ 330} 331 332void DCOMAtom::OnProcessMetaData() 333{ 334 Read(&compressionID); 335} 336 337char *DCOMAtom::OnGetAtomName() 338{ 339 return "Decompression Atom"; 340} 341 342CMVDAtom::CMVDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 343{ 344 Buffer = NULL; 345 UncompressedSize = 0; 346 BufferSize = 0; 347} 348 349CMVDAtom::~CMVDAtom() 350{ 351 if (Buffer) { 352 free(Buffer); 353 } 354} 355 356void CMVDAtom::OnProcessMetaData() 357{ 358 Read(&UncompressedSize); 359 360 if (UncompressedSize > 0) { 361 BufferSize = getBytesRemaining(); 362 Buffer = (uint8 *)(malloc(BufferSize)); 363 Read(Buffer,BufferSize); 364 } 365} 366 367char *CMVDAtom::OnGetAtomName() 368{ 369 return "Compressed Movie Data"; 370} 371 372MVHDAtom::MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 373{ 374} 375 376MVHDAtom::~MVHDAtom() 377{ 378} 379 380void MVHDAtom::OnProcessMetaData() 381{ 382 Read(&theHeader.CreationTime); 383 Read(&theHeader.ModificationTime); 384 Read(&theHeader.TimeScale); 385 Read(&theHeader.Duration); 386 Read(&theHeader.PreferredRate); 387 Read(&theHeader.PreferredVolume); 388 Read(&theHeader.PreviewTime); 389 Read(&theHeader.PreviewDuration); 390 Read(&theHeader.PosterTime); 391 Read(&theHeader.SelectionTime); 392 Read(&theHeader.SelectionDuration); 393 Read(&theHeader.CurrentTime); 394 Read(&theHeader.NextTrackID); 395} 396 397char *MVHDAtom::OnGetAtomName() 398{ 399 return "Quicktime Movie Header"; 400} 401 402MVHDAtom *MOOVAtom::getMVHDAtom() 403{ 404AtomBase *aAtomBase; 405 406 if (theMVHDAtom == NULL) { 407 aAtomBase = GetChildAtom(uint32('mvhd')); 408 theMVHDAtom = dynamic_cast<MVHDAtom *>(aAtomBase); 409 } 410 411 // Assert(theMVHDAtom != NULL,"Movie has no movie header atom"); 412 return theMVHDAtom; 413} 414 415STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 416{ 417 theHeader.NoEntries = 0; 418 SUMDurations = 0; 419 SUMCounts = 0; 420} 421 422STTSAtom::~STTSAtom() 423{ 424 for (uint32 i=0;i<theHeader.NoEntries;i++) { 425 delete theTimeToSampleArray[i]; 426 theTimeToSampleArray[i] = NULL; 427 } 428} 429 430void STTSAtom::OnProcessMetaData() 431{ 432TimeToSample *aTimeToSample; 433 434 ReadArrayHeader(&theHeader); 435 436 for (uint32 i=0;i<theHeader.NoEntries;i++) { 437 aTimeToSample = new TimeToSample; 438 439 Read(&aTimeToSample->Count); 440 Read(&aTimeToSample->Duration); 441 442 theTimeToSampleArray[i] = aTimeToSample; 443 SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count); 444 SUMCounts += theTimeToSampleArray[i]->Count; 445 } 446} 447 448char *STTSAtom::OnGetAtomName() 449{ 450 return "Time to Sample Atom"; 451} 452 453uint32 STTSAtom::getSampleForTime(uint32 pTime) 454{ 455// TODO this is too slow. PreCalc when loading this? 456 uint64 Duration = 0; 457 458 for (uint32 i=0;i<theHeader.NoEntries;i++) { 459 Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count); 460 if (Duration > pTime) { 461 return i; 462 } 463 } 464 465 return 0; 466} 467 468uint32 STTSAtom::getSampleForFrame(uint32 pFrame) 469{ 470// Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs 471 return pFrame; 472} 473 474STSCAtom::STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 475{ 476 theHeader.NoEntries = 0; 477} 478 479STSCAtom::~STSCAtom() 480{ 481 for (uint32 i=0;i<theHeader.NoEntries;i++) { 482 delete theSampleToChunkArray[i]; 483 theSampleToChunkArray[i] = NULL; 484 } 485} 486 487void STSCAtom::OnProcessMetaData() 488{ 489SampleToChunk *aSampleToChunk; 490 491 ReadArrayHeader(&theHeader); 492 493 uint32 TotalPrevSamples = 0; 494 495 for (uint32 i=0;i<theHeader.NoEntries;i++) { 496 aSampleToChunk = new SampleToChunk; 497 498 Read(&aSampleToChunk->FirstChunk); 499 Read(&aSampleToChunk->SamplesPerChunk); 500 Read(&aSampleToChunk->SampleDescriptionID); 501 502 if (i > 0) { 503 TotalPrevSamples = TotalPrevSamples + (aSampleToChunk->FirstChunk - theSampleToChunkArray[i-1]->FirstChunk) * theSampleToChunkArray[i-1]->SamplesPerChunk; 504 aSampleToChunk->TotalPrevSamples = TotalPrevSamples; 505 } else { 506 aSampleToChunk->TotalPrevSamples = 0; 507 } 508 509 theSampleToChunkArray[i] = aSampleToChunk; 510 } 511} 512 513char *STSCAtom::OnGetAtomName() 514{ 515 return "Sample to Chunk Atom"; 516} 517 518uint32 STSCAtom::getNoSamplesInChunk(uint32 pChunkID) 519{ 520 for (uint32 i=0;i<theHeader.NoEntries;i++) { 521 if (theSampleToChunkArray[i]->FirstChunk > pChunkID) { 522 return theSampleToChunkArray[i-1]->SamplesPerChunk; 523 } 524 } 525 526 return theSampleToChunkArray[theHeader.NoEntries-1]->SamplesPerChunk; 527} 528 529uint32 STSCAtom::getFirstSampleInChunk(uint32 pChunkID) 530{ 531uint32 Diff; 532 533 for (uint32 i=0;i<theHeader.NoEntries;i++) { 534 if (theSampleToChunkArray[i]->FirstChunk > pChunkID) { 535 Diff = pChunkID - theSampleToChunkArray[i-1]->FirstChunk; 536 return ((Diff * theSampleToChunkArray[i-1]->SamplesPerChunk) + theSampleToChunkArray[i-1]->TotalPrevSamples); 537 } 538 } 539 540 Diff = pChunkID - theSampleToChunkArray[theHeader.NoEntries-1]->FirstChunk; 541 return ((Diff * theSampleToChunkArray[theHeader.NoEntries-1]->SamplesPerChunk) + theSampleToChunkArray[theHeader.NoEntries-1]->TotalPrevSamples); 542} 543 544uint32 STSCAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk) 545{ 546 uint32 ChunkID = 0; 547 uint32 OffsetInChunk = 0; 548 549 for (int32 i=theHeader.NoEntries-1;i>=0;i--) { 550 if (pSample >= theSampleToChunkArray[i]->TotalPrevSamples) { 551 // Found chunk now calculate offset 552 ChunkID = (pSample - theSampleToChunkArray[i]->TotalPrevSamples) / theSampleToChunkArray[i]->SamplesPerChunk; 553 ChunkID += theSampleToChunkArray[i]->FirstChunk; 554 555 OffsetInChunk = (pSample - theSampleToChunkArray[i]->TotalPrevSamples) % theSampleToChunkArray[i]->SamplesPerChunk; 556 557 *pOffsetInChunk = OffsetInChunk; 558 return ChunkID; 559 } 560 } 561 562 *pOffsetInChunk = 0; 563 return theSampleToChunkArray[theHeader.NoEntries-1]->FirstChunk; 564} 565 566STSSAtom::STSSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 567{ 568 theHeader.NoEntries = 0; 569} 570 571STSSAtom::~STSSAtom() 572{ 573 for (uint32 i=0;i<theHeader.NoEntries;i++) { 574 delete theSyncSampleArray[i]; 575 theSyncSampleArray[i] = NULL; 576 } 577} 578 579void STSSAtom::OnProcessMetaData() 580{ 581SyncSample *aSyncSample; 582 583 ReadArrayHeader(&theHeader); 584 585 for (uint32 i=0;i<theHeader.NoEntries;i++) { 586 aSyncSample = new SyncSample; 587 588 Read(&aSyncSample->SyncSampleNo); 589 theSyncSampleArray[i] = aSyncSample; 590 } 591} 592 593char *STSSAtom::OnGetAtomName() 594{ 595 return "Sync Sample Atom"; 596} 597 598bool STSSAtom::IsSyncSample(uint32 pSampleNo) 599{ 600 601 for (uint32 i=0;i<theHeader.NoEntries;i++) { 602 if (theSyncSampleArray[i]->SyncSampleNo == pSampleNo) { 603 return true; 604 } 605 606 if (pSampleNo > theSyncSampleArray[i]->SyncSampleNo) { 607 return false; 608 } 609 } 610 611 return false; 612} 613 614STSZAtom::STSZAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 615{ 616 theHeader.NoEntries = 0; 617} 618 619STSZAtom::~STSZAtom() 620{ 621 for (uint32 i=0;i<theHeader.NoEntries;i++) { 622 delete theSampleSizeArray[i]; 623 theSampleSizeArray[i] = NULL; 624 } 625} 626 627void STSZAtom::OnProcessMetaData() 628{ 629SampleSizeEntry *aSampleSize; 630 631 // Just to make things difficult this is not quite a standard array header 632 Read(&theHeader.Version); 633 Read(&theHeader.Flags1); 634 Read(&theHeader.Flags2); 635 Read(&theHeader.Flags3); 636 Read(&theHeader.SampleSize); 637 Read(&theHeader.NoEntries); 638 639 // If the sample size is constant there is no array and NoEntries seems to contain bad values 640 if (theHeader.SampleSize == 0) { 641 for (uint32 i=0;i<theHeader.NoEntries;i++) { 642 aSampleSize = new SampleSizeEntry; 643 644 Read(&aSampleSize->EntrySize); 645 theSampleSizeArray[i] = aSampleSize; 646 } 647 } 648} 649 650char *STSZAtom::OnGetAtomName() 651{ 652 return "Sample Size Atom"; 653} 654 655uint32 STSZAtom::getSizeForSample(uint32 pSampleNo) 656{ 657 if (theHeader.SampleSize > 0) { 658 // All samples are the same size 659 return theHeader.SampleSize; 660 } 661 662 // Sample Array indexed by SampleNo 663 return theSampleSizeArray[pSampleNo]->EntrySize; 664} 665 666bool STSZAtom::IsSingleSampleSize() 667{ 668 return (theHeader.SampleSize > 0); 669} 670 671STCOAtom::STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 672{ 673 theHeader.NoEntries = 0; 674} 675 676STCOAtom::~STCOAtom() 677{ 678 for (uint32 i=0;i<theHeader.NoEntries;i++) { 679 delete theChunkToOffsetArray[i]; 680 theChunkToOffsetArray[i] = NULL; 681 } 682} 683 684uint64 STCOAtom::OnGetChunkOffset() 685{ 686 uint32 Offset; 687 688 Read(&Offset); 689 690 // Upconvert to uint64 691 return uint64(Offset); 692} 693 694void STCOAtom::OnProcessMetaData() 695{ 696ChunkToOffset *aChunkToOffset; 697 698 ReadArrayHeader(&theHeader); 699 700 for (uint32 i=0;i<theHeader.NoEntries;i++) { 701 aChunkToOffset = new ChunkToOffset; 702 703 aChunkToOffset->Offset = OnGetChunkOffset(); 704 705 theChunkToOffsetArray[i] = aChunkToOffset; 706 } 707 708 PRINT(("Chunk to Offset Array has %ld entries\n",theHeader.NoEntries)); 709} 710 711char *STCOAtom::OnGetAtomName() 712{ 713 return "Chunk to Offset Atom"; 714} 715 716uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID) 717{ 718 // First chunk is first array entry 719 if ((pChunkID > 0) && (pChunkID <= theHeader.NoEntries)) { 720 return theChunkToOffsetArray[pChunkID - 1]->Offset; 721 } 722 723 #if DEBUG 724 char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries); 725 DEBUGGER(msg); 726 #endif 727 728 TRESPASS(); 729 return 0LL; 730} 731 732ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 733{ 734 theVOL = NULL; 735} 736 737ESDSAtom::~ESDSAtom() 738{ 739 if (theVOL) { 740 free(theVOL); 741 } 742} 743 744void ESDSAtom::OnProcessMetaData() 745{ 746 theVOL = (uint8 *)(malloc(getBytesRemaining())); 747 Read(theVOL,getBytesRemaining()); 748} 749 750uint8 *ESDSAtom::getVOL() 751{ 752 return theVOL; 753} 754 755char *ESDSAtom::OnGetAtomName() 756{ 757 return "Extended Sample Description Atom"; 758} 759 760STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 761{ 762 theHeader.NoEntries = 0; 763} 764 765STSDAtom::~STSDAtom() 766{ 767 if (getMediaComponentSubType() == 'soun') { 768 for (uint32 i=0;i<theHeader.NoEntries;i++) { 769 if (theAudioDescArray[i]->theVOL) { 770 free(theAudioDescArray[i]->theVOL); 771 theAudioDescArray[i]->theVOL = NULL; 772 } 773 774 delete theAudioDescArray[i]; 775 theAudioDescArray[i] = NULL; 776 } 777 } else if (getMediaComponentSubType() == 'vide') { 778 for (uint32 i=0;i<theHeader.NoEntries;i++) { 779 if (theVideoDescArray[i]->theVOL) { 780 free(theVideoDescArray[i]->theVOL); 781 theVideoDescArray[i]->theVOL = NULL; 782 } 783 784 delete theVideoDescArray[i]; 785 theVideoDescArray[i] = NULL; 786 } 787 } 788} 789 790uint32 STSDAtom::getMediaComponentSubType() 791{ 792 return dynamic_cast<STBLAtom *>(getParent())->getMediaComponentSubType(); 793} 794 795void STSDAtom::ReadSoundDescription() 796{ 797 uint64 descBytesLeft; 798 799 SoundDescriptionV1 *aSoundDescriptionV1; 800 801 aSoundDescriptionV1 = new SoundDescriptionV1; 802 Read(&aSoundDescriptionV1->basefields.Size); 803 Read(&aSoundDescriptionV1->basefields.DataFormat); 804 Read(aSoundDescriptionV1->basefields.Reserved,6); 805 Read(&aSoundDescriptionV1->basefields.DataReference); 806 807 aSoundDescriptionV1->VOLSize = 0; 808 aSoundDescriptionV1->theVOL = NULL; 809 810 // Read in Audio Sample Data 811 // We place into a V1 description even though it might be a V0 or earlier 812 813 Read(&aSoundDescriptionV1->desc.Version); 814 Read(&aSoundDescriptionV1->desc.Revision); 815 Read(&aSoundDescriptionV1->desc.Vendor); 816 Read(&aSoundDescriptionV1->desc.NoOfChannels); 817 Read(&aSoundDescriptionV1->desc.SampleSize); 818 Read(&aSoundDescriptionV1->desc.CompressionID); 819 Read(&aSoundDescriptionV1->desc.PacketSize); 820 Read(&aSoundDescriptionV1->desc.SampleRate); 821 822 if ((aSoundDescriptionV1->desc.Version == 1) && (aSoundDescriptionV1->basefields.DataFormat != AUDIO_IMA4)) { 823 Read(&(aSoundDescriptionV1->samplesPerPacket)); 824 Read(&(aSoundDescriptionV1->bytesPerPacket)); 825 Read(&(aSoundDescriptionV1->bytesPerFrame)); 826 Read(&(aSoundDescriptionV1->bytesPerSample)); 827 828 } else { 829 // Calculate? 830 if (aSoundDescriptionV1->basefields.DataFormat == AUDIO_IMA4) { 831 aSoundDescriptionV1->samplesPerPacket = 64; 832 aSoundDescriptionV1->bytesPerFrame = aSoundDescriptionV1->desc.NoOfChannels * 34; 833 834 aSoundDescriptionV1->bytesPerSample = aSoundDescriptionV1->desc.SampleSize / 8; 835 aSoundDescriptionV1->bytesPerPacket = 64 * aSoundDescriptionV1->bytesPerFrame; 836 } else { 837 aSoundDescriptionV1->bytesPerSample = aSoundDescriptionV1->desc.SampleSize / 8; 838 aSoundDescriptionV1->bytesPerFrame = aSoundDescriptionV1->desc.NoOfChannels * aSoundDescriptionV1->bytesPerSample; 839 aSoundDescriptionV1->bytesPerPacket = aSoundDescriptionV1->desc.PacketSize; 840 aSoundDescriptionV1->samplesPerPacket = aSoundDescriptionV1->desc.PacketSize / aSoundDescriptionV1->bytesPerFrame; 841 } 842 } 843 844 // 0 means we dont have one 845 aSoundDescriptionV1->theWaveFormat.format_tag = 0; 846 847 descBytesLeft = getBytesRemaining(); 848 849 while (descBytesLeft > 0) { 850 851 // More extended atoms 852 AtomBase *aAtomBase = getAtom(theStream); 853 854 aAtomBase->OnProcessMetaData(); 855 printf("%s\n",aAtomBase->getAtomName()); 856 857 if (dynamic_cast<WAVEAtom *>(aAtomBase)) { 858 // WAVE atom 859 aSoundDescriptionV1->theWaveFormat = dynamic_cast<WAVEAtom *>(aAtomBase)->getWaveFormat(); 860 } 861 862 if (dynamic_cast<ESDSAtom *>(aAtomBase)) { 863 // ESDS atom good 864 aSoundDescriptionV1->VOLSize = aAtomBase->getDataSize(); 865 aSoundDescriptionV1->theVOL = (uint8 *)(malloc(aSoundDescriptionV1->VOLSize)); 866 memcpy(aSoundDescriptionV1->theVOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(),aSoundDescriptionV1->VOLSize); 867 } 868 869 if ((aAtomBase->getAtomSize() > 0) && (descBytesLeft >= aAtomBase->getAtomSize())) { 870 descBytesLeft = descBytesLeft - aAtomBase->getAtomSize(); 871 } else { 872 DEBUGGER("Invalid Atom found when reading Sound Description\n"); 873 descBytesLeft = 0; 874 } 875 876 delete aAtomBase; 877 } 878 879 theAudioDescArray[0] = aSoundDescriptionV1; 880 881 PRINT(("Size:Format=%ld:%ld %Ld\n",aSoundDescriptionV1->basefields.Size,aSoundDescriptionV1->basefields.DataFormat,descBytesLeft)); 882} 883 884void STSDAtom::ReadVideoDescription() 885{ 886 uint64 descBytesLeft; 887 888 // read in Video Sample Data 889 VideoDescriptionV0 *aVideoDescription; 890 891 aVideoDescription = new VideoDescriptionV0; 892 893 Read(&aVideoDescription->basefields.Size); 894 Read(&aVideoDescription->basefields.DataFormat); 895 Read(aVideoDescription->basefields.Reserved,6); 896 Read(&aVideoDescription->basefields.DataReference); 897 898 Read(&aVideoDescription->desc.Version); 899 Read(&aVideoDescription->desc.Revision); 900 Read(&aVideoDescription->desc.Vendor); 901 Read(&aVideoDescription->desc.TemporaralQuality); 902 Read(&aVideoDescription->desc.SpacialQuality); 903 Read(&aVideoDescription->desc.Width); 904 Read(&aVideoDescription->desc.Height); 905 Read(&aVideoDescription->desc.HorizontalResolution); 906 Read(&aVideoDescription->desc.VerticalResolution); 907 Read(&aVideoDescription->desc.DataSize); 908 // FrameCount is actually No of Frames per Sample which is usually 1 909 Read(&aVideoDescription->desc.FrameCount); 910 Read(aVideoDescription->desc.CompressorName,32); 911 Read(&aVideoDescription->desc.Depth); 912 Read(&aVideoDescription->desc.ColourTableID); 913 914 aVideoDescription->VOLSize = 0; 915 aVideoDescription->theVOL = NULL; 916 917 theVideoDescArray[0] = aVideoDescription; 918 919 descBytesLeft = getBytesRemaining(); 920 921 // May be a VOL 922 // If not then seek back to where we are as it may be a complete new video description 923 924 if (descBytesLeft > 0) { 925 926 off_t pos = theStream->Position(); 927 // More extended atoms 928 AtomBase *aAtomBase = getAtom(theStream); 929 930 aAtomBase->OnProcessMetaData(); 931 printf("%s\n",aAtomBase->getAtomName()); 932 933 if (dynamic_cast<ESDSAtom *>(aAtomBase)) { 934 // ESDS atom good 935 aVideoDescription->VOLSize = aAtomBase->getDataSize(); 936 aVideoDescription->theVOL = (uint8 *)(malloc(aVideoDescription->VOLSize)); 937 memcpy(aVideoDescription->theVOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(),aVideoDescription->VOLSize); 938 } else { 939 // Seek Back 940 theStream->Seek(pos,SEEK_SET); 941 } 942 943 delete aAtomBase; 944 } 945 946 PRINT(("Size:Format=%ld:%ld %Ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,getBytesRemaining())); 947} 948 949void STSDAtom::OnProcessMetaData() 950{ 951 ReadArrayHeader(&theHeader); 952 953 for (uint32 i=0;i<theHeader.NoEntries;i++) { 954 955 switch (getMediaComponentSubType()) { 956 case 'soun': 957 ReadSoundDescription(); 958 break; 959 case 'vide': 960 ReadVideoDescription(); 961 break; 962 default: 963 // Skip 964 SampleDescBase aSampleDescBase; 965 Read(&aSampleDescBase.Size); 966 Read(&aSampleDescBase.DataFormat); 967 Read(aSampleDescBase.Reserved,6); 968 Read(&aSampleDescBase.DataReference); 969 970 printf("%c%c%c%c\n",char(aSampleDescBase.DataFormat>>24),char(aSampleDescBase.DataFormat>>16),char(aSampleDescBase.DataFormat>>8),char(aSampleDescBase.DataFormat)); 971 972 theStream->Seek(aSampleDescBase.Size - SampleDescBaseSize, SEEK_CUR); 973 break; 974 } 975 } 976} 977 978VideoDescriptionV0 STSDAtom::getAsVideo() 979{ 980 // Assert IsVideo - how will we handle multiples 981 return *theVideoDescArray[0]; 982} 983 984SoundDescriptionV1 STSDAtom::getAsAudio() 985{ 986 // Assert IsAudio - how will we handle multiples 987 return *theAudioDescArray[0]; 988} 989 990char *STSDAtom::OnGetAtomName() 991{ 992 return "Sample Description Atom"; 993} 994 995WAVEAtom::WAVEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 996{ 997} 998 999WAVEAtom::~WAVEAtom() 1000{ 1001} 1002 1003void WAVEAtom::OnProcessMetaData() 1004{ 1005 // This should be in LITTLE ENDIAN DATA 1006 theStream->Read(&theWaveFormat.format_tag,sizeof(uint16)); 1007 theStream->Read(&theWaveFormat.channels,sizeof(uint16)); 1008 theStream->Read(&theWaveFormat.frames_per_sec,sizeof(uint32)); 1009 theStream->Read(&theWaveFormat.avg_bytes_per_sec,sizeof(uint32)); 1010 theStream->Read(&theWaveFormat.block_align,sizeof(uint16)); 1011 theStream->Read(&theWaveFormat.bits_per_sample,sizeof(uint16)); 1012 theStream->Read(&theWaveFormat.extra_size,sizeof(uint16)); 1013 1014 theWaveFormat.format_tag = B_LENDIAN_TO_HOST_INT16(theWaveFormat.format_tag); 1015 theWaveFormat.channels = B_LENDIAN_TO_HOST_INT16(theWaveFormat.channels); 1016 theWaveFormat.frames_per_sec = B_LENDIAN_TO_HOST_INT32(theWaveFormat.frames_per_sec); 1017 theWaveFormat.avg_bytes_per_sec = B_LENDIAN_TO_HOST_INT32(theWaveFormat.avg_bytes_per_sec); 1018 theWaveFormat.block_align = B_LENDIAN_TO_HOST_INT16(theWaveFormat.block_align); 1019 theWaveFormat.bits_per_sample = B_LENDIAN_TO_HOST_INT16(theWaveFormat.bits_per_sample); 1020 theWaveFormat.extra_size = B_LENDIAN_TO_HOST_INT16(theWaveFormat.extra_size); 1021} 1022 1023char *WAVEAtom::OnGetAtomName() 1024{ 1025 return "WAVE structure Atom"; 1026} 1027 1028TMCDAtom::TMCDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1029{ 1030} 1031 1032TMCDAtom::~TMCDAtom() 1033{ 1034} 1035 1036void TMCDAtom::OnProcessMetaData() 1037{ 1038} 1039 1040char *TMCDAtom::OnGetAtomName() 1041{ 1042 return "TimeCode Atom"; 1043} 1044 1045WIDEAtom::WIDEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1046{ 1047} 1048 1049WIDEAtom::~WIDEAtom() 1050{ 1051} 1052 1053void WIDEAtom::OnProcessMetaData() 1054{ 1055} 1056 1057char *WIDEAtom::OnGetAtomName() 1058{ 1059 return "WIDE Atom"; 1060} 1061 1062FREEAtom::FREEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1063{ 1064} 1065 1066FREEAtom::~FREEAtom() 1067{ 1068} 1069 1070void FREEAtom::OnProcessMetaData() 1071{ 1072} 1073 1074char *FREEAtom::OnGetAtomName() 1075{ 1076 return "Free Atom"; 1077} 1078 1079PNOTAtom::PNOTAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1080{ 1081} 1082 1083PNOTAtom::~PNOTAtom() 1084{ 1085} 1086 1087void PNOTAtom::OnProcessMetaData() 1088{ 1089} 1090 1091char *PNOTAtom::OnGetAtomName() 1092{ 1093 return "Preview Atom"; 1094} 1095 1096SKIPAtom::SKIPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1097{ 1098} 1099 1100SKIPAtom::~SKIPAtom() 1101{ 1102} 1103 1104void SKIPAtom::OnProcessMetaData() 1105{ 1106} 1107 1108char *SKIPAtom::OnGetAtomName() 1109{ 1110 return "Skip Atom"; 1111} 1112 1113MDATAtom::MDATAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1114{ 1115} 1116 1117MDATAtom::~MDATAtom() 1118{ 1119} 1120 1121void MDATAtom::OnProcessMetaData() 1122{ 1123} 1124 1125char *MDATAtom::OnGetAtomName() 1126{ 1127 return "Media Data Atom"; 1128} 1129 1130off_t MDATAtom::getEOF() 1131{ 1132 return getStreamOffset() + getAtomSize(); 1133} 1134 1135MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 1136{ 1137} 1138 1139MINFAtom::~MINFAtom() 1140{ 1141} 1142 1143void MINFAtom::OnProcessMetaData() 1144{ 1145} 1146 1147char *MINFAtom::OnGetAtomName() 1148{ 1149 return "Quicktime Media Information Atom"; 1150} 1151 1152uint32 MINFAtom::getMediaComponentSubType() 1153{ 1154 return dynamic_cast<MDIAAtom *>(getParent())->getMediaComponentSubType(); 1155} 1156 1157STBLAtom::STBLAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 1158{ 1159} 1160 1161STBLAtom::~STBLAtom() 1162{ 1163} 1164 1165void STBLAtom::OnProcessMetaData() 1166{ 1167} 1168 1169char *STBLAtom::OnGetAtomName() 1170{ 1171 return "Quicktime Sample Table Atom"; 1172} 1173 1174uint32 STBLAtom::getMediaComponentSubType() 1175{ 1176 return dynamic_cast<MINFAtom *>(getParent())->getMediaComponentSubType(); 1177} 1178 1179DINFAtom::DINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 1180{ 1181} 1182 1183DINFAtom::~DINFAtom() 1184{ 1185} 1186 1187void DINFAtom::OnProcessMetaData() 1188{ 1189} 1190 1191char *DINFAtom::OnGetAtomName() 1192{ 1193 return "Quicktime Data Information Atom"; 1194} 1195 1196TKHDAtom::TKHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1197{ 1198} 1199 1200TKHDAtom::~TKHDAtom() 1201{ 1202} 1203 1204void TKHDAtom::OnProcessMetaData() 1205{ 1206 Read(&Version); 1207 1208 if (Version == 0) { 1209 // Read into V0 header and convert to V1 Header 1210 tkhdV0 aHeaderV0; 1211 1212 Read(&aHeaderV0.Flags1); 1213 Read(&aHeaderV0.Flags2); 1214 Read(&aHeaderV0.Flags3); 1215 Read(&aHeaderV0.CreationTime); 1216 Read(&aHeaderV0.ModificationTime); 1217 Read(&aHeaderV0.TrackID); 1218 Read(&aHeaderV0.Reserved1); 1219 Read(&aHeaderV0.Duration); 1220 Read(&aHeaderV0.Reserved2); 1221 Read(&aHeaderV0.Layer); 1222 Read(&aHeaderV0.AlternateGroup); 1223 Read(&aHeaderV0.Volume); 1224 Read(&aHeaderV0.Reserved3); 1225 Read(aHeaderV0.MatrixStructure,36); 1226 Read(&aHeaderV0.TrackWidth); 1227 Read(&aHeaderV0.TrackHeight); 1228 1229 theHeader.Flags1 = aHeaderV0.Flags1; 1230 theHeader.Flags2 = aHeaderV0.Flags2; 1231 theHeader.Flags3 = aHeaderV0.Flags3; 1232 theHeader.Reserved1 = aHeaderV0.Reserved1; 1233 theHeader.Reserved2 = aHeaderV0.Reserved2; 1234 theHeader.Reserved3 = aHeaderV0.Reserved3; 1235 1236 for (uint32 i=0;i<36;i++) { 1237 theHeader.MatrixStructure[i] = aHeaderV0.MatrixStructure[i]; 1238 } 1239 1240 // upconvert to V1 header 1241 theHeader.CreationTime = uint64(aHeaderV0.CreationTime); 1242 theHeader.ModificationTime = uint64(aHeaderV0.ModificationTime); 1243 theHeader.TrackID = aHeaderV0.TrackID; 1244 theHeader.Duration = aHeaderV0.Duration; 1245 theHeader.Layer = aHeaderV0.Layer; 1246 theHeader.AlternateGroup = aHeaderV0.AlternateGroup; 1247 theHeader.Volume = aHeaderV0.Volume; 1248 theHeader.TrackWidth = aHeaderV0.TrackWidth; 1249 theHeader.TrackHeight = aHeaderV0.TrackHeight; 1250 1251 } else { 1252 // Read direct into V1 Header 1253 Read(&theHeader.Flags1); 1254 Read(&theHeader.Flags2); 1255 Read(&theHeader.Flags3); 1256 Read(&theHeader.CreationTime); 1257 Read(&theHeader.ModificationTime); 1258 Read(&theHeader.TrackID); 1259 Read(&theHeader.Reserved1); 1260 Read(&theHeader.Duration); 1261 Read(&theHeader.Reserved2); 1262 Read(&theHeader.Layer); 1263 Read(&theHeader.AlternateGroup); 1264 Read(&theHeader.Volume); 1265 Read(&theHeader.Reserved3); 1266 Read(theHeader.MatrixStructure,36); 1267 Read(&theHeader.TrackWidth); 1268 Read(&theHeader.TrackHeight); 1269 } 1270 1271} 1272 1273char *TKHDAtom::OnGetAtomName() 1274{ 1275 return "Quicktime Track Header"; 1276} 1277 1278MDIAAtom::MDIAAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) 1279{ 1280} 1281 1282MDIAAtom::~MDIAAtom() 1283{ 1284} 1285 1286void MDIAAtom::OnProcessMetaData() 1287{ 1288} 1289 1290char *MDIAAtom::OnGetAtomName() 1291{ 1292 return "Quicktime Media Atom"; 1293} 1294 1295uint32 MDIAAtom::getMediaComponentSubType() 1296{ 1297 // get child atom hdlr 1298 HDLRAtom *aHDLRAtom; 1299 aHDLRAtom = dynamic_cast<HDLRAtom *>(GetChildAtom(uint32('hdlr'))); 1300 1301 if (aHDLRAtom) { 1302 return aHDLRAtom->getMediaComponentSubType(); 1303 } 1304 1305 return 0; 1306} 1307 1308MDHDAtom::MDHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1309{ 1310} 1311 1312MDHDAtom::~MDHDAtom() 1313{ 1314} 1315 1316void MDHDAtom::OnProcessMetaData() 1317{ 1318 Read(&theHeader.Version); 1319 Read(&theHeader.Flags1); 1320 Read(&theHeader.Flags2); 1321 Read(&theHeader.Flags3); 1322 Read(&theHeader.CreationTime); 1323 Read(&theHeader.ModificationTime); 1324 Read(&theHeader.TimeScale); 1325 Read(&theHeader.Duration); 1326 Read(&theHeader.Language); 1327 Read(&theHeader.Quality); 1328} 1329 1330char *MDHDAtom::OnGetAtomName() 1331{ 1332 return "Quicktime Media Header"; 1333} 1334 1335bigtime_t MDHDAtom::getDuration() 1336{ 1337 return bigtime_t((uint64(theHeader.Duration) * 1000000L) / theHeader.TimeScale); 1338} 1339 1340uint32 MDHDAtom::getTimeScale() 1341{ 1342 return theHeader.TimeScale; 1343} 1344 1345HDLRAtom::HDLRAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1346{ 1347} 1348 1349HDLRAtom::~HDLRAtom() 1350{ 1351} 1352 1353void HDLRAtom::OnProcessMetaData() 1354{ 1355 Read(&theHeader.Version); 1356 Read(&theHeader.Flags1); 1357 Read(&theHeader.Flags2); 1358 Read(&theHeader.Flags3); 1359 Read(&theHeader.ComponentType); 1360 Read(&theHeader.ComponentSubType); 1361 Read(&theHeader.ComponentManufacturer); 1362 Read(&theHeader.ComponentFlags); 1363 Read(&theHeader.ComponentFlagsMask); 1364 1365 // Read Array of Strings? 1366} 1367 1368char *HDLRAtom::OnGetAtomName() 1369{ 1370 return "Quicktime Handler Reference Atom "; 1371} 1372 1373bool HDLRAtom::IsVideoHandler() 1374{ 1375 return (theHeader.ComponentSubType == 'vide'); 1376} 1377 1378bool HDLRAtom::IsAudioHandler() 1379{ 1380 return (theHeader.ComponentSubType == 'soun'); 1381} 1382 1383uint32 HDLRAtom::getMediaComponentSubType() 1384{ 1385 return theHeader.ComponentSubType; 1386} 1387 1388VMHDAtom::VMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1389{ 1390} 1391 1392VMHDAtom::~VMHDAtom() 1393{ 1394} 1395 1396void VMHDAtom::OnProcessMetaData() 1397{ 1398 vmhd aHeader; 1399 Read(&aHeader.Version); 1400 Read(&aHeader.Flags1); 1401 Read(&aHeader.Flags2); 1402 Read(&aHeader.Flags3); 1403 Read(&aHeader.GraphicsMode); 1404 Read(&aHeader.OpColourRed); 1405 Read(&aHeader.OpColourGreen); 1406 Read(&aHeader.OpColourBlue); 1407} 1408 1409char *VMHDAtom::OnGetAtomName() 1410{ 1411 return "Quicktime Video Media Header"; 1412} 1413 1414SMHDAtom::SMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1415{ 1416} 1417 1418SMHDAtom::~SMHDAtom() 1419{ 1420} 1421 1422void SMHDAtom::OnProcessMetaData() 1423{ 1424 smhd aHeader; 1425 Read(&aHeader.Version); 1426 Read(&aHeader.Flags1); 1427 Read(&aHeader.Flags2); 1428 Read(&aHeader.Flags3); 1429 Read(&aHeader.Balance); 1430 Read(&aHeader.Reserved); 1431} 1432 1433char *SMHDAtom::OnGetAtomName() 1434{ 1435 return "Quicktime Sound Media Header"; 1436} 1437 1438FTYPAtom::FTYPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) 1439{ 1440} 1441 1442FTYPAtom::~FTYPAtom() 1443{ 1444} 1445 1446void FTYPAtom::OnProcessMetaData() 1447{ 1448// ftyp is really an mp4 thing, but some mov encoders are adding it anyway. 1449// but a mov file with an ftyp should define a brand of qt (I think) 1450 1451 Read(&major_brand); 1452 Read(&minor_version); 1453 1454 total_brands = getBytesRemaining() / sizeof(uint32); 1455 1456 if (total_brands > 32) { 1457 total_brands = 32; // restrict to 32 1458 } 1459 1460 for (uint32 i=0;i<total_brands;i++) { 1461 Read(&compatable_brands[i]); 1462 } 1463} 1464 1465char *FTYPAtom::OnGetAtomName() 1466{ 1467 return "Quicktime File Type"; 1468} 1469 1470bool FTYPAtom::HasBrand(uint32 brand) 1471{ 1472 // return true if the specified brand is in the list 1473 1474 if (major_brand == brand) { 1475 return true; 1476 } 1477 1478 for (uint32 i=0;i<total_brands;i++) { 1479 if (compatable_brands[i] == brand) { 1480 return true; 1481 } 1482 } 1483 1484 return false; 1485} 1486