diff --git a/src/add-ons/media/plugins/mov_reader/TODO b/src/add-ons/media/plugins/mov_reader/TODO index c40123dfb3..2d9929551c 100644 --- a/src/add-ons/media/plugins/mov_reader/TODO +++ b/src/add-ons/media/plugins/mov_reader/TODO @@ -4,5 +4,5 @@ Quicktime Reader TODO KNOWN ISSUES Edits lists are ignored the track is played start to finish regardless of edit lists -MP3 sound tracks create a noise at irregular intervals (too little data supplied to decoder?) -IMA4 sound tracks repeat (no idea) \ No newline at end of file +IMA4 sound tracks stop too early +Seeking will not work for compressed audio \ No newline at end of file diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.cpp new file mode 100644 index 0000000000..3c7328b200 --- /dev/null +++ b/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2005, David McPaul + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ChunkSuperIndex.h" + +ChunkSuperIndex::ChunkSuperIndex() +{ +} + +ChunkSuperIndex::~ChunkSuperIndex() +{ + theChunkIndexArray.erase(theChunkIndexArray.begin(),theChunkIndexArray.end()); +} + +void ChunkSuperIndex::AddChunkIndex(uint32 stream, uint32 chunkid, off_t chunk_start) +{ + ChunkIndexPtr aChunkIndexPtr; + aChunkIndexPtr = new ChunkIndex; + aChunkIndexPtr->stream = stream; + aChunkIndexPtr->chunkid = chunkid; + aChunkIndexPtr->chunk_start = chunk_start; + + theChunkIndexArray[chunk_start] = aChunkIndexPtr; +} + +uint32 ChunkSuperIndex::getChunkSize(uint32 stream, uint32 chunkid, off_t chunk_start) +{ + ChunkIndexPtr aChunkIndexPtr = theChunkIndexArray[chunk_start]; + + if (aChunkIndexPtr) { + // Find next chunkIndex + ChunkIndexPtr nextChunkIndex; + + nextChunkIndex = theChunkIndexArray.upper_bound(chunk_start)->second; + + // Assert stream + // Assert chunkid + return (nextChunkIndex->chunk_start - aChunkIndexPtr->chunk_start); + } + + return 0; +} diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.h b/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.h new file mode 100644 index 0000000000..bf5ba955b0 --- /dev/null +++ b/src/add-ons/media/plugins/mov_reader/libMOV/ChunkSuperIndex.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005, David McPaul + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _CHUNK_INDEX_H +#define _CHUNK_INDEX_H + +#include + +// Std Headers +#include + +struct ChunkIndex { + uint32 stream; + uint32 chunkid; + off_t chunk_start; +}; + +typedef ChunkIndex* ChunkIndexPtr; +typedef std::map > ChunkIndexArray; + +class ChunkSuperIndex { +public: + ChunkSuperIndex(); + virtual ~ChunkSuperIndex(); + + void AddChunkIndex(uint32 stream, uint32 chunkid, off_t chunk_start); + uint32 getChunkSize(uint32 stream, uint32 chunkid, off_t chunk_start); + +private: + ChunkIndexArray theChunkIndexArray; +}; + +#endif // _CHUNK_INDEX_H diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/Jamfile b/src/add-ons/media/plugins/mov_reader/libMOV/Jamfile index 94ef72f252..65a0d13c5b 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/Jamfile +++ b/src/add-ons/media/plugins/mov_reader/libMOV/Jamfile @@ -5,4 +5,5 @@ StaticLibrary movreader : MOVFileReader.cpp MOVAtom.cpp MOVTrakAtom.cpp + ChunkSuperIndex.cpp ; diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h index 16d6628953..dd86b2e6f9 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVAtom.h @@ -101,6 +101,8 @@ public: uint64 getAtomSize() {return atomSize;}; uint32 getAtomType() {return atomType;}; + off_t getAtomOffset() {return atomOffset;}; + off_t getStreamOffset() {return streamOffset;}; uint64 getBytesRemaining(); diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp index e21d5ea5bb..4ae04f824f 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp @@ -39,6 +39,7 @@ MOVFileReader::MOVFileReader(BPositionIO *pStream) // Find Size of Stream, need to rethink this for non seekable streams theStream->Seek(0,SEEK_END); StreamSize = theStream->Position(); + theStream->Seek(0,SEEK_SET); TotalChildren = 0; @@ -51,6 +52,19 @@ MOVFileReader::~MOVFileReader() theMVHDAtom = NULL; } +bool MOVFileReader::IsEndOfData(off_t pPosition) +{ +AtomBase *aAtomBase; + + aAtomBase = GetChildAtom(uint32('mdat'),0); + if (aAtomBase) { + MDATAtom *aMdatAtom = dynamic_cast(aAtomBase); + return pPosition >= aMdatAtom->getEOF(); + } + + return true; +} + bool MOVFileReader::IsEndOfFile(off_t pPosition) { return (pPosition >= StreamSize); @@ -332,6 +346,28 @@ uint64 MOVFileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo) return 0; } +void MOVFileReader::BuildSuperIndex() +{ +AtomBase *aAtomBase; + + for (uint32 stream=0;stream(aAtomBase); + for (uint32 chunkid=1;chunkid<=aTrakAtom->getTotalChunks();chunkid++) { + theChunkSuperIndex.AddChunkIndex(stream,chunkid,aTrakAtom->getOffsetForChunk(chunkid)); + } + } + } + + // Add end of file to index + aAtomBase = GetChildAtom(uint32('mdat'),0); + if (aAtomBase) { + MDATAtom *aMdatAtom = dynamic_cast(aAtomBase); + theChunkSuperIndex.AddChunkIndex(0,0,aMdatAtom->getEOF()); + } +} + status_t MOVFileReader::ParseFile() { AtomBase *aChild; @@ -347,6 +383,8 @@ status_t MOVFileReader::ParseFile() atomChildren[i]->DisplayAtoms(); } + BuildSuperIndex(); + return B_OK; } @@ -514,22 +552,29 @@ uint32 MOVFileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo) if (IsAudio(stream_index)) { // We read audio in chunk by chunk so chunk size is chunk size - uint32 ChunkNo = pFrameNo; - + uint32 ChunkNo = pFrameNo; + off_t Chunk_Start = aTrakAtom->getOffsetForChunk(ChunkNo); + uint32 ChunkSize = ChunkSize = theChunkSuperIndex.getChunkSize(stream_index,ChunkNo,Chunk_Start); + uint32 NoSamples = aTrakAtom->getNoSamplesInChunk(ChunkNo); + uint32 TotalSampleSize = 0; + // Get first sample in chunk uint32 SampleNo = aTrakAtom->getFirstSampleInChunk(ChunkNo); - uint32 ChunkSize = 0; if (aTrakAtom->IsSingleSampleSize()) { - ChunkSize = aTrakAtom->getNoSamplesInChunk(ChunkNo) * aTrakAtom->getSizeForSample(SampleNo); + TotalSampleSize = NoSamples * aTrakAtom->getSizeForSample(SampleNo); } else { // Add up all sample sizes in chunk - for (uint32 i=0;igetNoSamplesInChunk(ChunkNo);i++) { - ChunkSize += aTrakAtom->getSizeForSample(SampleNo); + for (uint32 i=0;igetSizeForSample(SampleNo); SampleNo++; } } + TotalSampleSize = TotalSampleSize * aTrakAtom->getBytesPerSample(); + +// printf("[%ld] start %lld, size %ld NoSamples %ld TotalSampleSize %ld\n",ChunkNo,Chunk_Start,ChunkSize,NoSamples,TotalSampleSize); + return ChunkSize; } @@ -568,7 +613,7 @@ bool MOVFileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *keyframe = IsKeyFrame(stream_index, pFrameNo); } - return ((*start > 0) && (*size > 0) && !(IsEndOfFile(*start))); + return ((*start > 0) && (*size > 0) && !(IsEndOfFile(*start + *size)) && !(IsEndOfData(*start + *size))); } bool MOVFileReader::IsActive(uint32 stream_index) diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h index dcae47c293..1e1f6a10a8 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h @@ -31,6 +31,7 @@ #include #include "MOVParser.h" +#include "ChunkSuperIndex.h" // QT MOV file reader (and maybe MP4 as well) class MOVFileReader { @@ -56,6 +57,10 @@ private: MVHDAtom *theMVHDAtom; + ChunkSuperIndex theChunkSuperIndex; + + void BuildSuperIndex(); + public: MOVFileReader(BPositionIO *pStream); virtual ~MOVFileReader(); @@ -65,6 +70,7 @@ public: bool IsEndOfFile(off_t pPosition); bool IsEndOfFile(); + bool IsEndOfData(off_t pPosition); // Is this a quicktime file static bool IsSupported(BPositionIO *source); diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp index 72fc8e877c..77a743e82d 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp @@ -516,11 +516,12 @@ uint32 STSCAtom::getNoSamplesInChunk(uint32 pChunkID) { for (uint32 i=0;iFirstChunk > pChunkID) { +// printf("Chunk %ld contains %ld samples\n",pChunkID, theSampleToChunkArray[i-1]->SamplesPerChunk); return theSampleToChunkArray[i-1]->SamplesPerChunk; } } - return 0; + return theSampleToChunkArray[theHeader.NoEntries-1]->SamplesPerChunk; } uint32 STSCAtom::getFirstSampleInChunk(uint32 pChunkID) @@ -646,6 +647,7 @@ SampleSize *aSampleSize; char *STSZAtom::OnGetAtomName() { + printf("%ld ",theHeader.SampleSize); return "Sample Size Atom"; } @@ -720,7 +722,7 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID) DEBUGGER(("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries)); TRESPASS(); - return theChunkToOffsetArray[0]->Offset; + return -1LL; } STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) @@ -779,6 +781,7 @@ void STSDAtom::ReadSoundDescription() aSoundDescriptionV1->desc.SampleRate = B_BENDIAN_TO_HOST_INT32(aSoundDescriptionV1->desc.SampleRate); if (aSoundDescriptionV1->desc.Version == 1) { + printf("V1 Sound\n"); theStream->Read(&(aSoundDescriptionV1->samplesPerPacket),4); theStream->Read(&(aSoundDescriptionV1->bytesPerPacket),4); theStream->Read(&(aSoundDescriptionV1->bytesPerFrame),4); @@ -791,11 +794,17 @@ void STSDAtom::ReadSoundDescription() descBytesLeft = descBytesLeft - 16; } else { + printf("V0 Sound\n"); // Calculate? - aSoundDescriptionV1->samplesPerPacket = 0; - aSoundDescriptionV1->bytesPerPacket = 0; - aSoundDescriptionV1->bytesPerFrame = 0; - aSoundDescriptionV1->bytesPerSample = 0; + aSoundDescriptionV1->bytesPerSample = aSoundDescriptionV1->desc.SampleSize / 8; + if (aSoundDescriptionV1->basefields.DataFormat == 'ima4') { + printf("IMA4\n"); + aSoundDescriptionV1->bytesPerFrame = aSoundDescriptionV1->desc.NoOfChannels * 64 / 34; + } else { + aSoundDescriptionV1->bytesPerFrame = aSoundDescriptionV1->desc.NoOfChannels * aSoundDescriptionV1->bytesPerSample; + } + aSoundDescriptionV1->bytesPerPacket = aSoundDescriptionV1->desc.PacketSize; + aSoundDescriptionV1->samplesPerPacket = aSoundDescriptionV1->desc.PacketSize / aSoundDescriptionV1->bytesPerFrame; } // 0 means we dont have one @@ -1043,6 +1052,11 @@ char *MDATAtom::OnGetAtomName() return "Media Data Atom"; } +off_t MDATAtom::getEOF() +{ + return getStreamOffset() + getAtomSize(); +} + MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize) { } diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h index 56a6f24f30..34c1312c81 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h @@ -194,6 +194,7 @@ public: char *OnGetAtomName(); uint64 getOffsetForChunk(uint32 pChunkID); + uint32 getTotalChunks() {return theHeader.NoEntries;}; protected: // Read a single chunk offset from Stream @@ -250,7 +251,7 @@ public: virtual ~MDATAtom(); void OnProcessMetaData(); char *OnGetAtomName(); - + off_t getEOF(); }; // Atom class for reading the sdst atom @@ -361,10 +362,14 @@ public: uint32 getFirstSampleInChunk(uint32 pChunkID); uint32 getSizeForSample(uint32 pSample); uint32 getNoSamplesInChunk(uint32 pChunkID); + uint32 getTotalChunks(); + bool IsSyncSample(uint32 pSampleNo); bool IsSingleSampleSize(); bool IsActive(); + uint32 getBytesPerSample(); + TKHDAtom *getTKHDAtom(); MDHDAtom *getMDHDAtom(); private: @@ -372,6 +377,7 @@ private: MDHDAtom *theMDHDAtom; uint32 framecount; + uint32 bytespersample; }; // Atom class for reading the media container atom diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp index 570d134dc4..64eb3c9069 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp @@ -29,6 +29,7 @@ TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, theTKHDAtom = NULL; theMDHDAtom = NULL; framecount = 0; + bytespersample = 0; } TRAKAtom::~TRAKAtom() @@ -226,5 +227,41 @@ bool TRAKAtom::IsActive() return getTKHDAtom()->IsActive(); } +uint32 TRAKAtom::getBytesPerSample() +{ +AtomBase *aAtomBase; + + if (bytespersample > 0) { + return bytespersample; + } + + // calculate bytes per frame and cache it + + if (IsAudio()) { + // only used by Audio + aAtomBase = GetChildAtom(uint32('stsd'),0); + if (aAtomBase) { + STSDAtom *aSTSDAtom = dynamic_cast(aAtomBase); + + SoundDescriptionV1 aSoundDescription = aSTSDAtom->getAsAudio(); + + bytespersample = aSoundDescription.bytesPerSample; + } + } + + return bytespersample; +} + +uint32 TRAKAtom::getTotalChunks() +{ + AtomBase *aAtomBase = GetChildAtom(uint32('stco'),0); + + if (aAtomBase) { + return (dynamic_cast(aAtomBase))->getTotalChunks(); + } + + return 0; +} + // GetAudioMetaData() // If this is a audio track get the audio meta data // GetVideoMetaData() // If this is a video track get the video meta data