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

View File

@ -86,7 +86,7 @@ bool AtomBase::MoveToEnd()
off_t NewPosition = streamOffset + atomSize;
if (getStream()->Position() != NewPosition) {
return (getStream()->Seek(NewPosition,0) > 0);
return (getStream()->Seek(NewPosition,SEEK_SET) > 0);
}
return true;
}

View File

@ -104,6 +104,8 @@ public:
off_t getAtomOffset() {return atomOffset;};
off_t getStreamOffset() {return streamOffset;};
uint64 getDataSize() {return atomSize - 8;};
uint64 getBytesRemaining();
bool IsType(uint32 patomType) {return patomType == atomType;};

View File

@ -459,6 +459,9 @@ const AudioMetaData *MOVFileReader::AudioFormat(uint32 stream_index, size_t *
theAudio.SampleSize = aSoundDescription.desc.SampleSize;
theAudio.SampleRate = aSoundDescription.desc.SampleRate / 65536; // Convert from fixed point decimal to float
theAudio.PacketSize = uint32((theAudio.SampleRate * theAudio.NoOfChannels * theAudio.SampleSize) / 8);
theAudio.theVOL = aSoundDescription.theVOL;
theAudio.VOLSize = aSoundDescription.VOLSize;
// // Do we have a wave structure
// if ((aSoundDescription.samplesPerPacket == 0) && (aSoundDescription.theWaveFormat.format_tag != 0)) {
@ -502,6 +505,9 @@ const VideoMetaData *MOVFileReader::VideoFormat(uint32 stream_index)
theVideo.HorizontalResolution = aVideoDescriptionV0.desc.HorizontalResolution;
theVideo.VerticalResolution = aVideoDescriptionV0.desc.VerticalResolution;
theVideo.theVOL = aVideoDescriptionV0.theVOL;
theVideo.VOLSize = aVideoDescriptionV0.VOLSize;
aAtomBase = aTrakAtom->GetChildAtom(uint32('stts'),0);
if (aAtomBase) {
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);

View File

@ -173,6 +173,10 @@ AtomBase *getAtom(BPositionIO *pStream)
return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
if (aAtomType == uint32('esds')) {
return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
}
@ -718,6 +722,34 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
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)
{
theHeader.NoEntries = 0;
@ -727,11 +759,21 @@ STSDAtom::~STSDAtom()
{
if (getMediaComponentSubType() == 'soun') {
for (uint32 i=0;i<theHeader.NoEntries;i++) {
if (theAudioDescArray[i]->theVOL) {
free(theAudioDescArray[i]->theVOL);
theAudioDescArray[i]->theVOL = NULL;
}
delete theAudioDescArray[i];
theAudioDescArray[i] = NULL;
}
} else if (getMediaComponentSubType() == 'vide') {
for (uint32 i=0;i<theHeader.NoEntries;i++) {
if (theVideoDescArray[i]->theVOL) {
free(theVideoDescArray[i]->theVOL);
theVideoDescArray[i]->theVOL = NULL;
}
delete theVideoDescArray[i];
theVideoDescArray[i] = NULL;
}
@ -755,6 +797,9 @@ void STSDAtom::ReadSoundDescription()
Read(aSoundDescriptionV1->basefields.Reserved,6);
Read(&aSoundDescriptionV1->basefields.DataReference);
aSoundDescriptionV1->VOLSize = 0;
aSoundDescriptionV1->theVOL = NULL;
// Read in Audio Sample Data
// We place into a V1 description even though it might be a V0 or earlier
@ -802,7 +847,14 @@ void STSDAtom::ReadSoundDescription()
// WAVE atom
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) {
descBytesLeft = descBytesLeft - aAtomBase->getAtomSize();
} else {
@ -811,7 +863,6 @@ void STSDAtom::ReadSoundDescription()
}
delete aAtomBase;
}
theAudioDescArray[0] = aSoundDescriptionV1;
@ -821,6 +872,8 @@ void STSDAtom::ReadSoundDescription()
void STSDAtom::ReadVideoDescription()
{
uint64 descBytesLeft;
// read in Video Sample Data
VideoDescriptionV0 *aVideoDescription;
@ -830,7 +883,7 @@ void STSDAtom::ReadVideoDescription()
Read(&aVideoDescription->basefields.DataFormat);
Read(aVideoDescription->basefields.Reserved,6);
Read(&aVideoDescription->basefields.DataReference);
Read(&aVideoDescription->desc.Version);
Read(&aVideoDescription->desc.Revision);
Read(&aVideoDescription->desc.Vendor);
@ -847,8 +900,38 @@ void STSDAtom::ReadVideoDescription()
Read(&aVideoDescription->desc.Depth);
Read(&aVideoDescription->desc.ColourTableID);
aVideoDescription->VOLSize = 0;
aVideoDescription->theVOL = NULL;
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()));
}
@ -872,8 +955,10 @@ void STSDAtom::OnProcessMetaData()
Read(&aSampleDescBase.DataFormat);
Read(aSampleDescBase.Reserved,6);
Read(&aSampleDescBase.DataReference);
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, 0);
theStream->Seek(aSampleDescBase.Size - SampleDescBaseSize, SEEK_CUR);
break;
}
}

View File

@ -254,6 +254,18 @@ public:
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
class STSDAtom : public AtomBase {
public:
@ -293,7 +305,7 @@ public:
// 0x008 Track in Poster
// 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:
tkhdV1 theHeader;

View File

@ -92,6 +92,8 @@ struct VideoMetaData
uint32 HorizontalResolution;
uint32 VerticalResolution;
float FrameRate;
uint8 *theVOL;
size_t VOLSize;
};
struct AudioMetaData
@ -101,6 +103,8 @@ struct AudioMetaData
uint16 SampleSize; // bits per sample
float SampleRate; // Samples per second (OR Frames per second)
uint32 PacketSize; // (Sample Rate * NoOfchannels * SampleSize)/8 = bytes per second
uint8 *theVOL;
size_t VOLSize;
};
struct wave_format_ex
@ -306,6 +310,8 @@ struct SoundDescriptionV1 {
uint32 bytesPerSample;
// These are optional data from atoms that follow
wave_format_ex theWaveFormat; // wave atom is a copy of wave_format_ex
uint8 *theVOL;
size_t VOLSize;
};
struct VideoDescription {
@ -331,4 +337,6 @@ struct VideoDescription {
struct VideoDescriptionV0 {
SampleDescBase basefields;
VideoDescription desc;
uint8 *theVOL;
size_t VOLSize;
};

View File

@ -402,6 +402,14 @@ movReader::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 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;
}

View File

@ -899,7 +899,10 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
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();
return 0LL;

View File

@ -427,17 +427,19 @@ mp4Reader::AllocateCookie(int32 streamNumber, void **_cookie)
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);
if (video_format->VOLSize > 0) {
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]);
}
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;
}