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->width = fOutputVideoFormat.display.line_width;
|
||||||
ffc->height = fOutputVideoFormat.display.line_count;
|
ffc->height = fOutputVideoFormat.display.line_count;
|
||||||
ffc->frame_rate = (int)(fOutputVideoFormat.field_rate * ffc->frame_rate_base);
|
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);
|
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_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_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_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
|
#ifdef HAS_MACE_AUDIO
|
||||||
{CODEC_ID_MACE3, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'MAC3', "MACE 3:1"},
|
{CODEC_ID_MACE3, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'MAC3', "MACE 3:1"},
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ AtomBase *aAtomBase;
|
|||||||
return bytespersample;
|
return bytespersample;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate bytes per frame and cache it
|
// calculate bytes per sample and cache it
|
||||||
|
|
||||||
if (IsAudio()) {
|
if (IsAudio()) {
|
||||||
// only used by Audio
|
// 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
|
MP4FileReader.cpp
|
||||||
MP4Atom.cpp
|
MP4Atom.cpp
|
||||||
MP4TrakAtom.cpp
|
MP4TrakAtom.cpp
|
||||||
|
ChunkSuperIndex.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ public:
|
|||||||
|
|
||||||
uint64 getAtomSize() {return atomSize;};
|
uint64 getAtomSize() {return atomSize;};
|
||||||
uint32 getAtomType() {return atomType;};
|
uint32 getAtomType() {return atomType;};
|
||||||
|
off_t getAtomOffset() {return atomOffset;};
|
||||||
|
off_t getStreamOffset() {return streamOffset;};
|
||||||
|
|
||||||
|
uint64 getDataSize() {return atomSize - 8;};
|
||||||
|
|
||||||
uint64 getBytesRemaining();
|
uint64 getBytesRemaining();
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,21 @@ MP4FileReader::~MP4FileReader()
|
|||||||
theMVHDAtom = NULL;
|
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)
|
bool MP4FileReader::IsEndOfFile(off_t pPosition)
|
||||||
{
|
{
|
||||||
return (pPosition >= StreamSize);
|
return (pPosition >= StreamSize);
|
||||||
@@ -118,6 +133,28 @@ AtomBase *aAtomBase;
|
|||||||
return theMVHDAtom;
|
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()
|
uint32 MP4FileReader::getMovieTimeScale()
|
||||||
{
|
{
|
||||||
return getMVHDAtom()->getTimeScale();
|
return getMVHDAtom()->getTimeScale();
|
||||||
@@ -347,6 +384,8 @@ status_t MP4FileReader::ParseFile()
|
|||||||
atomChildren[i]->DisplayAtoms();
|
atomChildren[i]->DisplayAtoms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuildSuperIndex();
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +458,10 @@ const AudioMetaData *MP4FileReader::AudioFormat(uint32 stream_index, size_t *
|
|||||||
theAudio.SampleSize = aAudioDescription.theAudioSampleEntry.SampleSize;
|
theAudio.SampleSize = aAudioDescription.theAudioSampleEntry.SampleSize;
|
||||||
theAudio.SampleRate = aAudioDescription.theAudioSampleEntry.SampleRate / 65536; // Convert from fixed point decimal to float
|
theAudio.SampleRate = aAudioDescription.theAudioSampleEntry.SampleRate / 65536; // Convert from fixed point decimal to float
|
||||||
theAudio.PacketSize = uint32((theAudio.SampleRate * theAudio.NoOfChannels * theAudio.SampleSize) / 8);
|
theAudio.PacketSize = uint32((theAudio.SampleRate * theAudio.NoOfChannels * theAudio.SampleSize) / 8);
|
||||||
|
|
||||||
|
theAudio.theVOL = aAudioDescription.theVOL;
|
||||||
|
theAudio.VOLSize = aAudioDescription.VOLSize;
|
||||||
|
|
||||||
return &theAudio;
|
return &theAudio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,6 +496,10 @@ const VideoMetaData *MP4FileReader::VideoFormat(uint32 stream_index)
|
|||||||
theVideo.image_size = aVideoDescription.theVideoSampleEntry.Height * aVideoDescription.theVideoSampleEntry.Width;
|
theVideo.image_size = aVideoDescription.theVideoSampleEntry.Height * aVideoDescription.theVideoSampleEntry.Width;
|
||||||
theVideo.HorizontalResolution = aVideoDescription.theVideoSampleEntry.HorizontalResolution;
|
theVideo.HorizontalResolution = aVideoDescription.theVideoSampleEntry.HorizontalResolution;
|
||||||
theVideo.VerticalResolution = aVideoDescription.theVideoSampleEntry.VerticalResolution;
|
theVideo.VerticalResolution = aVideoDescription.theVideoSampleEntry.VerticalResolution;
|
||||||
|
theVideo.FrameCount = aVideoDescription.theVideoSampleEntry.FrameCount;
|
||||||
|
|
||||||
|
theVideo.theVOL = aVideoDescription.theVOL;
|
||||||
|
theVideo.VOLSize = aVideoDescription.VOLSize;
|
||||||
|
|
||||||
aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0);
|
aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0);
|
||||||
if (aAtomBase) {
|
if (aAtomBase) {
|
||||||
@@ -505,28 +551,33 @@ uint32 MP4FileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo)
|
|||||||
if (IsAudio(stream_index)) {
|
if (IsAudio(stream_index)) {
|
||||||
|
|
||||||
// We read audio in chunk by chunk so chunk size is chunk size
|
// 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
|
// Get first sample in chunk
|
||||||
uint32 SampleNo = aTrakAtom->getFirstSampleInChunk(ChunkNo);
|
uint32 SampleNo = aTrakAtom->getFirstSampleInChunk(ChunkNo);
|
||||||
|
|
||||||
uint32 ChunkSize = 0;
|
|
||||||
if (aTrakAtom->IsSingleSampleSize()) {
|
if (aTrakAtom->IsSingleSampleSize()) {
|
||||||
ChunkSize = aTrakAtom->getNoSamplesInChunk(ChunkNo) * aTrakAtom->getSizeForSample(SampleNo);
|
TotalSampleSize = NoSamples * aTrakAtom->getSizeForSample(SampleNo);
|
||||||
} else {
|
} else {
|
||||||
// Add up all sample sizes in chunk
|
// Add up all sample sizes in chunk
|
||||||
for (uint32 i=0;i<aTrakAtom->getNoSamplesInChunk(ChunkNo);i++) {
|
for (uint32 i=0;i<NoSamples;i++) {
|
||||||
ChunkSize += aTrakAtom->getSizeForSample(SampleNo);
|
TotalSampleSize += aTrakAtom->getSizeForSample(SampleNo);
|
||||||
SampleNo++;
|
SampleNo++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TotalSampleSize = TotalSampleSize * aTrakAtom->getBytesPerSample();
|
||||||
|
|
||||||
return ChunkSize;
|
return ChunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsVideo(stream_index)) {
|
if (IsVideo(stream_index)) {
|
||||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
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);
|
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||||
return aTrakAtom->getSizeForSample(SampleNo);
|
return aTrakAtom->getSizeForSample(SampleNo);
|
||||||
}
|
}
|
||||||
@@ -559,7 +610,7 @@ bool MP4FileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t
|
|||||||
*keyframe = IsKeyFrame(stream_index, pFrameNo);
|
*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)
|
bool MP4FileReader::IsActive(uint32 stream_index)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
#include "MP4Parser.h"
|
#include "MP4Parser.h"
|
||||||
|
#include "ChunkSuperIndex.h"
|
||||||
|
|
||||||
// MP4 file reader
|
// MP4 file reader
|
||||||
class MP4FileReader {
|
class MP4FileReader {
|
||||||
@@ -56,6 +57,10 @@ private:
|
|||||||
|
|
||||||
MVHDAtom *theMVHDAtom;
|
MVHDAtom *theMVHDAtom;
|
||||||
|
|
||||||
|
ChunkSuperIndex theChunkSuperIndex;
|
||||||
|
|
||||||
|
void BuildSuperIndex();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MP4FileReader(BPositionIO *pStream);
|
MP4FileReader(BPositionIO *pStream);
|
||||||
virtual ~MP4FileReader();
|
virtual ~MP4FileReader();
|
||||||
@@ -65,6 +70,7 @@ public:
|
|||||||
|
|
||||||
bool IsEndOfFile(off_t pPosition);
|
bool IsEndOfFile(off_t pPosition);
|
||||||
bool IsEndOfFile();
|
bool IsEndOfFile();
|
||||||
|
bool IsEndOfData(off_t pPosition);
|
||||||
|
|
||||||
// Is this a quicktime file
|
// Is this a quicktime file
|
||||||
static bool IsSupported(BPositionIO *source);
|
static bool IsSupported(BPositionIO *source);
|
||||||
|
|||||||
@@ -182,6 +182,10 @@ AtomBase *getAtom(BPositionIO *pStream)
|
|||||||
return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
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);
|
return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -693,7 +697,7 @@ void STSZAtom::OnProcessMetaData()
|
|||||||
theStream->Read(&SampleSize,sizeof(uint32));
|
theStream->Read(&SampleSize,sizeof(uint32));
|
||||||
theStream->Read(&SampleCount,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);
|
SampleCount = B_BENDIAN_TO_HOST_INT32(SampleCount);
|
||||||
|
|
||||||
// If the sample size is constant there is no array and NoEntries seems to contain bad values
|
// 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));
|
DEBUGGER(("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries));
|
||||||
|
|
||||||
TRESPASS();
|
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)
|
STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
|
||||||
{
|
{
|
||||||
theHeader.NoEntries = 0;
|
theHeader.NoEntries = 0;
|
||||||
|
theAudioDescription.theVOL = NULL;
|
||||||
|
theVideoDescription.theVOL = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
STSDAtom::~STSDAtom()
|
STSDAtom::~STSDAtom()
|
||||||
{
|
{
|
||||||
|
if (theAudioDescription.theVOL) {
|
||||||
|
free(theAudioDescription.theVOL);
|
||||||
|
theAudioDescription.theVOL = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theVideoDescription.theVOL) {
|
||||||
|
free(theVideoDescription.theVOL);
|
||||||
|
theVideoDescription.theVOL = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 STSDAtom::getMediaHandlerType()
|
uint32 STSDAtom::getMediaHandlerType()
|
||||||
@@ -902,18 +945,48 @@ uint32 STSDAtom::getMediaHandlerType()
|
|||||||
return dynamic_cast<STBLAtom *>(getParent())->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()
|
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.ChannelCount = B_BENDIAN_TO_HOST_INT16(theAudioDescription.theAudioSampleEntry.ChannelCount);
|
||||||
theAudioDescription.theAudioSampleEntry.SampleSize = B_BENDIAN_TO_HOST_INT16(theAudioDescription.theAudioSampleEntry.SampleSize);
|
theAudioDescription.theAudioSampleEntry.SampleSize = B_BENDIAN_TO_HOST_INT16(theAudioDescription.theAudioSampleEntry.SampleSize);
|
||||||
theAudioDescription.theAudioSampleEntry.SampleRate = B_BENDIAN_TO_HOST_INT32(theAudioDescription.theAudioSampleEntry.SampleRate);
|
theAudioDescription.theAudioSampleEntry.SampleRate = B_BENDIAN_TO_HOST_INT32(theAudioDescription.theAudioSampleEntry.SampleRate);
|
||||||
|
|
||||||
|
ReadESDS(&theAudioDescription.theVOL,&theAudioDescription.VOLSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void STSDAtom::ReadVideoDescription()
|
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.Width = B_BENDIAN_TO_HOST_INT16(theVideoDescription.theVideoSampleEntry.Width);
|
||||||
theVideoDescription.theVideoSampleEntry.Height = B_BENDIAN_TO_HOST_INT16(theVideoDescription.theVideoSampleEntry.Height);
|
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)
|
// convert from pascal string (first bytes size) to C string (null terminated)
|
||||||
uint8 size = (uint8)(theVideoDescription.theVideoSampleEntry.CompressorName[0]);
|
uint8 size = (uint8)(theVideoDescription.theVideoSampleEntry.CompressorName[0]);
|
||||||
memcpy(&theVideoDescription.theVideoSampleEntry.CompressorName[0],&theVideoDescription.theVideoSampleEntry.CompressorName[1],size);
|
if (size > 0) {
|
||||||
theVideoDescription.theVideoSampleEntry.CompressorName[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()
|
void STSDAtom::OnProcessMetaData()
|
||||||
@@ -1119,9 +1194,15 @@ void MDATAtom::OnProcessMetaData()
|
|||||||
|
|
||||||
char *MDATAtom::OnGetAtomName()
|
char *MDATAtom::OnGetAtomName()
|
||||||
{
|
{
|
||||||
|
printf("Offset %lld, Size %lld ",getStreamOffset(),getAtomSize());
|
||||||
return "Media Data Atom";
|
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)
|
MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ public:
|
|||||||
char *OnGetAtomName();
|
char *OnGetAtomName();
|
||||||
|
|
||||||
uint64 getOffsetForChunk(uint32 pChunkID);
|
uint64 getOffsetForChunk(uint32 pChunkID);
|
||||||
|
uint32 getTotalChunks() {return theHeader.NoEntries;};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Read a single chunk offset from Stream
|
// Read a single chunk offset from Stream
|
||||||
@@ -294,7 +295,19 @@ public:
|
|||||||
virtual ~MDATAtom();
|
virtual ~MDATAtom();
|
||||||
void OnProcessMetaData();
|
void OnProcessMetaData();
|
||||||
char *OnGetAtomName();
|
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
|
// Atom class for reading the sdst atom
|
||||||
@@ -311,11 +324,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
uint32 getMediaHandlerType();
|
uint32 getMediaHandlerType();
|
||||||
|
|
||||||
|
void ReadESDS(uint8 **VOL, size_t *VOLSize);
|
||||||
void ReadSoundDescription();
|
void ReadSoundDescription();
|
||||||
void ReadVideoDescription();
|
void ReadVideoDescription();
|
||||||
|
|
||||||
|
|
||||||
uint32 codecid;
|
uint32 codecid;
|
||||||
|
|
||||||
array_header theHeader;
|
array_header theHeader;
|
||||||
SampleEntry theSampleEntry;
|
SampleEntry theSampleEntry;
|
||||||
AudioDescription theAudioDescription;
|
AudioDescription theAudioDescription;
|
||||||
@@ -410,10 +425,14 @@ public:
|
|||||||
uint32 getFirstSampleInChunk(uint32 pChunkID);
|
uint32 getFirstSampleInChunk(uint32 pChunkID);
|
||||||
uint32 getSizeForSample(uint32 pSample);
|
uint32 getSizeForSample(uint32 pSample);
|
||||||
uint32 getNoSamplesInChunk(uint32 pChunkID);
|
uint32 getNoSamplesInChunk(uint32 pChunkID);
|
||||||
|
uint32 getTotalChunks();
|
||||||
|
|
||||||
bool IsSyncSample(uint32 pSampleNo);
|
bool IsSyncSample(uint32 pSampleNo);
|
||||||
bool IsSingleSampleSize();
|
bool IsSingleSampleSize();
|
||||||
bool IsActive();
|
bool IsActive();
|
||||||
|
|
||||||
|
uint32 getBytesPerSample();
|
||||||
|
|
||||||
TKHDAtom *getTKHDAtom();
|
TKHDAtom *getTKHDAtom();
|
||||||
MDHDAtom *getMDHDAtom();
|
MDHDAtom *getMDHDAtom();
|
||||||
private:
|
private:
|
||||||
@@ -421,6 +440,7 @@ private:
|
|||||||
MDHDAtom *theMDHDAtom;
|
MDHDAtom *theMDHDAtom;
|
||||||
|
|
||||||
uint32 framecount;
|
uint32 framecount;
|
||||||
|
uint32 bytespersample;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Atom class for reading the media container atom
|
// Atom class for reading the media container atom
|
||||||
|
|||||||
@@ -79,7 +79,10 @@ struct VideoMetaData
|
|||||||
uint32 image_size;
|
uint32 image_size;
|
||||||
uint32 HorizontalResolution;
|
uint32 HorizontalResolution;
|
||||||
uint32 VerticalResolution;
|
uint32 VerticalResolution;
|
||||||
|
uint32 FrameCount;
|
||||||
float FrameRate;
|
float FrameRate;
|
||||||
|
uint8 *theVOL;
|
||||||
|
size_t VOLSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AudioMetaData
|
struct AudioMetaData
|
||||||
@@ -89,6 +92,8 @@ struct AudioMetaData
|
|||||||
uint16 SampleSize; // bits per sample
|
uint16 SampleSize; // bits per sample
|
||||||
float SampleRate; // Samples per second (OR Frames per second)
|
float SampleRate; // Samples per second (OR Frames per second)
|
||||||
uint32 PacketSize; // (Sample Rate * NoOfchannels * SampleSize)/8 = bytes per second
|
uint32 PacketSize; // (Sample Rate * NoOfchannels * SampleSize)/8 = bytes per second
|
||||||
|
uint8 *theVOL;
|
||||||
|
size_t VOLSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimeToSample {
|
struct TimeToSample {
|
||||||
@@ -225,6 +230,8 @@ struct SampleEntry {
|
|||||||
uint16 DataReference;
|
uint16 DataReference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SampleEntrySize sizeof(SampleEntry)
|
||||||
|
|
||||||
struct AudioSampleEntry {
|
struct AudioSampleEntry {
|
||||||
uint32 Reserved[2];
|
uint32 Reserved[2];
|
||||||
uint16 ChannelCount;
|
uint16 ChannelCount;
|
||||||
@@ -234,9 +241,13 @@ struct AudioSampleEntry {
|
|||||||
uint32 SampleRate; // 16.16
|
uint32 SampleRate; // 16.16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define AudioSampleEntrySize sizeof(AudioSampleEntry)
|
||||||
|
|
||||||
struct AudioDescription {
|
struct AudioDescription {
|
||||||
AudioSampleEntry theAudioSampleEntry;
|
AudioSampleEntry theAudioSampleEntry;
|
||||||
uint32 codecid;
|
uint32 codecid;
|
||||||
|
uint8 *theVOL;
|
||||||
|
size_t VOLSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VideoSampleEntry {
|
struct VideoSampleEntry {
|
||||||
@@ -254,7 +265,11 @@ struct VideoSampleEntry {
|
|||||||
uint16 pre_defined3;
|
uint16 pre_defined3;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VideoSampleEntrySize 70
|
||||||
|
|
||||||
struct VideoDescription {
|
struct VideoDescription {
|
||||||
VideoSampleEntry theVideoSampleEntry;
|
VideoSampleEntry theVideoSampleEntry;
|
||||||
uint32 codecid;
|
uint32 codecid;
|
||||||
|
uint8 *theVOL;
|
||||||
|
size_t VOLSize;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
|
|||||||
theTKHDAtom = NULL;
|
theTKHDAtom = NULL;
|
||||||
theMDHDAtom = NULL;
|
theMDHDAtom = NULL;
|
||||||
framecount = 0;
|
framecount = 0;
|
||||||
|
bytespersample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRAKAtom::~TRAKAtom()
|
TRAKAtom::~TRAKAtom()
|
||||||
@@ -226,5 +227,41 @@ bool TRAKAtom::IsActive()
|
|||||||
return getTKHDAtom()->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
|
// GetAudioMetaData() // If this is a audio track get the audio meta data
|
||||||
// GetVideoMetaData() // If this is a video track get the video 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;
|
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||||
*(uint32 *)format->user_data = audio_format->compression; format->user_data[4] = 0;
|
*(uint32 *)format->user_data = audio_format->compression; format->user_data[4] = 0;
|
||||||
|
|
||||||
// put the Audio struct, including extra data, into the format meta data.
|
// Set the VOL
|
||||||
size_t size;
|
size_t size = audio_format->VOLSize;
|
||||||
const void *data = theFileReader->AudioFormat(cookie->stream, &size);
|
const void *data = audio_format->theVOL;
|
||||||
format->SetMetaData(data, size);
|
format->SetMetaData(data, size);
|
||||||
|
|
||||||
#ifdef TRACE_MP4_READER
|
#ifdef TRACE_MP4_READER
|
||||||
uint8 *p = 18 + (uint8 *)data;
|
if (data) {
|
||||||
TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
uint8 *p = (uint8 *)data;
|
||||||
size - 18, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
|
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
|
#endif
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -403,6 +405,7 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||||||
|
|
||||||
format->user_data_type = B_CODEC_TYPE_INFO;
|
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||||
*(uint32 *)format->user_data = description.u.quicktime.codec; format->user_data[4] = 0;
|
*(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.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.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;
|
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("max_bit_rate %.3f\n", format->u.encoded_video.max_bit_rate);
|
||||||
TRACE("field_rate %.3f\n", format->u.encoded_video.output.field_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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user