bring haiku mp4_reader up to date with BeOS mp4_extractor
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25340 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
a2e55dcc0c
commit
899c7641d4
@ -41,6 +41,17 @@ AtomBase::~AtomBase()
|
||||
parentAtom = NULL;
|
||||
}
|
||||
|
||||
char *AtomBase::getAtomTypeAsFourcc()
|
||||
{
|
||||
fourcc[0] = (char)((atomType >> 24) & 0xff);
|
||||
fourcc[1] = (char)((atomType >> 16) & 0xff);
|
||||
fourcc[2] = (char)((atomType >> 8) & 0xff);
|
||||
fourcc[3] = (char)((atomType >> 0) & 0xff);
|
||||
fourcc[4] = '\0';
|
||||
|
||||
return fourcc;
|
||||
}
|
||||
|
||||
char *AtomBase::getAtomName()
|
||||
{
|
||||
char *_result;
|
||||
@ -209,6 +220,36 @@ void AtomBase::Read(uint8 *value, uint32 maxread)
|
||||
// Assert((bytes_read == maxread,"Read Error");
|
||||
}
|
||||
|
||||
uint64 AtomBase::GetBits(uint64 buffer, uint8 startBit, uint8 totalBits)
|
||||
{
|
||||
// startBit should range from 0-63, totalBits should range from 1-64
|
||||
if ((startBit < 64) && (totalBits > 0) && (totalBits <= 64) && (startBit + totalBits <= 64)) {
|
||||
// Ok pull from the buffer the bits wanted.
|
||||
buffer = buffer << startBit;
|
||||
buffer = buffer >> (64 - (totalBits + startBit) + startBit);
|
||||
|
||||
printf("buffer = %Ld\n",buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
uint32 AtomBase::GetBits(uint32 buffer, uint8 startBit, uint8 totalBits)
|
||||
{
|
||||
// startBit should range from 0-31, totalBits should range from 1-32
|
||||
if ((startBit < 32) && (totalBits > 0) && (totalBits <= 32) && (startBit + totalBits <= 32)) {
|
||||
// Ok pull from the buffer the bits wanted.
|
||||
buffer = buffer << startBit;
|
||||
buffer = buffer >> (32 - (startBit + totalBits) + startBit);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FullAtom::FullAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
|
@ -101,17 +101,18 @@ public:
|
||||
|
||||
uint64 getAtomSize() {return atomSize;};
|
||||
uint32 getAtomType() {return atomType;};
|
||||
off_t getAtomOffset() {return atomOffset;};
|
||||
off_t getStreamOffset() {return streamOffset;};
|
||||
char *getAtomTypeAsFourcc();
|
||||
off_t getAtomOffset() { return atomOffset; };
|
||||
off_t getStreamOffset() { return streamOffset; };
|
||||
|
||||
uint64 getDataSize() {return atomSize - 8;};
|
||||
uint64 getDataSize() { return atomSize - 8;};
|
||||
|
||||
uint64 getBytesRemaining();
|
||||
|
||||
bool IsType(uint32 patomType) {return patomType == atomType;};
|
||||
bool IsType(uint32 patomType) { return patomType == atomType; };
|
||||
|
||||
void setAtomOffset(off_t patomOffset) {atomOffset = patomOffset;};
|
||||
void setStreamOffset(off_t pstreamOffset) {streamOffset = pstreamOffset;};
|
||||
void setAtomOffset(off_t patomOffset) { atomOffset = patomOffset; };
|
||||
void setStreamOffset(off_t pstreamOffset) { streamOffset = pstreamOffset; };
|
||||
|
||||
char *getAtomName();
|
||||
|
||||
@ -142,6 +143,9 @@ public:
|
||||
void Read(uint8 *value);
|
||||
void Read(char *value, uint32 maxread);
|
||||
void Read(uint8 *value, uint32 maxread);
|
||||
|
||||
uint64 GetBits(uint64 buffer, uint8 startBit, uint8 totalBits);
|
||||
uint32 GetBits(uint32 buffer, uint8 startBit, uint8 totalBits);
|
||||
};
|
||||
|
||||
class FullAtom : public AtomBase {
|
||||
|
@ -62,11 +62,15 @@ MP4FileReader::IsEndOfData(off_t pPosition)
|
||||
{
|
||||
AtomBase* aAtomBase;
|
||||
|
||||
// check all mdat atoms to make sure pPosition is within one of them
|
||||
|
||||
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();
|
||||
MDATAtom *aMDATAtom = dynamic_cast<MDATAtom *>(aAtomBase);
|
||||
if (pPosition >= aMDATAtom->getAtomOffset() && pPosition <= aMDATAtom->getEOF()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,8 +191,7 @@ MP4FileReader::getMovieTimeScale()
|
||||
bigtime_t
|
||||
MP4FileReader::getMovieDuration()
|
||||
{
|
||||
return (bigtime_t(getMVHDAtom()->getDuration()) * 1000000L)
|
||||
/ getMovieTimeScale();
|
||||
return bigtime_t((getMVHDAtom()->getDuration() * 1000000.0) / getMovieTimeScale());
|
||||
}
|
||||
|
||||
|
||||
@ -261,24 +264,13 @@ MP4FileReader::getMaxDuration()
|
||||
|
||||
|
||||
uint32
|
||||
MP4FileReader::getVideoFrameCount(uint32 streamIndex)
|
||||
MP4FileReader::getFrameCount(uint32 streamIndex)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
MP4FileReader::getAudioFrameCount(uint32 streamIndex)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'), streamIndex);
|
||||
|
||||
if (aAtomBase && dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())
|
||||
if (aAtomBase) {
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -368,8 +360,12 @@ MP4FileReader::getOffsetForFrame(uint32 streamIndex, uint32 pFrameNo)
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
if (pFrameNo < aTrakAtom->FrameCount()) {
|
||||
// Get Sample for Frame
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
// Get time for Frame
|
||||
bigtime_t Time = aTrakAtom->getTimeForFrame(pFrameNo);
|
||||
|
||||
// Get Sample for Time
|
||||
uint32 SampleNo = aTrakAtom->getSampleForTime(Time);
|
||||
|
||||
// Get Chunk For Sample and the offset for the frame within that chunk
|
||||
uint32 OffsetInChunk;
|
||||
uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk);
|
||||
@ -391,6 +387,8 @@ MP4FileReader::getOffsetForFrame(uint32 streamIndex, uint32 pFrameNo)
|
||||
}
|
||||
}
|
||||
|
||||
// printf("frame %ld, time %Ld, sample %ld, Chunk %ld, OffsetInChunk %ld, Offset %Ld\n",pFrameNo, Time, SampleNo, ChunkNo, OffsetInChunk, OffsetNo);
|
||||
|
||||
return OffsetNo;
|
||||
}
|
||||
}
|
||||
@ -458,7 +456,7 @@ MP4FileReader::MovMainHeader()
|
||||
} else {
|
||||
theMainHeader.width = VideoFormat(videoStream)->width;
|
||||
theMainHeader.height = VideoFormat(videoStream)->height;
|
||||
theMainHeader.total_frames = getVideoFrameCount(videoStream);
|
||||
theMainHeader.total_frames = getFrameCount(videoStream);
|
||||
theMainHeader.suggested_buffer_size = theMainHeader.width * theMainHeader.height * VideoFormat(videoStream)->bit_count / 8;
|
||||
theMainHeader.micro_sec_per_frame = uint32(1000000.0 / VideoFormat(videoStream)->FrameRate);
|
||||
}
|
||||
@ -483,18 +481,33 @@ MP4FileReader::AudioFormat(uint32 streamIndex, size_t *size)
|
||||
if (aAtomBase) {
|
||||
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
|
||||
|
||||
// Fill In a wave_format_ex structure
|
||||
// Fill in the AudioMetaData structure
|
||||
AudioDescription aAudioDescription = aSTSDAtom->getAsAudio();
|
||||
|
||||
theAudio.compression = aAudioDescription.codecid;
|
||||
theAudio.codecSubType = aAudioDescription.codecSubType;
|
||||
|
||||
theAudio.NoOfChannels = aAudioDescription.theAudioSampleEntry.ChannelCount;
|
||||
theAudio.SampleSize = aAudioDescription.theAudioSampleEntry.SampleSize;
|
||||
|
||||
// Fix for broken mp4's with 0 SampleSize, default to 16 bits
|
||||
if (aAudioDescription.theAudioSampleEntry.SampleSize == 0) {
|
||||
theAudio.SampleSize = 16;
|
||||
} else {
|
||||
theAudio.SampleSize = aAudioDescription.theAudioSampleEntry.SampleSize;
|
||||
}
|
||||
|
||||
theAudio.SampleRate = aAudioDescription.theAudioSampleEntry.SampleRate / 65536; // Convert from fixed point decimal to float
|
||||
theAudio.PacketSize = uint32((theAudio.SampleSize * theAudio.NoOfChannels * 1024) / 8);
|
||||
theAudio.FrameSize = aAudioDescription.FrameSize;
|
||||
if (aAudioDescription.BufferSize == 0) {
|
||||
theAudio.BufferSize = uint32((theAudio.SampleSize * theAudio.NoOfChannels * theAudio.FrameSize) / 8);
|
||||
} else {
|
||||
theAudio.BufferSize = aAudioDescription.BufferSize;
|
||||
}
|
||||
|
||||
theAudio.BitRate = aAudioDescription.BitRate;
|
||||
|
||||
theAudio.theVOL = aAudioDescription.theVOL;
|
||||
theAudio.VOLSize = aAudioDescription.VOLSize;
|
||||
theAudio.theDecoderConfig = aAudioDescription.theDecoderConfig;
|
||||
theAudio.DecoderConfigSize = aAudioDescription.DecoderConfigSize;
|
||||
|
||||
return &theAudio;
|
||||
}
|
||||
@ -519,25 +532,26 @@ MP4FileReader::VideoFormat(uint32 streamIndex)
|
||||
VideoDescription aVideoDescription = aSTSDAtom->getAsVideo();
|
||||
|
||||
theVideo.compression = aVideoDescription.codecid;
|
||||
theVideo.codecSubType = aVideoDescription.codecSubType;
|
||||
|
||||
theVideo.width = aVideoDescription.theVideoSampleEntry.Width;
|
||||
theVideo.height = aVideoDescription.theVideoSampleEntry.Height;
|
||||
theVideo.planes = aVideoDescription.theVideoSampleEntry.Depth;
|
||||
theVideo.size = aVideoDescription.theVideoSampleEntry.Width * aVideoDescription.theVideoSampleEntry.Height * aVideoDescription.theVideoSampleEntry.Depth / 8;
|
||||
theVideo.BufferSize = aVideoDescription.theVideoSampleEntry.Width * aVideoDescription.theVideoSampleEntry.Height * aVideoDescription.theVideoSampleEntry.Depth / 8;
|
||||
theVideo.bit_count = aVideoDescription.theVideoSampleEntry.Depth;
|
||||
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;
|
||||
theVideo.theDecoderConfig = aVideoDescription.theDecoderConfig;
|
||||
theVideo.DecoderConfigSize = aVideoDescription.DecoderConfigSize;
|
||||
|
||||
aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0);
|
||||
if (aAtomBase) {
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
|
||||
|
||||
theVideo.FrameRate = ((aSTTSAtom->getSUMCounts() * 1000000.0L) / aTrakAtom->Duration(1));
|
||||
theVideo.FrameRate = ((aSTTSAtom->getSUMCounts() * 1000000.0) / aTrakAtom->Duration(1));
|
||||
|
||||
return &theVideo;
|
||||
}
|
||||
@ -552,25 +566,25 @@ MP4FileReader::VideoFormat(uint32 streamIndex)
|
||||
const mp4_stream_header*
|
||||
MP4FileReader::StreamFormat(uint32 streamIndex)
|
||||
{
|
||||
// Fill In a Stream Header
|
||||
theStreamHeader.length = 0;
|
||||
|
||||
if (IsActive(streamIndex) == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fill In a Stream Header
|
||||
theStreamHeader.length = 0;
|
||||
|
||||
if (IsVideo(streamIndex)) {
|
||||
theStreamHeader.rate = uint32(1000000L*VideoFormat(streamIndex)->FrameRate);
|
||||
theStreamHeader.rate = uint32(1000000.0*VideoFormat(streamIndex)->FrameRate);
|
||||
theStreamHeader.scale = 1000000L;
|
||||
theStreamHeader.length = getVideoFrameCount(streamIndex);
|
||||
theStreamHeader.length = getFrameCount(streamIndex);
|
||||
}
|
||||
|
||||
if (IsAudio(streamIndex)) {
|
||||
theStreamHeader.rate = uint32(AudioFormat(streamIndex)->SampleRate);
|
||||
theStreamHeader.scale = 1;
|
||||
theStreamHeader.length = getAudioFrameCount(streamIndex);
|
||||
theStreamHeader.length = getFrameCount(streamIndex);
|
||||
theStreamHeader.sample_size = AudioFormat(streamIndex)->SampleSize;
|
||||
theStreamHeader.suggested_buffer_size = theStreamHeader.rate * theStreamHeader.sample_size;
|
||||
theStreamHeader.suggested_buffer_size = AudioFormat(streamIndex)->BufferSize;
|
||||
}
|
||||
|
||||
return &theStreamHeader;
|
||||
@ -601,8 +615,7 @@ MP4FileReader::IsKeyFrame(uint32 streamIndex, uint32 pFrameNo)
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
|
||||
uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo);
|
||||
return aTrakAtom->IsSyncSample(SampleNo);
|
||||
return aTrakAtom->IsSyncSample(pFrameNo);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -620,6 +633,8 @@ MP4FileReader::GetNextChunkInfo(uint32 streamIndex, uint32 pFrameNo,
|
||||
*keyframe = IsKeyFrame(streamIndex, pFrameNo);
|
||||
}
|
||||
|
||||
// printf("start %Ld, size %ld, eof %s, eod %s\n",*start,*size, IsEndOfFile(*start + *size) ? "true" : "false", IsEndOfData(*start + *size) ? "true" : "false");
|
||||
|
||||
// TODO need a better method for detecting End of Data Note ChunkSize of 0 seems to be it.
|
||||
return *start > 0 && *size > 0 && !IsEndOfFile(*start + *size)
|
||||
&& !IsEndOfData(*start + *size);
|
||||
@ -647,11 +662,18 @@ MP4FileReader::IsSupported(BPositionIO *source)
|
||||
if (aAtom) {
|
||||
if (dynamic_cast<FTYPAtom *>(aAtom)) {
|
||||
aAtom->ProcessMetaData();
|
||||
printf("ftyp atom found checking brands\n");
|
||||
printf("ftyp atom found checking brands...");
|
||||
// MP4 files start with a ftyp atom that does not contain a qt brand
|
||||
return !(dynamic_cast<FTYPAtom *>(aAtom)->HasBrand(uint32('qt ')));
|
||||
if (!dynamic_cast<FTYPAtom *>(aAtom)->HasBrand(uint32('qt '))) {
|
||||
printf("no quicktime brand found must be mp4\n");
|
||||
return true;
|
||||
} else {
|
||||
printf("quicktime brand found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("NO ftyp atom found, cannot be mp4\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -89,10 +89,7 @@ public:
|
||||
bigtime_t getMaxDuration();
|
||||
|
||||
// The no of frames in the video track indexed by streamIndex
|
||||
// 1 frame = 1 chunk
|
||||
uint32 getVideoFrameCount(uint32 streamIndex);
|
||||
// The no of frames in the audio track indexed by streamIndex
|
||||
uint32 getAudioFrameCount(uint32 streamIndex);
|
||||
uint32 getFrameCount(uint32 streamIndex);
|
||||
// The no of chunks in the audio track indexed by streamIndex
|
||||
uint32 getAudioChunkCount(uint32 streamIndex);
|
||||
// Is stream (track) a video track
|
||||
|
@ -189,6 +189,14 @@ AtomBase *getAtom(BPositionIO *pStream)
|
||||
return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
if (aAtomType == uint32('alac')) {
|
||||
return new ALACAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
if (aAtomType == uint32('wave')) {
|
||||
return new WAVEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
}
|
||||
|
||||
return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
|
||||
|
||||
}
|
||||
@ -477,6 +485,8 @@ TimeToSample *aTimeToSample;
|
||||
|
||||
ReadArrayHeader(&theHeader);
|
||||
|
||||
// printf("STTS:: Entries %ld\n",theHeader.NoEntries);
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
aTimeToSample = new TimeToSample;
|
||||
|
||||
@ -486,7 +496,11 @@ TimeToSample *aTimeToSample;
|
||||
theTimeToSampleArray[i] = aTimeToSample;
|
||||
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
SUMCounts += theTimeToSampleArray[i]->Count;
|
||||
|
||||
// printf("(%ld,%ld)",aTimeToSample->Count,aTimeToSample->Duration);
|
||||
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
char *STTSAtom::OnGetAtomName()
|
||||
@ -494,24 +508,30 @@ char *STTSAtom::OnGetAtomName()
|
||||
return "Time to Sample Atom";
|
||||
}
|
||||
|
||||
uint32 STTSAtom::getSampleForTime(uint32 pTime)
|
||||
uint32 STTSAtom::getSampleForTime(bigtime_t pTime)
|
||||
{
|
||||
// TODO this is too slow. PreCalc when loading this?
|
||||
uint64 Duration = 0;
|
||||
// Sample for time is this calc, how does STTS help us?
|
||||
return uint32((pTime * FrameRate + 50) / 1000000.0);
|
||||
|
||||
|
||||
// TODO this is too slow. PreCalc when loading this?
|
||||
/* bigtime_t TotalDuration = 0;
|
||||
uint64 TotalCount = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
if (Duration > pTime) {
|
||||
return i;
|
||||
TotalDuration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
TotalCount += theTimeToSampleArray[i]->Count;
|
||||
if ((TotalDuration * 44100) > pTime) {
|
||||
return uint32((pTime * FrameRate + 50) / 1000000.0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0; */
|
||||
}
|
||||
|
||||
uint32 STTSAtom::getSampleForFrame(uint32 pFrame)
|
||||
{
|
||||
// Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
|
||||
// Convert frame to time and call getSampleForTime()
|
||||
return pFrame;
|
||||
}
|
||||
|
||||
@ -573,6 +593,8 @@ SampleToChunk *aSampleToChunk;
|
||||
ReadArrayHeader(&theHeader);
|
||||
|
||||
uint32 TotalPrevSamples = 0;
|
||||
|
||||
// printf("STSC:: Entries %ld\n",theHeader.NoEntries);
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
aSampleToChunk = new SampleToChunk;
|
||||
@ -588,8 +610,11 @@ SampleToChunk *aSampleToChunk;
|
||||
aSampleToChunk->TotalPrevSamples = 0;
|
||||
}
|
||||
|
||||
// printf("(%ld,%ld)",aSampleToChunk->SamplesPerChunk, aSampleToChunk->TotalPrevSamples);
|
||||
|
||||
theSampleToChunkArray[i] = aSampleToChunk;
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
char *STSCAtom::OnGetAtomName()
|
||||
@ -665,7 +690,7 @@ SyncSample *aSyncSample;
|
||||
FullAtom::OnProcessMetaData();
|
||||
|
||||
ReadArrayHeader(&theHeader);
|
||||
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
aSyncSample = new SyncSample;
|
||||
|
||||
@ -688,7 +713,7 @@ bool STSSAtom::IsSyncSample(uint32 pSampleNo)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pSampleNo > theSyncSampleArray[i]->SyncSampleNo) {
|
||||
if (pSampleNo < theSyncSampleArray[i]->SyncSampleNo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -908,28 +933,42 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
|
||||
return 0LL;
|
||||
}
|
||||
|
||||
ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : FullAtom(pStream, pstreamOffset, patomType, patomSize)
|
||||
DecoderConfigAtom::DecoderConfigAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
theVOL = NULL;
|
||||
theDecoderConfig = NULL;
|
||||
DecoderConfigSize = 0;
|
||||
}
|
||||
|
||||
ESDSAtom::~ESDSAtom()
|
||||
DecoderConfigAtom::~DecoderConfigAtom()
|
||||
{
|
||||
if (theVOL) {
|
||||
free(theVOL);
|
||||
if (theDecoderConfig) {
|
||||
free(theDecoderConfig);
|
||||
}
|
||||
}
|
||||
|
||||
bool ESDSAtom::SkipTag(uint8 Tag, uint32 *offset) {
|
||||
void DecoderConfigAtom::OnProcessMetaData()
|
||||
{
|
||||
DecoderConfigSize = getBytesRemaining();
|
||||
|
||||
theDecoderConfig = (uint8 *)(malloc(DecoderConfigSize));
|
||||
Read(theDecoderConfig,DecoderConfigSize);
|
||||
}
|
||||
|
||||
uint8 *DecoderConfigAtom::getDecoderConfig()
|
||||
{
|
||||
return theDecoderConfig;
|
||||
}
|
||||
|
||||
bool DecoderConfigAtom::SkipTag(uint8 *ESDS, uint8 Tag, uint32 *offset) {
|
||||
uint8 byte;
|
||||
|
||||
byte = theVOL[(*offset)++];
|
||||
byte = ESDS[(*offset)++];
|
||||
if (byte == Tag) {
|
||||
uint8 numBytes = 0;
|
||||
unsigned int length = 0;
|
||||
|
||||
do {
|
||||
byte = theVOL[(*offset)++];
|
||||
byte = ESDS[(*offset)++];
|
||||
numBytes++;
|
||||
length = (length << 7) | (byte & 0x7F);
|
||||
} while ((byte & 0x80) && numBytes < 4);
|
||||
@ -937,99 +976,51 @@ bool ESDSAtom::SkipTag(uint8 Tag, uint32 *offset) {
|
||||
} else {
|
||||
// go back Tag not found
|
||||
(*offset)--;
|
||||
printf("No Tag %d\n",Tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *DecoderConfigAtom::OnGetAtomName()
|
||||
{
|
||||
return "Decoder Config Atom - Unknown type";
|
||||
}
|
||||
|
||||
void DecoderConfigAtom::OverrideAudioDescription(AudioDescription *pAudioDescription)
|
||||
{
|
||||
if (pAudioDescription) {
|
||||
pAudioDescription->DecoderConfigSize = DecoderConfigSize;
|
||||
pAudioDescription->theDecoderConfig = (uint8 *)(malloc(DecoderConfigSize));
|
||||
memcpy(pAudioDescription->theDecoderConfig, theDecoderConfig, DecoderConfigSize);
|
||||
OnOverrideAudioDescription(pAudioDescription);
|
||||
}
|
||||
}
|
||||
|
||||
void DecoderConfigAtom::OverrideVideoDescription(VideoDescription *pVideoDescription)
|
||||
{
|
||||
if (pVideoDescription) {
|
||||
pVideoDescription->DecoderConfigSize = DecoderConfigSize;
|
||||
pVideoDescription->theDecoderConfig = (uint8 *)(malloc(DecoderConfigSize));
|
||||
memcpy(pVideoDescription->theDecoderConfig, theDecoderConfig, DecoderConfigSize);
|
||||
OnOverrideVideoDescription(pVideoDescription);
|
||||
}
|
||||
}
|
||||
|
||||
ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : DecoderConfigAtom(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
|
||||
ESDSAtom::~ESDSAtom()
|
||||
{
|
||||
}
|
||||
|
||||
void ESDSAtom::OnProcessMetaData()
|
||||
{
|
||||
FullAtom::OnProcessMetaData();
|
||||
|
||||
VOLSize = getBytesRemaining();
|
||||
uint32 offset = 0;
|
||||
|
||||
theVOL = (uint8 *)(malloc(VOLSize));
|
||||
Read(theVOL,VOLSize);
|
||||
|
||||
// Display the VOL
|
||||
if (VOLSize > 0) {
|
||||
if (SkipTag(0x03,&offset)) {
|
||||
offset += 3;
|
||||
} else {
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (SkipTag(0x04,&offset)) {
|
||||
printf("type id is %d", theVOL[offset]);
|
||||
switch (theVOL[offset]) {
|
||||
case 1: printf("system v1"); break;
|
||||
case 2: printf("system v2"); break;
|
||||
case 32: printf("MPEG-4 video"); break;
|
||||
case 33: printf("MPEG-4 AVC SPS"); break;
|
||||
case 34: printf("MPEG-4 AVC PPS"); break;
|
||||
case 64: printf("MPEG-4 audio"); break;
|
||||
}
|
||||
|
||||
offset+=2;
|
||||
|
||||
uint32 a,b,c;
|
||||
uint32 buff;
|
||||
|
||||
a = theVOL[offset];
|
||||
b = theVOL[offset+1];
|
||||
c = theVOL[offset+2];
|
||||
|
||||
buff = (a << 16) | (b << 8) | c;
|
||||
|
||||
printf(" buf size %ld ",buff);
|
||||
printf(" max bit rate %ld",uint32(theVOL[offset+4]));
|
||||
printf(" avg bit rate %ld\n",uint32(theVOL[offset+8]));
|
||||
}
|
||||
} else {
|
||||
printf("VOL size is 0\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t ESDSAtom::getVOLSize(bool forAudio)
|
||||
{
|
||||
uint32 offset = 0;
|
||||
if (forAudio) {
|
||||
if (SkipTag(0x03,&offset)) {
|
||||
offset += 3;
|
||||
} else {
|
||||
offset += 2;
|
||||
}
|
||||
if (SkipTag(0x04,&offset)) {
|
||||
offset += 13;
|
||||
}
|
||||
|
||||
SkipTag(0x05,&offset);
|
||||
}
|
||||
|
||||
return ( VOLSize - offset);
|
||||
}
|
||||
|
||||
uint8 *ESDSAtom::getVOL(bool forAudio)
|
||||
{
|
||||
uint32 offset = 0;
|
||||
if (forAudio) {
|
||||
if (SkipTag(0x03,&offset)) {
|
||||
offset += 3;
|
||||
} else {
|
||||
offset += 2;
|
||||
}
|
||||
if (SkipTag(0x04,&offset)) {
|
||||
offset += 13;
|
||||
}
|
||||
|
||||
SkipTag(0x05,&offset);
|
||||
}
|
||||
|
||||
return &theVOL[offset];
|
||||
// Read 4 bytes because this is really a FullAtom
|
||||
uint32 version;
|
||||
Read(&version);
|
||||
DecoderConfigAtom::OnProcessMetaData();
|
||||
}
|
||||
|
||||
char *ESDSAtom::OnGetAtomName()
|
||||
@ -1037,23 +1028,191 @@ char *ESDSAtom::OnGetAtomName()
|
||||
return "Extended Sample Description Atom";
|
||||
}
|
||||
|
||||
char *obj_type_names[]=
|
||||
{
|
||||
"Unknown",
|
||||
"Main-AAC",
|
||||
"LC-AAC",
|
||||
"SSR-AAC",
|
||||
"LTP-AAC",
|
||||
"HE-AAC",
|
||||
"HE-AAC(disabled)"
|
||||
};
|
||||
|
||||
int aac_sampling_rate[16] =
|
||||
{
|
||||
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
||||
16000, 12000, 11025, 8000, 7350, 0, 0, 0
|
||||
};
|
||||
|
||||
void ESDSAtom::OnOverrideAudioDescription(AudioDescription *pAudioDescription)
|
||||
{
|
||||
// decode for aac and check for HE-AAC which uses a framesize of 2048
|
||||
// also check for MP3 which has an ESDS
|
||||
uint32 offset = 0;
|
||||
|
||||
if (SkipTag(pAudioDescription->theDecoderConfig, 0x03, &offset)) {
|
||||
offset += 3;
|
||||
} else {
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (SkipTag(pAudioDescription->theDecoderConfig, 0x04, &offset)) {
|
||||
ESDSType = pAudioDescription->theDecoderConfig[offset];
|
||||
StreamType = pAudioDescription->theDecoderConfig[offset+1]/4;
|
||||
NeededBufferSize = uint32(pAudioDescription->theDecoderConfig[offset+2]) * 256 * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+3] * 256 + pAudioDescription->theDecoderConfig[offset+4];
|
||||
MaxBitRate = uint32(pAudioDescription->theDecoderConfig[offset+5]) * 256 * 256 * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+6] * 256 * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+7] * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+8];
|
||||
AvgBitRate = uint32(pAudioDescription->theDecoderConfig[offset+9]) * 256 * 256 * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+10] * 256 * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+11] * 256 +
|
||||
pAudioDescription->theDecoderConfig[offset+12];
|
||||
printf("obj type id is %d \n", ESDSType);
|
||||
printf("stream type is %d\n", StreamType);
|
||||
printf("Buffer Size is %ld\n", NeededBufferSize);
|
||||
printf("max Bitrate is %ld\n", MaxBitRate);
|
||||
printf("avg Bitrate is %ld\n", AvgBitRate);
|
||||
|
||||
pAudioDescription->BitRate = AvgBitRate;
|
||||
|
||||
offset+=13;
|
||||
}
|
||||
|
||||
SkipTag(pAudioDescription->theDecoderConfig, 0x05, &offset);
|
||||
uint32 buffer;
|
||||
uint32 temp;
|
||||
|
||||
switch (ESDSType) {
|
||||
case 64: // AAC
|
||||
// Attempt to read AAC Header
|
||||
buffer = pAudioDescription->theDecoderConfig[offset];
|
||||
buffer = buffer * 256 + pAudioDescription->theDecoderConfig[offset+1] ;
|
||||
buffer = buffer * 256 + pAudioDescription->theDecoderConfig[offset+2] ;
|
||||
buffer = buffer * 256 + pAudioDescription->theDecoderConfig[offset+3] ;
|
||||
|
||||
// Bits 0-5 are decoder type
|
||||
temp = GetBits(buffer,0,5);
|
||||
theAACHeader.objTypeIndex = temp;
|
||||
// Bits 6-9 are frequency index
|
||||
temp = GetBits(buffer,6,3);
|
||||
theAACHeader.sampleRateIndex = temp;
|
||||
// Bits 10-12 are channels
|
||||
temp = GetBits(buffer,10,3);
|
||||
theAACHeader.totalChannels = temp;
|
||||
|
||||
if (theAACHeader.objTypeIndex < 3) {
|
||||
pAudioDescription->codecSubType = 'mp4a';
|
||||
pAudioDescription->FrameSize = 1024;
|
||||
} else {
|
||||
pAudioDescription->codecSubType = 'haac';
|
||||
pAudioDescription->FrameSize = 2048;
|
||||
}
|
||||
|
||||
// SampleRate is in 16.16 format
|
||||
pAudioDescription->theAudioSampleEntry.SampleRate = aac_sampling_rate[theAACHeader.sampleRateIndex] * 65536 ;
|
||||
pAudioDescription->theAudioSampleEntry.ChannelCount = theAACHeader.totalChannels;
|
||||
break;
|
||||
|
||||
case 107: // MP3
|
||||
pAudioDescription->codecSubType = 'mp3';
|
||||
|
||||
// Only set this for mp3, we calc it normally
|
||||
if (NeededBufferSize > pAudioDescription->BufferSize) {
|
||||
pAudioDescription->BufferSize = NeededBufferSize;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ESDSAtom::OnOverrideVideoDescription(VideoDescription *pVideoDescription)
|
||||
{
|
||||
// Nothing to override
|
||||
}
|
||||
|
||||
ALACAtom::ALACAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : DecoderConfigAtom(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
|
||||
ALACAtom::~ALACAtom()
|
||||
{
|
||||
}
|
||||
|
||||
void ALACAtom::OnProcessMetaData()
|
||||
{
|
||||
DecoderConfigAtom::OnProcessMetaData();
|
||||
}
|
||||
|
||||
char *ALACAtom::OnGetAtomName()
|
||||
{
|
||||
return "ALAC Decoder Config Atom";
|
||||
}
|
||||
|
||||
void ALACAtom::OnOverrideAudioDescription(AudioDescription *pAudioDescription)
|
||||
{
|
||||
pAudioDescription->codecSubType = 'alac';
|
||||
pAudioDescription->FrameSize = 4096;
|
||||
}
|
||||
|
||||
void ALACAtom::OnOverrideVideoDescription(VideoDescription *pVideoDescription)
|
||||
{
|
||||
// Nothing to override
|
||||
}
|
||||
|
||||
WAVEAtom::WAVEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : DecoderConfigAtom(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
}
|
||||
|
||||
WAVEAtom::~WAVEAtom()
|
||||
{
|
||||
}
|
||||
|
||||
void WAVEAtom::OnProcessMetaData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
char *WAVEAtom::OnGetAtomName()
|
||||
{
|
||||
return "WAVE Decoder Config Atom";
|
||||
}
|
||||
|
||||
void WAVEAtom::OnOverrideAudioDescription(AudioDescription *pAudioDescription)
|
||||
{
|
||||
pAudioDescription->codecSubType = 'alac';
|
||||
pAudioDescription->FrameSize = 4096;
|
||||
}
|
||||
|
||||
void WAVEAtom::OnOverrideVideoDescription(VideoDescription *pVideoDescription)
|
||||
{
|
||||
// Nothing to override
|
||||
}
|
||||
|
||||
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;
|
||||
theAudioDescription.codecid = 0;
|
||||
theAudioDescription.codecSubType = 0;
|
||||
theAudioDescription.FrameSize = 0;
|
||||
theAudioDescription.BufferSize = 0;
|
||||
theAudioDescription.BitRate = 0;
|
||||
theAudioDescription.theDecoderConfig = NULL;
|
||||
theVideoDescription.theDecoderConfig = NULL;
|
||||
}
|
||||
|
||||
STSDAtom::~STSDAtom()
|
||||
{
|
||||
if (theAudioDescription.theVOL) {
|
||||
free(theAudioDescription.theVOL);
|
||||
theAudioDescription.theVOL = NULL;
|
||||
if (theAudioDescription.theDecoderConfig) {
|
||||
free(theAudioDescription.theDecoderConfig);
|
||||
theAudioDescription.theDecoderConfig = NULL;
|
||||
}
|
||||
|
||||
if (theVideoDescription.theVOL) {
|
||||
free(theVideoDescription.theVOL);
|
||||
theVideoDescription.theVOL = NULL;
|
||||
if (theVideoDescription.theDecoderConfig) {
|
||||
free(theVideoDescription.theDecoderConfig);
|
||||
theVideoDescription.theDecoderConfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1062,12 +1221,14 @@ uint32 STSDAtom::getMediaHandlerType()
|
||||
return dynamic_cast<STBLAtom *>(getParent())->getMediaHandlerType();
|
||||
}
|
||||
|
||||
void STSDAtom::ReadESDS(uint8 **VOL, size_t *VOLSize, bool forAudio)
|
||||
void STSDAtom::ReadDecoderConfig(uint8 **pDecoderConfig, size_t *pDecoderConfigSize, AudioDescription *pAudioDescription, VideoDescription *pVideoDescription)
|
||||
{
|
||||
// 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)
|
||||
// Check for a Decoder Config and if it exists copy it back to the caller
|
||||
// MPEG-4 video/audio use the various decoder config structures to pass additional
|
||||
// decoder information to the decoder. The extractor sometimes needs to decode the data
|
||||
// to work out how to properly construct the decoder
|
||||
|
||||
// First make sure we have a esds
|
||||
// First make sure we have a something
|
||||
if (getBytesRemaining() > 0) {
|
||||
// Well something is there so read it as an atom
|
||||
AtomBase *aAtomBase = getAtom(theStream);
|
||||
@ -1075,11 +1236,11 @@ void STSDAtom::ReadESDS(uint8 **VOL, size_t *VOLSize, bool forAudio)
|
||||
aAtomBase->ProcessMetaData();
|
||||
printf("%s [%Ld]\n",aAtomBase->getAtomName(),aAtomBase->getAtomSize());
|
||||
|
||||
if (dynamic_cast<ESDSAtom *>(aAtomBase)) {
|
||||
// ESDS atom good
|
||||
*VOLSize = dynamic_cast<ESDSAtom *>(aAtomBase)->getVOLSize(forAudio);
|
||||
*VOL = (uint8 *)(malloc(*VOLSize));
|
||||
memcpy(*VOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(forAudio),*VOLSize);
|
||||
if (dynamic_cast<DecoderConfigAtom *>(aAtomBase)) {
|
||||
// DecoderConfig atom good
|
||||
DecoderConfigAtom *aDecoderConfigAtom = dynamic_cast<DecoderConfigAtom *>(aAtomBase);
|
||||
aDecoderConfigAtom->OverrideAudioDescription(pAudioDescription);
|
||||
aDecoderConfigAtom->OverrideVideoDescription(pVideoDescription);
|
||||
|
||||
delete aAtomBase;
|
||||
} else {
|
||||
@ -1099,7 +1260,7 @@ void STSDAtom::ReadSoundDescription()
|
||||
Read(&theAudioDescription.theAudioSampleEntry.reserved);
|
||||
Read(&theAudioDescription.theAudioSampleEntry.SampleRate);
|
||||
|
||||
ReadESDS(&theAudioDescription.theVOL,&theAudioDescription.VOLSize,true);
|
||||
ReadDecoderConfig(&theAudioDescription.theDecoderConfig, &theAudioDescription.DecoderConfigSize, &theAudioDescription, NULL);
|
||||
}
|
||||
|
||||
void STSDAtom::ReadVideoDescription()
|
||||
@ -1129,7 +1290,7 @@ void STSDAtom::ReadVideoDescription()
|
||||
Read(&theVideoDescription.theVideoSampleEntry.Depth);
|
||||
Read(&theVideoDescription.theVideoSampleEntry.pre_defined3);
|
||||
|
||||
ReadESDS(&theVideoDescription.theVOL,&theVideoDescription.VOLSize, false);
|
||||
ReadDecoderConfig(&theVideoDescription.theDecoderConfig, &theVideoDescription.DecoderConfigSize, NULL, &theVideoDescription);
|
||||
}
|
||||
|
||||
void STSDAtom::OnProcessMetaData()
|
||||
@ -1331,13 +1492,13 @@ void MDATAtom::OnProcessMetaData()
|
||||
|
||||
char *MDATAtom::OnGetAtomName()
|
||||
{
|
||||
printf("Offset %lld, Size %lld ",getStreamOffset(),getAtomSize());
|
||||
printf("Offset %lld, Size %lld ",getAtomOffset(),getAtomSize() - 8);
|
||||
return "Media Data Atom";
|
||||
}
|
||||
|
||||
off_t MDATAtom::getEOF()
|
||||
{
|
||||
return getStreamOffset() + getAtomSize();
|
||||
return getAtomOffset() + getAtomSize() - 8;
|
||||
}
|
||||
|
||||
MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
|
||||
@ -1549,7 +1710,7 @@ char *MDHDAtom::OnGetAtomName()
|
||||
|
||||
bigtime_t MDHDAtom::getDuration()
|
||||
{
|
||||
return bigtime_t((uint64(theHeader.Duration) * 1000000L) / theHeader.TimeScale);
|
||||
return bigtime_t((theHeader.Duration * 1000000.0) / theHeader.TimeScale);
|
||||
}
|
||||
|
||||
uint32 MDHDAtom::getTimeScale()
|
||||
|
@ -171,15 +171,18 @@ public:
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
|
||||
uint64 getSUMCounts() {return SUMCounts;};
|
||||
uint64 getSUMDurations() {return SUMDurations;};
|
||||
uint32 getSampleForTime(uint32 pTime);
|
||||
uint64 getSUMCounts() { return SUMCounts; };
|
||||
uint64 getSUMDurations() { return SUMDurations; };
|
||||
uint32 getSampleForTime(bigtime_t pTime);
|
||||
uint32 getSampleForFrame(uint32 pFrame);
|
||||
void setFrameRate(float pFrameRate) { FrameRate = pFrameRate; };
|
||||
|
||||
private:
|
||||
array_header theHeader;
|
||||
TimeToSampleArray theTimeToSampleArray;
|
||||
uint64 SUMDurations;
|
||||
bigtime_t SUMDurations;
|
||||
uint64 SUMCounts;
|
||||
float FrameRate;
|
||||
};
|
||||
|
||||
// Atom class for reading the composition time to sample atom
|
||||
@ -300,22 +303,72 @@ public:
|
||||
off_t getEOF();
|
||||
};
|
||||
|
||||
class ESDSAtom : public FullAtom {
|
||||
// Subclass for handling special decoder config atoms like ESDS, ALAC, AVCC, AMR
|
||||
// ESDS is actually a FullAtom but others are not :-(
|
||||
class DecoderConfigAtom : public AtomBase {
|
||||
public:
|
||||
DecoderConfigAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~DecoderConfigAtom();
|
||||
virtual void OnProcessMetaData();
|
||||
virtual char *OnGetAtomName();
|
||||
|
||||
// The decoder config is what the decoder uses for it's setup
|
||||
// The values SHOULD mirror the Container values but often don't
|
||||
// So we have to parse the config and use the values as container overrides
|
||||
void OverrideAudioDescription(AudioDescription *pAudioDescription);
|
||||
virtual void OnOverrideAudioDescription(AudioDescription *pAudioDescription) {} ;
|
||||
void OverrideVideoDescription(VideoDescription *pVideoDescription);
|
||||
virtual void OnOverrideVideoDescription(VideoDescription *pVideoDescription) {} ;
|
||||
bool SkipTag(uint8 *ESDS, uint8 Tag, uint32 *offset);
|
||||
|
||||
uint8 *getDecoderConfig();
|
||||
size_t getDecoderConfigSize() { return DecoderConfigSize; } ;
|
||||
private:
|
||||
uint8 *theDecoderConfig;
|
||||
size_t DecoderConfigSize;
|
||||
};
|
||||
|
||||
// Atom class for reading the ESDS decoder config atom
|
||||
class ESDSAtom : public DecoderConfigAtom {
|
||||
public:
|
||||
ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~ESDSAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
|
||||
uint8 *getVOL(bool forAudio);
|
||||
size_t getVOLSize(bool forAudio);
|
||||
void OnOverrideAudioDescription(AudioDescription *pAudioDescription);
|
||||
void OnOverrideVideoDescription(VideoDescription *pVideoDescription);
|
||||
private:
|
||||
bool SkipTag(uint8 Tag, uint32 *offset);
|
||||
uint8 *theVOL;
|
||||
size_t VOLSize;
|
||||
uint8 ESDSType;
|
||||
uint8 StreamType;
|
||||
uint32 NeededBufferSize;
|
||||
uint32 MaxBitRate;
|
||||
uint32 AvgBitRate;
|
||||
AACHeader theAACHeader;
|
||||
};
|
||||
|
||||
// Atom class for reading the sdst atom
|
||||
// Atom class for reading the ALAC decoder config atom
|
||||
class ALACAtom : public DecoderConfigAtom {
|
||||
public:
|
||||
ALACAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~ALACAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
void OnOverrideAudioDescription(AudioDescription *pAudioDescription);
|
||||
void OnOverrideVideoDescription(VideoDescription *pVideoDescription);
|
||||
};
|
||||
|
||||
// Atom class for reading the WAVE atom for mp3 decoder config
|
||||
class WAVEAtom : public DecoderConfigAtom {
|
||||
public:
|
||||
WAVEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
virtual ~WAVEAtom();
|
||||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
void OnOverrideAudioDescription(AudioDescription *pAudioDescription);
|
||||
void OnOverrideVideoDescription(VideoDescription *pVideoDescription);
|
||||
};
|
||||
|
||||
// Atom class for reading the Sample Description atom
|
||||
class STSDAtom : public FullAtom {
|
||||
public:
|
||||
STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize);
|
||||
@ -329,10 +382,10 @@ public:
|
||||
private:
|
||||
uint32 getMediaHandlerType();
|
||||
|
||||
void ReadESDS(uint8 **VOL, size_t *VOLSize, bool forAudio);
|
||||
void ReadDecoderConfig(uint8 **pDecoderConfig, size_t *pDecoderConfigSize, AudioDescription *pAudioDescription, VideoDescription *pVideoDescription);
|
||||
void ReadSoundDescription();
|
||||
void ReadVideoDescription();
|
||||
|
||||
void ReadHintDescription();
|
||||
|
||||
uint32 codecid;
|
||||
|
||||
@ -416,14 +469,15 @@ public:
|
||||
void OnChildProcessingComplete();
|
||||
|
||||
bigtime_t Duration(uint32 TimeScale); // Return duration of track
|
||||
uint32 FrameCount() {return framecount;};
|
||||
bigtime_t Duration() { return Duration(timescale); }
|
||||
uint32 FrameCount() { return framecount; };
|
||||
bool IsVideo(); // Is this a video track
|
||||
bool IsAudio(); // Is this a audio track
|
||||
// GetAudioMetaData() // If this is a audio track get the audio meta data
|
||||
// GetVideoMetaData() // If this is a video track get the video meta data
|
||||
|
||||
uint32 getTimeForFrame(uint32 pFrame, uint32 pTimeScale);
|
||||
uint32 getSampleForTime(uint32 pTime);
|
||||
bigtime_t getTimeForFrame(uint32 pFrame);
|
||||
uint32 getSampleForTime(bigtime_t pTime);
|
||||
uint32 getSampleForFrame(uint32 pFrame);
|
||||
uint32 getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk);
|
||||
uint64 getOffsetForChunk(uint32 pChunkID);
|
||||
@ -432,6 +486,9 @@ public:
|
||||
uint32 getNoSamplesInChunk(uint32 pChunkID);
|
||||
uint32 getTotalChunks();
|
||||
|
||||
float getSampleRate();
|
||||
float getFrameRate();
|
||||
|
||||
bool IsSyncSample(uint32 pSampleNo);
|
||||
bool IsSingleSampleSize();
|
||||
bool IsActive();
|
||||
@ -446,6 +503,7 @@ private:
|
||||
|
||||
uint32 framecount;
|
||||
uint32 bytespersample;
|
||||
uint32 timescale;
|
||||
};
|
||||
|
||||
// Atom class for reading the media container atom
|
||||
|
@ -76,7 +76,8 @@ struct mp4_stream_header
|
||||
struct VideoMetaData
|
||||
{
|
||||
uint32 compression;
|
||||
uint32 size;
|
||||
uint32 codecSubType;
|
||||
uint32 BufferSize;
|
||||
uint32 width;
|
||||
uint32 height;
|
||||
uint16 planes;
|
||||
@ -85,20 +86,23 @@ struct VideoMetaData
|
||||
uint32 HorizontalResolution;
|
||||
uint32 VerticalResolution;
|
||||
uint32 FrameCount;
|
||||
float FrameRate;
|
||||
uint8 *theVOL;
|
||||
size_t VOLSize;
|
||||
float FrameRate; // Frames per second
|
||||
uint8 *theDecoderConfig;
|
||||
size_t DecoderConfigSize;
|
||||
};
|
||||
|
||||
struct AudioMetaData
|
||||
{
|
||||
uint32 compression; // compression used
|
||||
uint32 compression; // compression used (ie codecid)
|
||||
uint32 codecSubType; // Additional codecid
|
||||
uint16 NoOfChannels; // 1 = mono, 2 = stereo
|
||||
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;
|
||||
float SampleRate; // Samples per second
|
||||
uint32 BufferSize; // (Sample Rate * NoOfchannels * SampleSize * SamplesPerFrame) / 8 = bytes per second
|
||||
uint32 FrameSize; // No Of Samples in 1 frame of audio (SamplesPerFrame)
|
||||
uint32 BitRate; // Average Bitrate
|
||||
uint8 *theDecoderConfig;
|
||||
size_t DecoderConfigSize;
|
||||
};
|
||||
|
||||
struct TimeToSample {
|
||||
@ -125,7 +129,7 @@ struct ChunkToOffset {
|
||||
};
|
||||
|
||||
struct SyncSample {
|
||||
uint64 SyncSampleNo;
|
||||
uint32 SyncSampleNo;
|
||||
};
|
||||
|
||||
struct SampleSizeEntry {
|
||||
@ -235,8 +239,6 @@ struct SampleEntry {
|
||||
uint16 DataReference;
|
||||
};
|
||||
|
||||
#define SampleEntrySize sizeof(SampleEntry)
|
||||
|
||||
struct AudioSampleEntry {
|
||||
uint32 Reserved[2];
|
||||
uint16 ChannelCount;
|
||||
@ -246,13 +248,15 @@ struct AudioSampleEntry {
|
||||
uint32 SampleRate; // 16.16
|
||||
};
|
||||
|
||||
#define AudioSampleEntrySize sizeof(AudioSampleEntry)
|
||||
|
||||
struct AudioDescription {
|
||||
AudioSampleEntry theAudioSampleEntry;
|
||||
uint32 codecid;
|
||||
uint8 *theVOL;
|
||||
size_t VOLSize;
|
||||
uint32 codecSubType;
|
||||
uint32 FrameSize;
|
||||
uint32 BufferSize;
|
||||
uint32 BitRate;
|
||||
uint8 *theDecoderConfig;
|
||||
size_t DecoderConfigSize;
|
||||
};
|
||||
|
||||
struct VideoSampleEntry {
|
||||
@ -270,13 +274,22 @@ struct VideoSampleEntry {
|
||||
uint16 pre_defined3;
|
||||
};
|
||||
|
||||
#define VideoSampleEntrySize 70
|
||||
|
||||
struct VideoDescription {
|
||||
VideoSampleEntry theVideoSampleEntry;
|
||||
uint32 codecid;
|
||||
uint8 *theVOL;
|
||||
size_t VOLSize;
|
||||
uint32 codecSubType;
|
||||
uint8 *theDecoderConfig;
|
||||
size_t DecoderConfigSize;
|
||||
};
|
||||
|
||||
// The parts of the AAC ESDS we care about
|
||||
struct AACHeader {
|
||||
uint8 objTypeIndex;
|
||||
uint8 sampleRateIndex;
|
||||
uint8 totalChannels;
|
||||
uint16 frameSize;
|
||||
uint16 adtsBuffer;
|
||||
uint8 totalDataBlocksInFrame;
|
||||
};
|
||||
|
||||
#endif // MP4_STRUCTS_H
|
||||
|
@ -30,6 +30,7 @@ TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType,
|
||||
theMDHDAtom = NULL;
|
||||
framecount = 0;
|
||||
bytespersample = 0;
|
||||
timescale = 1;
|
||||
}
|
||||
|
||||
TRAKAtom::~TRAKAtom()
|
||||
@ -78,16 +79,20 @@ bigtime_t TRAKAtom::Duration(uint32 TimeScale)
|
||||
return getMDHDAtom()->getDuration();
|
||||
}
|
||||
|
||||
return bigtime_t(getTKHDAtom()->getDuration() * 1000000L) / TimeScale;
|
||||
return bigtime_t(getTKHDAtom()->getDuration() * 1000000.0) / TimeScale;
|
||||
}
|
||||
|
||||
void TRAKAtom::OnChildProcessingComplete()
|
||||
{
|
||||
timescale = getMDHDAtom()->getTimeScale();
|
||||
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(GetChildAtom(uint32('stts'),0));
|
||||
|
||||
if (aSTTSAtom) {
|
||||
framecount = aSTTSAtom->getSUMCounts();
|
||||
aSTTSAtom->setFrameRate(getFrameRate());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Is this a video track
|
||||
@ -104,25 +109,46 @@ bool TRAKAtom::IsAudio()
|
||||
return (GetChildAtom(uint32('smhd'),0) != NULL);
|
||||
}
|
||||
|
||||
uint32 TRAKAtom::getTimeForFrame(uint32 pFrame, uint32 pTimeScale)
|
||||
// frames per us
|
||||
float TRAKAtom::getFrameRate()
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
|
||||
|
||||
if (aAtomBase) {
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
|
||||
if (IsAudio()) {
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stsd'),0);
|
||||
if (aAtomBase) {
|
||||
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
|
||||
|
||||
if (IsAudio()) {
|
||||
// Frame * SampleRate = Time
|
||||
} else if (IsVideo()) {
|
||||
// Frame * fps = Time
|
||||
return pFrame * ((aSTTSAtom->getSUMCounts() * 1000000L) / Duration(pTimeScale));
|
||||
AudioDescription aAudioDescription = aSTSDAtom->getAsAudio();
|
||||
return (aAudioDescription.theAudioSampleEntry.SampleRate / 65536.0) / aAudioDescription.FrameSize;
|
||||
}
|
||||
} else if (IsVideo()) {
|
||||
return (framecount * 1000000.0) / Duration();
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float TRAKAtom::getSampleRate()
|
||||
{
|
||||
// Only valid for Audio
|
||||
if (IsAudio()) {
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stsd'),0);
|
||||
if (aAtomBase) {
|
||||
STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
|
||||
|
||||
AudioDescription aAudioDescription = aSTSDAtom->getAsAudio();
|
||||
return aAudioDescription.theAudioSampleEntry.SampleRate / 65536;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
uint32 TRAKAtom::getSampleForTime(uint32 pTime)
|
||||
bigtime_t TRAKAtom::getTimeForFrame(uint32 pFrame)
|
||||
{
|
||||
return bigtime_t((pFrame * 1000000.0) / getFrameRate());
|
||||
}
|
||||
|
||||
uint32 TRAKAtom::getSampleForTime(bigtime_t pTime)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
|
||||
|
||||
@ -138,7 +164,7 @@ uint32 TRAKAtom::getSampleForFrame(uint32 pFrame)
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
|
||||
|
||||
if (aAtomBase) {
|
||||
return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForFrame(pFrame);
|
||||
return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForTime(getTimeForFrame(pFrame));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -262,6 +288,3 @@ uint32 TRAKAtom::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
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//#define TRACE_MP4_READER
|
||||
#define TRACE_MP4_READER
|
||||
#ifdef TRACE_MP4_READER
|
||||
# define TRACE printf
|
||||
#else
|
||||
@ -60,8 +60,6 @@ struct mp4_cookie {
|
||||
bool audio;
|
||||
|
||||
// audio only:
|
||||
off_t byte_pos;
|
||||
uint32 chunk_pos;
|
||||
uint32 bytes_per_sec_rate;
|
||||
uint32 bytes_per_sec_scale;
|
||||
|
||||
@ -145,6 +143,9 @@ mp4Reader::GetFileFormatInfo(media_file_format *mff)
|
||||
status_t
|
||||
mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
{
|
||||
size_t size;
|
||||
const void *data;
|
||||
|
||||
mp4_cookie *cookie = new mp4_cookie;
|
||||
*_cookie = cookie;
|
||||
|
||||
@ -181,12 +182,10 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
cookie->frame_count = theFileReader->getAudioFrameCount(cookie->stream);
|
||||
cookie->frame_count = theFileReader->getFrameCount(cookie->stream);
|
||||
cookie->duration = theFileReader->getAudioDuration(cookie->stream);
|
||||
|
||||
cookie->audio = true;
|
||||
cookie->byte_pos = 0;
|
||||
cookie->chunk_pos = 1;
|
||||
|
||||
if (stream_header->scale && stream_header->rate) {
|
||||
cookie->bytes_per_sec_rate = stream_header->rate *
|
||||
@ -196,6 +195,8 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
cookie->frames_per_sec_scale = stream_header->scale;
|
||||
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using both)\n",
|
||||
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using both)\n",
|
||||
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
} else if (stream_header->rate) {
|
||||
cookie->bytes_per_sec_rate = stream_header->rate * audio_format->SampleSize
|
||||
* audio_format->NoOfChannels / 8;
|
||||
@ -204,14 +205,8 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
cookie->frames_per_sec_scale = 1;
|
||||
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using rate)\n",
|
||||
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
||||
} else if (audio_format->PacketSize) {
|
||||
cookie->bytes_per_sec_rate = audio_format->PacketSize;
|
||||
cookie->bytes_per_sec_scale = 1;
|
||||
cookie->frames_per_sec_rate = audio_format->PacketSize * 8
|
||||
/ audio_format->SampleSize / audio_format->NoOfChannels;
|
||||
cookie->frames_per_sec_scale = 1;
|
||||
TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using PacketSize)\n",
|
||||
cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale);
|
||||
TRACE("frames_per_sec_rate %ld, frames_per_sec_scale %ld (using rate)\n",
|
||||
cookie->frames_per_sec_rate, cookie->frames_per_sec_scale);
|
||||
} else {
|
||||
cookie->bytes_per_sec_rate = 128000;
|
||||
cookie->bytes_per_sec_scale = 8;
|
||||
@ -294,10 +289,32 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
format->u.encoded_audio.output.channel_count = audio_format->NoOfChannels;
|
||||
break;
|
||||
case 'mp4a':
|
||||
TRACE("AAC Audio (mp4a)\n");
|
||||
format->u.encoded_audio.bit_rate = 8 * cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;
|
||||
format->u.encoded_audio.output.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;
|
||||
case 'alac':
|
||||
TRACE("AAC audio (mp4a) or ALAC audio\n");
|
||||
|
||||
format->u.encoded_audio.output.frame_rate = cookie->frames_per_sec_rate / cookie->frames_per_sec_scale;;
|
||||
format->u.encoded_audio.output.channel_count = audio_format->NoOfChannels;
|
||||
format->u.encoded_audio.output.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||
format->u.encoded_audio.output.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
|
||||
|
||||
// AAC is 1024 samples per frame
|
||||
// HE-AAC is 2048 samples per frame
|
||||
// ALAC is 4096 samples per frame
|
||||
|
||||
format->u.encoded_audio.frame_size = audio_format->FrameSize;
|
||||
format->u.encoded_audio.output.buffer_size = audio_format->BufferSize;
|
||||
|
||||
// Average BitRate = (TotalBytes * 8 * (SampleRate / FrameSize)) / TotalFrames
|
||||
// Setting a bitrate seems to cause more problems than it solves
|
||||
format->u.encoded_audio.bit_rate = audio_format->BitRate; // usually 128000 for AAC
|
||||
|
||||
printf("Audio NoOfChannels %d, SampleSize %d, SampleRate %f, FrameSize %ld\n",audio_format->NoOfChannels, audio_format->SampleSize, audio_format->SampleRate, audio_format->FrameSize);
|
||||
|
||||
printf("Audio frame_rate %f, channel_count %ld, format %ld, buffer_size %ld, frame_size %ld, bit_rate %f\n",
|
||||
format->u.encoded_audio.output.frame_rate, format->u.encoded_audio.output.channel_count, format->u.encoded_audio.output.format,format->u.encoded_audio.output.buffer_size, format->u.encoded_audio.frame_size, format->u.encoded_audio.bit_rate);
|
||||
|
||||
printf("Track %d MP4 Audio FrameCount %ld\n",cookie->stream,theFileReader->getFrameCount(cookie->stream));
|
||||
|
||||
break;
|
||||
default:
|
||||
char cc1,cc2,cc3,cc4;
|
||||
@ -315,49 +332,18 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
|
||||
}
|
||||
}
|
||||
|
||||
/* if (audio_format->compression == 0x0001) {
|
||||
// a raw PCM format
|
||||
description.family = B_BEOS_FORMAT_FAMILY;
|
||||
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
||||
if (B_OK != formats.GetFormatFor(description, format))
|
||||
format->type = B_MEDIA_RAW_AUDIO;
|
||||
format->u.raw_audio.frame_rate = audio_format->SampleRate;
|
||||
format->u.raw_audio.channel_count = audio_format->NoOfChannels;
|
||||
if (audio_format->bits_per_sample <= 8)
|
||||
format->u.raw_audio.format = B_AUDIO_FORMAT_UINT8;
|
||||
else if (audio_format->bits_per_sample <= 16)
|
||||
format->u.raw_audio.format = B_AUDIO_FORMAT_INT16;
|
||||
else if (audio_format->bits_per_sample <= 24)
|
||||
format->u.raw_audio.format = B_AUDIO_FORMAT_INT24;
|
||||
else if (audio_format->bits_per_sample <= 32)
|
||||
format->u.raw_audio.format = B_AUDIO_FORMAT_INT32;
|
||||
else {
|
||||
ERROR("movReader::AllocateCookie: unhandled bits per sample %d\n", audio_format->bits_per_sample);
|
||||
return B_ERROR;
|
||||
}
|
||||
format->u.raw_audio.format |= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE;
|
||||
format->u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN;
|
||||
format->u.raw_audio.buffer_size = stream_header->suggested_buffer_size;
|
||||
} else {
|
||||
// some encoded format
|
||||
description.family = B_WAV_FORMAT_FAMILY;
|
||||
description.u.wav.codec = audio_format->compression;
|
||||
if (B_OK != formats.GetFormatFor(description, format))
|
||||
format->type = B_MEDIA_ENCODED_AUDIO;
|
||||
format->u.encoded_audio.bit_rate = 8 * audio_format->PacketSize;
|
||||
TRACE("bit_rate %.3f\n", format->u.encoded_audio.bit_rate);
|
||||
format->u.encoded_audio.output.frame_rate = audio_format->SampleRate;
|
||||
format->u.encoded_audio.output.channel_count = audio_format->NoOfChannels;
|
||||
}
|
||||
*/
|
||||
// this doesn't seem to work (it's not even a fourcc)
|
||||
format->user_data_type = B_CODEC_TYPE_INFO;
|
||||
*(uint32 *)format->user_data = audio_format->compression; format->user_data[4] = 0;
|
||||
|
||||
// Set the VOL
|
||||
size_t size = audio_format->VOLSize;
|
||||
const void *data = audio_format->theVOL;
|
||||
format->SetMetaData(data, size);
|
||||
// Set the DecoderConfigSize
|
||||
size = audio_format->DecoderConfigSize;
|
||||
data = audio_format->theDecoderConfig;
|
||||
if (size > 0) {
|
||||
if (format->SetMetaData(data, size) != B_OK) {
|
||||
printf("Failed to set Decoder Config\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TRACE_MP4_READER
|
||||
if (data) {
|
||||
@ -463,13 +449,13 @@ 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
|
||||
if (video_format->VOLSize > 0) {
|
||||
TRACE("VOL Found Size is %ld\n",video_format->VOLSize);
|
||||
size_t size = video_format->VOLSize;
|
||||
const void *data = video_format->theVOL;
|
||||
// Set the Decoder Config
|
||||
size = video_format->DecoderConfigSize;
|
||||
data = video_format->theDecoderConfig;
|
||||
if (size > 0) {
|
||||
TRACE("Decoder Config Found Size is %ld\n",size);
|
||||
if (format->SetMetaData(data, size) != B_OK) {
|
||||
ERROR("Failed to set VOL\n %d %d",(16 << 20),32000);
|
||||
printf("Failed to set Decoder Config\n");
|
||||
}
|
||||
|
||||
#ifdef TRACE_MP4_READER
|
||||
@ -514,12 +500,12 @@ mp4Reader::GetStreamInfo(void *_cookie, int64 *frameCount, bigtime_t *duration,
|
||||
// Copy metadata to infoBuffer
|
||||
if (theFileReader->IsVideo(cookie->stream)) {
|
||||
const VideoMetaData *video_format = theFileReader->VideoFormat(cookie->stream);
|
||||
*infoBuffer = video_format->theVOL;
|
||||
*infoSize = video_format->VOLSize;
|
||||
*infoBuffer = video_format->theDecoderConfig;
|
||||
*infoSize = video_format->DecoderConfigSize;
|
||||
} else {
|
||||
const AudioMetaData *audio_format = theFileReader->AudioFormat(cookie->stream);
|
||||
*infoBuffer = audio_format->theVOL;
|
||||
*infoSize = audio_format->VOLSize;
|
||||
*infoBuffer = audio_format->theDecoderConfig;
|
||||
*infoSize = audio_format->DecoderConfigSize;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
@ -538,16 +524,16 @@ mp4Reader::Seek(void *cookie, uint32 seekTo, int64 *frame, bigtime_t *time)
|
||||
// frame = (time * rate) / fps / 1000000LL
|
||||
*frame = ((*time * mp4cookie->frames_per_sec_rate) / (int64)mp4cookie->frames_per_sec_scale) / 1000000LL;
|
||||
TRACE("Time %Ld to Frame %Ld\n",*time, *frame);
|
||||
// movcookie->frame_pos = *frame;
|
||||
// return B_ERROR;
|
||||
mp4cookie->frame_pos = *frame;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
|
||||
// time = frame * 1000000LL * fps / rate
|
||||
TRACE("Frame %Ld to Time %Ld\n", *frame, *time);
|
||||
*time = (*frame * 1000000LL * (int64)mp4cookie->frames_per_sec_scale) / mp4cookie->frames_per_sec_rate;
|
||||
// movcookie->frame_pos = *frame;
|
||||
// return B_ERROR;
|
||||
mp4cookie->frame_pos = *frame;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
TRACE("mp4Reader::Seek: seekTo%s%s%s%s, time %Ld, frame %Ld\n",
|
||||
@ -570,16 +556,9 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
||||
uint32 size;
|
||||
bool keyframe;
|
||||
|
||||
if (cookie->audio) {
|
||||
// use chunk position
|
||||
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->chunk_pos,
|
||||
&start, &size, &keyframe))
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
} else {
|
||||
// use frame position
|
||||
if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos,
|
||||
&start, &size, &keyframe))
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
if (theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe) == false) {
|
||||
TRACE("LAST BUFFER ERROR\n");
|
||||
return B_LAST_BUFFER_ERROR;
|
||||
}
|
||||
|
||||
if (cookie->buffer_size < size) {
|
||||
@ -589,36 +568,23 @@ mp4Reader::GetNextChunk(void *_cookie, const void **chunkBuffer,
|
||||
}
|
||||
|
||||
if (cookie->audio) {
|
||||
TRACE("Audio stream %d: chunk %ld expected start time %lld output size %ld key %d\n",cookie->stream, cookie->chunk_pos, start, size, keyframe);
|
||||
// TRACE("Audio stream %d: frame %ld expected start time %lld output size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
mediaHeader->type = B_MEDIA_ENCODED_AUDIO;
|
||||
mediaHeader->u.encoded_audio.buffer_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||
|
||||
// This will only work with raw audio I think.
|
||||
mediaHeader->start_time = (cookie->byte_pos * 1000000LL * cookie->bytes_per_sec_scale) / cookie->bytes_per_sec_rate;
|
||||
TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using byte_pos\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->chunk_pos),mediaHeader->start_time);
|
||||
|
||||
// We should find the current frame position (ie first frame in chunk) then compute using fps
|
||||
cookie->frame_pos = theFileReader->getFirstFrameInChunk(cookie->stream,cookie->chunk_pos);
|
||||
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
||||
TRACE("Audio - Frames in Chunk %ld / Actual Start Time %Ld using frame_no %ld\n",theFileReader->getNoFramesInChunk(cookie->stream,cookie->chunk_pos),mediaHeader->start_time, cookie->frame_pos);
|
||||
|
||||
cookie->byte_pos += size;
|
||||
// frame_pos is chunk No for audio
|
||||
cookie->chunk_pos++;
|
||||
} else {
|
||||
TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
mediaHeader->start_time = (cookie->frame_pos * 1000000LL * (int64)cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
||||
// TRACE("Video stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe);
|
||||
mediaHeader->type = B_MEDIA_ENCODED_VIDEO;
|
||||
mediaHeader->u.encoded_video.field_flags = keyframe ? B_MEDIA_KEY_FRAME : 0;
|
||||
mediaHeader->u.encoded_video.first_active_line = 0;
|
||||
mediaHeader->u.encoded_video.line_count = cookie->line_count;
|
||||
mediaHeader->u.encoded_video.field_number = 0;
|
||||
mediaHeader->u.encoded_video.field_sequence = cookie->frame_pos;
|
||||
|
||||
cookie->frame_pos++;
|
||||
}
|
||||
|
||||
mediaHeader->start_time = bigtime_t(cookie->frame_pos * 1000000.0 * cookie->frames_per_sec_scale) / cookie->frames_per_sec_rate;
|
||||
cookie->frame_pos++;
|
||||
|
||||
TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);
|
||||
// TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);
|
||||
|
||||
*chunkBuffer = cookie->buffer;
|
||||
*chunkSize = size;
|
||||
|
Loading…
Reference in New Issue
Block a user