diff --git a/src/add-ons/media/plugins/avcodec/avcodec.cpp b/src/add-ons/media/plugins/avcodec/avcodec.cpp index c2f56087c0..b0af75ff76 100644 --- a/src/add-ons/media/plugins/avcodec/avcodec.cpp +++ b/src/add-ons/media/plugins/avcodec/avcodec.cpp @@ -263,6 +263,11 @@ avCodec::NegotiateOutputFormat(media_format *inout_format) ffc->width = fOutputVideoFormat.display.line_width; ffc->height = fOutputVideoFormat.display.line_count; ffc->frame_rate = (int)(fOutputVideoFormat.field_rate * ffc->frame_rate_base); + + if (fInputFormat.MetaDataSize() > 0) { + ffc->extradata = (void *)fInputFormat.MetaData(); + ffc->extradata_size = fInputFormat.MetaDataSize(); + } printf("#### requested video format 0x%x\n", inout_format->u.raw_video.display.format); diff --git a/src/add-ons/media/plugins/avcodec/codectbl.cpp b/src/add-ons/media/plugins/avcodec/codectbl.cpp index 56e4bf51dd..bcef8bebf6 100644 --- a/src/add-ons/media/plugins/avcodec/codectbl.cpp +++ b/src/add-ons/media/plugins/avcodec/codectbl.cpp @@ -51,6 +51,8 @@ const struct codec_table gCodecTable[] = { {CODEC_ID_ADPCM_IMA_QT, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'ima4', "Quicktime IMA4"}, {CODEC_ID_MPEG4AAC, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'mp4a', "MPEG4 AAC"}, {CODEC_ID_MPEG4, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'mp4v', "MPEG4 Video"}, + {CODEC_ID_MPEG4AAC, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'a4pm', "MPEG4 AAC"}, + {CODEC_ID_MPEG4, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'v4pm', "MPEG4 Video"}, #ifdef HAS_MACE_AUDIO {CODEC_ID_MACE3, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'MAC3', "MACE 3:1"}, 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 64eb3c9069..67bdce5fac 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp @@ -235,7 +235,7 @@ AtomBase *aAtomBase; return bytespersample; } - // calculate bytes per frame and cache it + // calculate bytes per sample and cache it if (IsAudio()) { // only used by Audio diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/ChunkSuperIndex.cpp b/src/add-ons/media/plugins/mp4_reader/libMP4/ChunkSuperIndex.cpp new file mode 100644 index 0000000000..3c7328b200 --- /dev/null +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/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/mp4_reader/libMP4/ChunkSuperIndex.h b/src/add-ons/media/plugins/mp4_reader/libMP4/ChunkSuperIndex.h new file mode 100644 index 0000000000..bf5ba955b0 --- /dev/null +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/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/mp4_reader/libMP4/Jamfile b/src/add-ons/media/plugins/mp4_reader/libMP4/Jamfile index 01a717c085..ae26eb167d 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/Jamfile +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/Jamfile @@ -5,4 +5,5 @@ StaticLibrary mp4reader : MP4FileReader.cpp MP4Atom.cpp MP4TrakAtom.cpp + ChunkSuperIndex.cpp ; diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Atom.h b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Atom.h index 31d457682a..b8523cd0d6 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Atom.h +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Atom.h @@ -101,6 +101,10 @@ public: uint64 getAtomSize() {return atomSize;}; uint32 getAtomType() {return atomType;}; + off_t getAtomOffset() {return atomOffset;}; + off_t getStreamOffset() {return streamOffset;}; + + uint64 getDataSize() {return atomSize - 8;}; uint64 getBytesRemaining(); diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp index 8596dbe273..ac745c41d2 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.cpp @@ -51,6 +51,21 @@ MP4FileReader::~MP4FileReader() theMVHDAtom = NULL; } +bool MP4FileReader::IsEndOfData(off_t pPosition) +{ +AtomBase *aAtomBase; + + for (uint32 index=0;indexgetAtomSize() > 8)) { + MDATAtom *aMdatAtom = dynamic_cast(aAtomBase); + return pPosition >= aMdatAtom->getEOF(); + } + } + + return true; +} + bool MP4FileReader::IsEndOfFile(off_t pPosition) { return (pPosition >= StreamSize); @@ -118,6 +133,28 @@ AtomBase *aAtomBase; return theMVHDAtom; } +void MP4FileReader::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()); + } +} + uint32 MP4FileReader::getMovieTimeScale() { return getMVHDAtom()->getTimeScale(); @@ -347,6 +384,8 @@ status_t MP4FileReader::ParseFile() atomChildren[i]->DisplayAtoms(); } + BuildSuperIndex(); + return B_OK; } @@ -419,7 +458,10 @@ const AudioMetaData *MP4FileReader::AudioFormat(uint32 stream_index, size_t * theAudio.SampleSize = aAudioDescription.theAudioSampleEntry.SampleSize; theAudio.SampleRate = aAudioDescription.theAudioSampleEntry.SampleRate / 65536; // Convert from fixed point decimal to float theAudio.PacketSize = uint32((theAudio.SampleRate * theAudio.NoOfChannels * theAudio.SampleSize) / 8); - + + theAudio.theVOL = aAudioDescription.theVOL; + theAudio.VOLSize = aAudioDescription.VOLSize; + return &theAudio; } } @@ -454,6 +496,10 @@ const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index) theVideo.image_size = aVideoDescription.theVideoSampleEntry.Height * aVideoDescription.theVideoSampleEntry.Width; theVideo.HorizontalResolution = aVideoDescription.theVideoSampleEntry.HorizontalResolution; theVideo.VerticalResolution = aVideoDescription.theVideoSampleEntry.VerticalResolution; + theVideo.FrameCount = aVideoDescription.theVideoSampleEntry.FrameCount; + + theVideo.theVOL = aVideoDescription.theVOL; + theVideo.VOLSize = aVideoDescription.VOLSize; aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0); if (aAtomBase) { @@ -505,28 +551,33 @@ uint32 MP4FileReader::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 = 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(); + return ChunkSize; } if (IsVideo(stream_index)) { if (pFrameNo < aTrakAtom->FrameCount()) { - // We read video in Sample by Sample so chunk size is Sample Size + // We read video in Sample by Sample so we use get Sample Size uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); return aTrakAtom->getSizeForSample(SampleNo); } @@ -559,7 +610,7 @@ bool MP4FileReader::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 MP4FileReader::IsActive(uint32 stream_index) diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.h b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.h index f1bd2656d5..30b0a7ef0b 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.h +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4FileReader.h @@ -31,6 +31,7 @@ #include #include "MP4Parser.h" +#include "ChunkSuperIndex.h" // MP4 file reader class MP4FileReader { @@ -56,6 +57,10 @@ private: MVHDAtom *theMVHDAtom; + ChunkSuperIndex theChunkSuperIndex; + + void BuildSuperIndex(); + public: MP4FileReader(BPositionIO *pStream); virtual ~MP4FileReader(); @@ -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/mp4_reader/libMP4/MP4Parser.cpp b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.cpp index dc4537e301..40b01411ff 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.cpp +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.cpp @@ -182,6 +182,10 @@ AtomBase *getAtom(BPositionIO *pStream) return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); } + if (aAtomType == uint32('esds')) { + return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize); + } + return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize); } @@ -693,7 +697,7 @@ void STSZAtom::OnProcessMetaData() theStream->Read(&SampleSize,sizeof(uint32)); theStream->Read(&SampleCount,sizeof(uint32)); - SampleSize = B_BENDIAN_TO_HOST_INT32(SampleCount); + SampleSize = B_BENDIAN_TO_HOST_INT32(SampleSize); SampleCount = B_BENDIAN_TO_HOST_INT32(SampleCount); // If the sample size is constant there is no array and NoEntries seems to contain bad values @@ -885,16 +889,55 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID) DEBUGGER(("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries)); TRESPASS(); - return theChunkToOffsetArray[0]->Offset; + return -1LL; +} + +ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize) +{ + theVOL = NULL; +} + +ESDSAtom::~ESDSAtom() +{ + if (theVOL) { + free(theVOL); + } +} + +void ESDSAtom::OnProcessMetaData() +{ + theVOL = (uint8 *)(malloc(getBytesRemaining())); + theStream->Read(theVOL,getBytesRemaining()); +} + +uint8 *ESDSAtom::getVOL() +{ + return theVOL; +} + +char *ESDSAtom::OnGetAtomName() +{ + return "Extended Sample Description Atom"; } STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize) { theHeader.NoEntries = 0; + theAudioDescription.theVOL = NULL; + theVideoDescription.theVOL = NULL; } STSDAtom::~STSDAtom() { + if (theAudioDescription.theVOL) { + free(theAudioDescription.theVOL); + theAudioDescription.theVOL = NULL; + } + + if (theVideoDescription.theVOL) { + free(theVideoDescription.theVOL); + theVideoDescription.theVOL = NULL; + } } uint32 STSDAtom::getMediaHandlerType() @@ -902,18 +945,48 @@ uint32 STSDAtom::getMediaHandlerType() return dynamic_cast(getParent())->getMediaHandlerType(); } +void STSDAtom::ReadESDS(uint8 **VOL, size_t *VOLSize) +{ + // Check for a esds and if it exists read it into the VOL buffer + // MPEG-4 video/audio use the esds to store the VOL (STUPID COMMITTEE IDEA) + + // First make sure we have a esds + if (getBytesRemaining() > 0) { + // Well something is there so read it as an atom + AtomBase *aAtomBase = getAtom(theStream); + + aAtomBase->ProcessMetaData(); + printf("%s [%Ld]\n",aAtomBase->getAtomName(),aAtomBase->getAtomSize()); + + if (dynamic_cast(aAtomBase)) { + // ESDS atom good + *VOLSize = aAtomBase->getDataSize(); + *VOL = (uint8 *)(malloc(*VOLSize)); + memcpy(*VOL,dynamic_cast(aAtomBase)->getVOL(),*VOLSize); + + delete aAtomBase; + } else { + // Unknown atom bad + delete aAtomBase; + } + } +} + void STSDAtom::ReadSoundDescription() { - theStream->Read(&theAudioDescription.theAudioSampleEntry,sizeof(AudioSampleEntry)); + theStream->Read(&theAudioDescription.theAudioSampleEntry,AudioSampleEntrySize); theAudioDescription.theAudioSampleEntry.ChannelCount = B_BENDIAN_TO_HOST_INT16(theAudioDescription.theAudioSampleEntry.ChannelCount); theAudioDescription.theAudioSampleEntry.SampleSize = B_BENDIAN_TO_HOST_INT16(theAudioDescription.theAudioSampleEntry.SampleSize); theAudioDescription.theAudioSampleEntry.SampleRate = B_BENDIAN_TO_HOST_INT32(theAudioDescription.theAudioSampleEntry.SampleRate); + + ReadESDS(&theAudioDescription.theVOL,&theAudioDescription.VOLSize); } void STSDAtom::ReadVideoDescription() { - theStream->Read(&theVideoDescription.theVideoSampleEntry,sizeof(VideoSampleEntry)); + // Hmm VideoSampleEntry is 70 bytes but the struct is 72 bytes stupid padding + theStream->Read(&theVideoDescription.theVideoSampleEntry,VideoSampleEntrySize); theVideoDescription.theVideoSampleEntry.Width = B_BENDIAN_TO_HOST_INT16(theVideoDescription.theVideoSampleEntry.Width); theVideoDescription.theVideoSampleEntry.Height = B_BENDIAN_TO_HOST_INT16(theVideoDescription.theVideoSampleEntry.Height); @@ -924,10 +997,12 @@ void STSDAtom::ReadVideoDescription() // convert from pascal string (first bytes size) to C string (null terminated) uint8 size = (uint8)(theVideoDescription.theVideoSampleEntry.CompressorName[0]); - memcpy(&theVideoDescription.theVideoSampleEntry.CompressorName[0],&theVideoDescription.theVideoSampleEntry.CompressorName[1],size); - theVideoDescription.theVideoSampleEntry.CompressorName[size] = '\0'; + if (size > 0) { + memcpy(&theVideoDescription.theVideoSampleEntry.CompressorName[0],&theVideoDescription.theVideoSampleEntry.CompressorName[1],size); + theVideoDescription.theVideoSampleEntry.CompressorName[size] = '\0'; + } - printf("Compressor Name %s\n",theVideoDescription.theVideoSampleEntry.CompressorName); + ReadESDS(&theVideoDescription.theVOL,&theVideoDescription.VOLSize); } void STSDAtom::OnProcessMetaData() @@ -1119,9 +1194,15 @@ void MDATAtom::OnProcessMetaData() char *MDATAtom::OnGetAtomName() { + printf("Offset %lld, Size %lld ",getStreamOffset(),getAtomSize()); 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/mp4_reader/libMP4/MP4Parser.h b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.h index 0af530d2d4..90a3ea011b 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.h +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Parser.h @@ -218,6 +218,7 @@ public: char *OnGetAtomName(); uint64 getOffsetForChunk(uint32 pChunkID); + uint32 getTotalChunks() {return theHeader.NoEntries;}; protected: // Read a single chunk offset from Stream @@ -294,7 +295,19 @@ public: virtual ~MDATAtom(); void OnProcessMetaData(); char *OnGetAtomName(); + off_t getEOF(); +}; + +class ESDSAtom : public AtomBase { +public: + ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize); + virtual ~ESDSAtom(); + void OnProcessMetaData(); + char *OnGetAtomName(); + uint8 *getVOL(); +private: + uint8 *theVOL; }; // Atom class for reading the sdst atom @@ -311,11 +324,13 @@ public: private: uint32 getMediaHandlerType(); + void ReadESDS(uint8 **VOL, size_t *VOLSize); void ReadSoundDescription(); void ReadVideoDescription(); + uint32 codecid; - + array_header theHeader; SampleEntry theSampleEntry; AudioDescription theAudioDescription; @@ -410,10 +425,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: @@ -421,6 +440,7 @@ private: MDHDAtom *theMDHDAtom; uint32 framecount; + uint32 bytespersample; }; // Atom class for reading the media container atom diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Structs.h b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Structs.h index 77f697792e..da9b2b32b2 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Structs.h +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4Structs.h @@ -79,7 +79,10 @@ struct VideoMetaData uint32 image_size; uint32 HorizontalResolution; uint32 VerticalResolution; + uint32 FrameCount; float FrameRate; + uint8 *theVOL; + size_t VOLSize; }; struct AudioMetaData @@ -89,6 +92,8 @@ struct AudioMetaData uint16 SampleSize; // bits per sample float SampleRate; // Samples per second (OR Frames per second) uint32 PacketSize; // (Sample Rate * NoOfchannels * SampleSize)/8 = bytes per second + uint8 *theVOL; + size_t VOLSize; }; struct TimeToSample { @@ -225,6 +230,8 @@ struct SampleEntry { uint16 DataReference; }; +#define SampleEntrySize sizeof(SampleEntry) + struct AudioSampleEntry { uint32 Reserved[2]; uint16 ChannelCount; @@ -234,9 +241,13 @@ struct AudioSampleEntry { uint32 SampleRate; // 16.16 }; +#define AudioSampleEntrySize sizeof(AudioSampleEntry) + struct AudioDescription { AudioSampleEntry theAudioSampleEntry; uint32 codecid; + uint8 *theVOL; + size_t VOLSize; }; struct VideoSampleEntry { @@ -254,7 +265,11 @@ struct VideoSampleEntry { uint16 pre_defined3; }; +#define VideoSampleEntrySize 70 + struct VideoDescription { VideoSampleEntry theVideoSampleEntry; uint32 codecid; + uint8 *theVOL; + size_t VOLSize; }; diff --git a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4TrakAtom.cpp b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4TrakAtom.cpp index 6954b06629..8527c721e5 100644 --- a/src/add-ons/media/plugins/mp4_reader/libMP4/MP4TrakAtom.cpp +++ b/src/add-ons/media/plugins/mp4_reader/libMP4/MP4TrakAtom.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 sample and cache it + + if (IsAudio()) { + // only used by Audio + aAtomBase = GetChildAtom(uint32('stsd'),0); + if (aAtomBase) { + STSDAtom *aSTSDAtom = dynamic_cast(aAtomBase); + + AudioDescription aAudioDescription = aSTSDAtom->getAsAudio(); + + bytespersample = aAudioDescription.theAudioSampleEntry.SampleSize / 8; + } + } + + 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 diff --git a/src/add-ons/media/plugins/mp4_reader/mp4_reader.cpp b/src/add-ons/media/plugins/mp4_reader/mp4_reader.cpp index 5ce5a0f497..d899f855f7 100644 --- a/src/add-ons/media/plugins/mp4_reader/mp4_reader.cpp +++ b/src/add-ons/media/plugins/mp4_reader/mp4_reader.cpp @@ -339,15 +339,17 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie) format->user_data_type = B_CODEC_TYPE_INFO; *(uint32 *)format->user_data = audio_format->compression; format->user_data[4] = 0; - // put the Audio struct, including extra data, into the format meta data. - size_t size; - const void *data = theFileReader->AudioFormat(cookie->stream, &size); + // Set the VOL + size_t size = audio_format->VOLSize; + const void *data = audio_format->theVOL; format->SetMetaData(data, size); #ifdef TRACE_MP4_READER - uint8 *p = 18 + (uint8 *)data; - TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - size - 18, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); + if (data) { + uint8 *p = (uint8 *)data; + TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + size , p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); + } #endif return B_OK; @@ -403,6 +405,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie) format->user_data_type = B_CODEC_TYPE_INFO; *(uint32 *)format->user_data = description.u.quicktime.codec; format->user_data[4] = 0; + format->u.encoded_video.max_bit_rate = 8 * theFileReader->MovMainHeader()->max_bytes_per_sec; format->u.encoded_video.avg_bit_rate = format->u.encoded_video.max_bit_rate / 2; // XXX fix this format->u.encoded_video.output.field_rate = cookie->frames_per_sec_rate / (float)cookie->frames_per_sec_scale; @@ -423,6 +426,19 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie) TRACE("max_bit_rate %.3f\n", format->u.encoded_video.max_bit_rate); TRACE("field_rate %.3f\n", format->u.encoded_video.output.field_rate); + // Set the VOL + size_t size = video_format->VOLSize; + const void *data = video_format->theVOL; + format->SetMetaData(data, size); + +#ifdef TRACE_MP4_READER + if (data) { + uint8 *p = (uint8 *)data; + TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + size, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); + } +#endif + return B_OK; }