added support to MOV for MPEG4 video

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14026 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
David McPaul
2005-08-21 05:12:22 +00:00
parent 2fcd430e35
commit a658e5df2d
9 changed files with 141 additions and 15 deletions
@@ -86,7 +86,7 @@ bool AtomBase::MoveToEnd()
off_t NewPosition = streamOffset + atomSize; off_t NewPosition = streamOffset + atomSize;
if (getStream()->Position() != NewPosition) { if (getStream()->Position() != NewPosition) {
return (getStream()->Seek(NewPosition,0) > 0); return (getStream()->Seek(NewPosition,SEEK_SET) > 0);
} }
return true; return true;
} }
@@ -104,6 +104,8 @@ public:
off_t getAtomOffset() {return atomOffset;}; off_t getAtomOffset() {return atomOffset;};
off_t getStreamOffset() {return streamOffset;}; off_t getStreamOffset() {return streamOffset;};
uint64 getDataSize() {return atomSize - 8;};
uint64 getBytesRemaining(); uint64 getBytesRemaining();
bool IsType(uint32 patomType) {return patomType == atomType;}; bool IsType(uint32 patomType) {return patomType == atomType;};
@@ -460,6 +460,9 @@ const AudioMetaData *MOVFileReader::AudioFormat(uint32 stream_index, size_t *
theAudio.SampleRate = aSoundDescription.desc.SampleRate / 65536; // Convert from fixed point decimal to float theAudio.SampleRate = aSoundDescription.desc.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 = aSoundDescription.theVOL;
theAudio.VOLSize = aSoundDescription.VOLSize;
// // Do we have a wave structure // // Do we have a wave structure
// if ((aSoundDescription.samplesPerPacket == 0) && (aSoundDescription.theWaveFormat.format_tag != 0)) { // if ((aSoundDescription.samplesPerPacket == 0) && (aSoundDescription.theWaveFormat.format_tag != 0)) {
// theAudio.PacketSize = aSoundDescription.theWaveFormat.frames_per_sec; // theAudio.PacketSize = aSoundDescription.theWaveFormat.frames_per_sec;
@@ -502,6 +505,9 @@ const VideoMetaData *MOVFileReader::VideoFormat(uint32 stream_index)
theVideo.HorizontalResolution = aVideoDescriptionV0.desc.HorizontalResolution; theVideo.HorizontalResolution = aVideoDescriptionV0.desc.HorizontalResolution;
theVideo.VerticalResolution = aVideoDescriptionV0.desc.VerticalResolution; theVideo.VerticalResolution = aVideoDescriptionV0.desc.VerticalResolution;
theVideo.theVOL = aVideoDescriptionV0.theVOL;
theVideo.VOLSize = aVideoDescriptionV0.VOLSize;
aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0); aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0);
if (aAtomBase) { if (aAtomBase) {
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase); STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
@@ -173,6 +173,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);
} }
@@ -718,6 +722,34 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
return 0LL; return 0LL;
} }
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()));
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) : AtomBase(pStream, pstreamOffset, patomType, patomSize) STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
{ {
theHeader.NoEntries = 0; theHeader.NoEntries = 0;
@@ -727,11 +759,21 @@ STSDAtom::~STSDAtom()
{ {
if (getMediaComponentSubType() == 'soun') { if (getMediaComponentSubType() == 'soun') {
for (uint32 i=0;i<theHeader.NoEntries;i++) { for (uint32 i=0;i<theHeader.NoEntries;i++) {
if (theAudioDescArray[i]->theVOL) {
free(theAudioDescArray[i]->theVOL);
theAudioDescArray[i]->theVOL = NULL;
}
delete theAudioDescArray[i]; delete theAudioDescArray[i];
theAudioDescArray[i] = NULL; theAudioDescArray[i] = NULL;
} }
} else if (getMediaComponentSubType() == 'vide') { } else if (getMediaComponentSubType() == 'vide') {
for (uint32 i=0;i<theHeader.NoEntries;i++) { for (uint32 i=0;i<theHeader.NoEntries;i++) {
if (theVideoDescArray[i]->theVOL) {
free(theVideoDescArray[i]->theVOL);
theVideoDescArray[i]->theVOL = NULL;
}
delete theVideoDescArray[i]; delete theVideoDescArray[i];
theVideoDescArray[i] = NULL; theVideoDescArray[i] = NULL;
} }
@@ -755,6 +797,9 @@ void STSDAtom::ReadSoundDescription()
Read(aSoundDescriptionV1->basefields.Reserved,6); Read(aSoundDescriptionV1->basefields.Reserved,6);
Read(&aSoundDescriptionV1->basefields.DataReference); Read(&aSoundDescriptionV1->basefields.DataReference);
aSoundDescriptionV1->VOLSize = 0;
aSoundDescriptionV1->theVOL = NULL;
// Read in Audio Sample Data // Read in Audio Sample Data
// We place into a V1 description even though it might be a V0 or earlier // We place into a V1 description even though it might be a V0 or earlier
@@ -803,6 +848,13 @@ void STSDAtom::ReadSoundDescription()
aSoundDescriptionV1->theWaveFormat = dynamic_cast<WAVEAtom *>(aAtomBase)->getWaveFormat(); aSoundDescriptionV1->theWaveFormat = dynamic_cast<WAVEAtom *>(aAtomBase)->getWaveFormat();
} }
if (dynamic_cast<ESDSAtom *>(aAtomBase)) {
// ESDS atom good
aSoundDescriptionV1->VOLSize = aAtomBase->getDataSize();
aSoundDescriptionV1->theVOL = (uint8 *)(malloc(aSoundDescriptionV1->VOLSize));
memcpy(aSoundDescriptionV1->theVOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(),aSoundDescriptionV1->VOLSize);
}
if (aAtomBase->getAtomSize() > 0) { if (aAtomBase->getAtomSize() > 0) {
descBytesLeft = descBytesLeft - aAtomBase->getAtomSize(); descBytesLeft = descBytesLeft - aAtomBase->getAtomSize();
} else { } else {
@@ -811,7 +863,6 @@ void STSDAtom::ReadSoundDescription()
} }
delete aAtomBase; delete aAtomBase;
} }
theAudioDescArray[0] = aSoundDescriptionV1; theAudioDescArray[0] = aSoundDescriptionV1;
@@ -821,6 +872,8 @@ void STSDAtom::ReadSoundDescription()
void STSDAtom::ReadVideoDescription() void STSDAtom::ReadVideoDescription()
{ {
uint64 descBytesLeft;
// read in Video Sample Data // read in Video Sample Data
VideoDescriptionV0 *aVideoDescription; VideoDescriptionV0 *aVideoDescription;
@@ -847,8 +900,38 @@ void STSDAtom::ReadVideoDescription()
Read(&aVideoDescription->desc.Depth); Read(&aVideoDescription->desc.Depth);
Read(&aVideoDescription->desc.ColourTableID); Read(&aVideoDescription->desc.ColourTableID);
aVideoDescription->VOLSize = 0;
aVideoDescription->theVOL = NULL;
theVideoDescArray[0] = aVideoDescription; theVideoDescArray[0] = aVideoDescription;
descBytesLeft = getBytesRemaining();
// May be a VOL
// If not then seek back to where we are as it may be a complete new video description
if (descBytesLeft > 0) {
off_t pos = theStream->Position();
// More extended atoms
AtomBase *aAtomBase = getAtom(theStream);
aAtomBase->OnProcessMetaData();
printf("%s\n",aAtomBase->getAtomName());
if (dynamic_cast<ESDSAtom *>(aAtomBase)) {
// ESDS atom good
aVideoDescription->VOLSize = aAtomBase->getDataSize();
aVideoDescription->theVOL = (uint8 *)(malloc(aVideoDescription->VOLSize));
memcpy(aVideoDescription->theVOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(),aVideoDescription->VOLSize);
} else {
// Seek Back
theStream->Seek(pos,SEEK_SET);
}
delete aAtomBase;
}
PRINT(("Size:Format=%ld:%ld %Ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,getBytesRemaining())); PRINT(("Size:Format=%ld:%ld %Ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,getBytesRemaining()));
} }
@@ -873,7 +956,9 @@ void STSDAtom::OnProcessMetaData()
Read(aSampleDescBase.Reserved,6); Read(aSampleDescBase.Reserved,6);
Read(&aSampleDescBase.DataReference); Read(&aSampleDescBase.DataReference);
theStream->Seek(aSampleDescBase.Size - SampleDescBaseSize, 0); printf("%c%c%c%c\n",char(aSampleDescBase.DataFormat>>24),char(aSampleDescBase.DataFormat>>16),char(aSampleDescBase.DataFormat>>8),char(aSampleDescBase.DataFormat));
theStream->Seek(aSampleDescBase.Size - SampleDescBaseSize, SEEK_CUR);
break; break;
} }
} }
@@ -254,6 +254,18 @@ public:
off_t getEOF(); 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
class STSDAtom : public AtomBase { class STSDAtom : public AtomBase {
public: public:
@@ -293,7 +305,7 @@ public:
// 0x008 Track in Poster // 0x008 Track in Poster
// It seems active tracks have all 4 flags set? // It seems active tracks have all 4 flags set?
bool IsActive() {return (theHeader.Flags3 == 0x0f);}; bool IsActive() {return ((theHeader.Flags3 == 0x0f) || (theHeader.Flags3 == 0x03));};
private: private:
tkhdV1 theHeader; tkhdV1 theHeader;
@@ -92,6 +92,8 @@ struct VideoMetaData
uint32 HorizontalResolution; uint32 HorizontalResolution;
uint32 VerticalResolution; uint32 VerticalResolution;
float FrameRate; float FrameRate;
uint8 *theVOL;
size_t VOLSize;
}; };
struct AudioMetaData struct AudioMetaData
@@ -101,6 +103,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 wave_format_ex struct wave_format_ex
@@ -306,6 +310,8 @@ struct SoundDescriptionV1 {
uint32 bytesPerSample; uint32 bytesPerSample;
// These are optional data from atoms that follow // These are optional data from atoms that follow
wave_format_ex theWaveFormat; // wave atom is a copy of wave_format_ex wave_format_ex theWaveFormat; // wave atom is a copy of wave_format_ex
uint8 *theVOL;
size_t VOLSize;
}; };
struct VideoDescription { struct VideoDescription {
@@ -331,4 +337,6 @@ struct VideoDescription {
struct VideoDescriptionV0 { struct VideoDescriptionV0 {
SampleDescBase basefields; SampleDescBase basefields;
VideoDescription desc; VideoDescription desc;
uint8 *theVOL;
size_t VOLSize;
}; };
@@ -402,6 +402,14 @@ movReader::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
if (video_format->VOLSize > 0) {
TRACE("VOL SIZE %ld\n", video_format->VOLSize);
size_t size = video_format->VOLSize;
const void *data = video_format->theVOL;
format->SetMetaData(data, size);
}
return B_OK; return B_OK;
} }
@@ -899,7 +899,10 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
return theChunkToOffsetArray[pChunkID - 1]->Offset; return theChunkToOffsetArray[pChunkID - 1]->Offset;
} }
DEBUGGER(("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries)); #if DEBUG
char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries);
DEBUGGER(msg);
#endif
TRESPASS(); TRESPASS();
return 0LL; return 0LL;
@@ -427,17 +427,19 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
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 // Set the VOL
size_t size = video_format->VOLSize; if (video_format->VOLSize > 0) {
const void *data = video_format->theVOL; size_t size = video_format->VOLSize;
format->SetMetaData(data, size); const void *data = video_format->theVOL;
format->SetMetaData(data, size);
#ifdef TRACE_MP4_READER #ifdef TRACE_MP4_READER
if (data) { if (data) {
uint8 *p = (uint8 *)data; uint8 *p = (uint8 *)data;
TRACE("extra_data: %ld: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 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]); 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;
} }