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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user