fixes to allow mp4 reader to handle video correctly. Now alpha software

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13874 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2005-08-02 08:49:01 +00:00
parent 11a3346caa
commit 4bf7f3047f
14 changed files with 380 additions and 24 deletions
@@ -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);
@@ -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"},
@@ -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
@@ -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;
}
@@ -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 <SupportDefs.h>
// Std Headers
#include <map.h>
struct ChunkIndex {
uint32 stream;
uint32 chunkid;
off_t chunk_start;
};
typedef ChunkIndex* ChunkIndexPtr;
typedef std::map<off_t, ChunkIndexPtr, std::less<off_t> > 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
@@ -5,4 +5,5 @@ StaticLibrary mp4reader :
MP4FileReader.cpp
MP4Atom.cpp
MP4TrakAtom.cpp
ChunkSuperIndex.cpp
;
@@ -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();
@@ -51,6 +51,21 @@ MP4FileReader::~MP4FileReader()
theMVHDAtom = NULL;
}
bool MP4FileReader::IsEndOfData(off_t pPosition)
{
AtomBase *aAtomBase;
for (uint32 index=0;index<CountChildAtoms('mdat');index++) {
aAtomBase = GetChildAtom(uint32('mdat'),index);
if ((aAtomBase) && (aAtomBase->getAtomSize() > 8)) {
MDATAtom *aMdatAtom = dynamic_cast<MDATAtom *>(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<getStreamCount();stream++) {
aAtomBase = GetChildAtom(uint32('trak'),stream);
if (aAtomBase) {
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(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<MDATAtom *>(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;i<aTrakAtom->getNoSamplesInChunk(ChunkNo);i++) {
ChunkSize += aTrakAtom->getSizeForSample(SampleNo);
for (uint32 i=0;i<NoSamples;i++) {
TotalSampleSize += aTrakAtom->getSizeForSample(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)
@@ -31,6 +31,7 @@
#include <SupportDefs.h>
#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);
@@ -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<STBLAtom *>(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<ESDSAtom *>(aAtomBase)) {
// ESDS atom good
*VOLSize = aAtomBase->getDataSize();
*VOL = (uint8 *)(malloc(*VOLSize));
memcpy(*VOL,dynamic_cast<ESDSAtom *>(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)
{
}
@@ -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
@@ -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;
};
@@ -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<STSDAtom *>(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<STCOAtom *>(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
@@ -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;
}