Removed many bugs relating to multiple video tracks. Replaced these bugs with much more interesting ones
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13657 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
b39b6ee51c
commit
24af6494ea
|
@ -32,9 +32,11 @@ const struct codec_table gCodecTable[] = {
|
|||
{CODEC_ID_PCM_ALAW, B_MEDIA_ENCODED_AUDIO, B_AIFF_FORMAT_FAMILY, 'alaw' , "aLaw"},
|
||||
{CODEC_ID_PCM_ALAW, B_MEDIA_ENCODED_AUDIO, B_AIFF_FORMAT_FAMILY, 'ALAW' , "aLaw"},
|
||||
{CODEC_ID_PCM_ALAW, B_MEDIA_ENCODED_AUDIO, B_MISC_FORMAT_FAMILY, (uint64('au') << 32) | 27, "aLaw"},
|
||||
/*
|
||||
|
||||
{CODEC_ID_PCM_MULAW, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'ulaw', "µLaw"},
|
||||
*/
|
||||
{CODEC_ID_PCM_ALAW, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'alaw', "aLaw"},
|
||||
{CODEC_ID_PCM_ALAW, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'ALAW', "aLaw"},
|
||||
|
||||
{CODEC_ID_PCM_MULAW, B_MEDIA_ENCODED_AUDIO, B_WAV_FORMAT_FAMILY, 0x07, "µLaw"},
|
||||
{CODEC_ID_PCM_MULAW, B_MEDIA_ENCODED_AUDIO, B_AIFF_FORMAT_FAMILY, 'ulaw', "µLaw"},
|
||||
{CODEC_ID_PCM_MULAW, B_MEDIA_ENCODED_AUDIO, B_AIFF_FORMAT_FAMILY, 'ULAW', "µLaw"},
|
||||
|
@ -44,7 +46,8 @@ const struct codec_table gCodecTable[] = {
|
|||
{CODEC_ID_ADPCM_MS, B_MEDIA_ENCODED_AUDIO, B_WAV_FORMAT_FAMILY, 0x0002, "MS ADPCM"},
|
||||
{CODEC_ID_ADPCM_IMA_WAV, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 0x6D730011, "IMA ADPCM"},
|
||||
{CODEC_ID_ADPCM_MS, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 0x6D730002, "MS ADPCM"},
|
||||
{CODEC_ID_MP3, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 0x6D730055, "MP3"},
|
||||
{CODEC_ID_MP2, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 0x6D730050, "MP Layer2"},
|
||||
{CODEC_ID_MP2, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 0x6D730055, "MP Layer3"},
|
||||
|
||||
#ifdef HAS_MACE_AUDIO
|
||||
{CODEC_ID_MACE3, B_MEDIA_ENCODED_AUDIO, B_QUICKTIME_FORMAT_FAMILY, 'MAC3', "MACE 3:1"},
|
||||
|
|
|
@ -125,7 +125,7 @@ uint32 MOVFileReader::getMovieTimeScale()
|
|||
|
||||
bigtime_t MOVFileReader::getMovieDuration()
|
||||
{
|
||||
return ((bigtime_t(getMVHDAtom()->getDuration()) * 1000000) / getMovieTimeScale());
|
||||
return ((bigtime_t(getMVHDAtom()->getDuration()) * 1000000L) / getMovieTimeScale());
|
||||
}
|
||||
|
||||
uint32 MOVFileReader::getStreamCount()
|
||||
|
@ -134,33 +134,27 @@ uint32 MOVFileReader::getStreamCount()
|
|||
return (CountChildAtoms(uint32('trak')));
|
||||
}
|
||||
|
||||
bigtime_t MOVFileReader::getVideoDuration()
|
||||
bigtime_t MOVFileReader::getVideoDuration(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
uint32 TimeScale = getMovieTimeScale();
|
||||
|
||||
for (uint32 i=0;i<getStreamCount();i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),i);
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(TimeScale));
|
||||
}
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bigtime_t MOVFileReader::getAudioDuration()
|
||||
bigtime_t MOVFileReader::getAudioDuration(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
uint32 TimeScale = getMovieTimeScale();
|
||||
|
||||
for (uint32 i=0;i<getStreamCount();i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),i);
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(TimeScale));
|
||||
}
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
|
||||
return (dynamic_cast<TRAKAtom *>(aAtomBase)->Duration(1));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -168,39 +162,59 @@ uint32 TimeScale = getMovieTimeScale();
|
|||
|
||||
bigtime_t MOVFileReader::getMaxDuration()
|
||||
{
|
||||
return MAX(getVideoDuration(),getAudioDuration());
|
||||
AtomBase *aAtomBase;
|
||||
int32 video_index,audio_index;
|
||||
video_index = -1;
|
||||
audio_index = -1;
|
||||
|
||||
// find the active video and audio tracks
|
||||
for (uint32 i=0;i<getStreamCount();i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),i);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsActive())) {
|
||||
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio()) {
|
||||
audio_index = int32(i);
|
||||
}
|
||||
if (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo()) {
|
||||
video_index = int32(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((video_index >= 0) && (audio_index >= 0)) {
|
||||
return MAX(getVideoDuration(video_index),getAudioDuration(audio_index));
|
||||
}
|
||||
if ((video_index < 0) && (audio_index >= 0)) {
|
||||
return getAudioDuration(audio_index);
|
||||
}
|
||||
if ((video_index >= 0) && (audio_index < 0)) {
|
||||
return getVideoDuration(video_index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 MOVFileReader::getVideoFrameCount()
|
||||
uint32 MOVFileReader::getVideoFrameCount(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
for (uint32 i=0;i<getStreamCount();i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),i);
|
||||
aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsVideo())) {
|
||||
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
}
|
||||
return dynamic_cast<TRAKAtom *>(aAtomBase)->FrameCount();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 MOVFileReader::getAudioFrameCount()
|
||||
uint32 MOVFileReader::getAudioFrameCount(uint32 stream_index)
|
||||
{
|
||||
|
||||
AtomBase *aAtomBase;
|
||||
|
||||
for (uint32 i=0;i<getStreamCount();i++) {
|
||||
aAtomBase = GetChildAtom(uint32('trak'),i);
|
||||
|
||||
if ((aAtomBase) && (dynamic_cast<TRAKAtom *>(aAtomBase)->IsAudio())) {
|
||||
return uint32(((getAudioDuration() * AudioFormat(i)->SampleRate) / 1000000L) + 0.5);
|
||||
}
|
||||
if (IsAudio(stream_index)) {
|
||||
return uint32(((getAudioDuration(stream_index) * AudioFormat(stream_index)->SampleRate) / 1000000L) + 0.5);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MOVFileReader::IsVideo(uint32 stream_index)
|
||||
|
@ -357,7 +371,7 @@ const mov_main_header *MOVFileReader::MovMainHeader()
|
|||
theMainHeader.initial_frames = 0;
|
||||
|
||||
while ( videoStream < theMainHeader.streams ) {
|
||||
if (IsVideo(videoStream)) {
|
||||
if (IsVideo(videoStream) && IsActive(videoStream)) {
|
||||
break;
|
||||
}
|
||||
videoStream++;
|
||||
|
@ -372,7 +386,7 @@ const mov_main_header *MOVFileReader::MovMainHeader()
|
|||
} else {
|
||||
theMainHeader.width = VideoFormat(videoStream)->width;
|
||||
theMainHeader.height = VideoFormat(videoStream)->height;
|
||||
theMainHeader.total_frames = getVideoFrameCount();
|
||||
theMainHeader.total_frames = getVideoFrameCount(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);
|
||||
}
|
||||
|
@ -454,7 +468,7 @@ const VideoMetaData *MOVFileReader::VideoFormat(uint32 stream_index)
|
|||
if (aAtomBase) {
|
||||
STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
|
||||
|
||||
theVideo.FrameRate = ((aSTTSAtom->getSUMCounts() * 1000000.0L) / getVideoDuration());
|
||||
theVideo.FrameRate = ((aSTTSAtom->getSUMCounts() * 1000000.0L) / aTrakAtom->Duration(1));
|
||||
|
||||
return &theVideo;
|
||||
}
|
||||
|
@ -469,17 +483,21 @@ const mov_stream_header *MOVFileReader::StreamFormat(uint32 stream_index)
|
|||
{
|
||||
// Fill In a Stream Header
|
||||
theStreamHeader.length = 0;
|
||||
|
||||
if (IsActive(stream_index) == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (IsVideo(stream_index)) {
|
||||
theStreamHeader.rate = uint32(1000000*VideoFormat(stream_index)->FrameRate);
|
||||
theStreamHeader.scale = 1000000;
|
||||
theStreamHeader.length = getVideoFrameCount();
|
||||
theStreamHeader.rate = uint32(1000000L*VideoFormat(stream_index)->FrameRate);
|
||||
theStreamHeader.scale = 1000000L;
|
||||
theStreamHeader.length = getVideoFrameCount(stream_index);
|
||||
}
|
||||
|
||||
if (IsAudio(stream_index)) {
|
||||
theStreamHeader.rate = uint32(AudioFormat(stream_index)->SampleRate);
|
||||
theStreamHeader.scale = 1;
|
||||
theStreamHeader.length = getAudioFrameCount();
|
||||
theStreamHeader.length = getAudioFrameCount(stream_index);
|
||||
theStreamHeader.sample_size = AudioFormat(stream_index)->SampleSize;
|
||||
theStreamHeader.suggested_buffer_size = theStreamHeader.rate * theStreamHeader.sample_size;
|
||||
}
|
||||
|
@ -550,6 +568,17 @@ bool MOVFileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t
|
|||
return ((*start > 0) && (*size > 0) && !(IsEndOfFile(*start)));
|
||||
}
|
||||
|
||||
bool MOVFileReader::IsActive(uint32 stream_index)
|
||||
{
|
||||
AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index);
|
||||
if (aAtomBase) {
|
||||
TRAKAtom *aTrakAtom = dynamic_cast<TRAKAtom *>(aAtomBase);
|
||||
return aTrakAtom->IsActive();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool MOVFileReader::IsSupported(BPositionIO *source)
|
||||
{
|
||||
|
|
|
@ -72,20 +72,20 @@ public:
|
|||
// How many tracks in file
|
||||
uint32 getStreamCount();
|
||||
|
||||
// Duration defined
|
||||
// Duration defined by the movie header
|
||||
bigtime_t getMovieDuration();
|
||||
|
||||
// The first video track duration
|
||||
bigtime_t getVideoDuration();
|
||||
// the first audio track duration
|
||||
bigtime_t getAudioDuration();
|
||||
// the max of the audio or video durations
|
||||
// The first video track duration indexed by stream_index
|
||||
bigtime_t getVideoDuration(uint32 stream_index);
|
||||
// the first audio track duration indexed by stream_index
|
||||
bigtime_t getAudioDuration(uint32 stream_index);
|
||||
// the max of all active audio or video durations
|
||||
bigtime_t getMaxDuration();
|
||||
|
||||
// The no of frames in the first video track
|
||||
uint32 getVideoFrameCount();
|
||||
// The no of frames in the first audio track
|
||||
uint32 getAudioFrameCount();
|
||||
// The no of frames in the video track indexed by stream_index
|
||||
uint32 getVideoFrameCount(uint32 stream_index);
|
||||
// The no of frames in the audio track indexed by stream_index
|
||||
uint32 getAudioFrameCount(uint32 stream_index);
|
||||
|
||||
// Is stream (track) a video track
|
||||
bool IsVideo(uint32 stream_index);
|
||||
|
@ -102,6 +102,8 @@ public:
|
|||
status_t ParseFile();
|
||||
BPositionIO *Source() {return theStream;};
|
||||
|
||||
bool IsActive(uint32 stream_index);
|
||||
|
||||
bool GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *start, uint32 *size, bool *keyframe);
|
||||
|
||||
// Return all Audio Meta Data
|
||||
|
|
|
@ -267,13 +267,13 @@ void CMOVAtom::OnProcessMetaData()
|
|||
printf("Failed to decompress headers uncompress returned ");
|
||||
switch (result) {
|
||||
case Z_MEM_ERROR:
|
||||
printf("Lack of Memory Error\n");
|
||||
DEBUGGER("Lack of Memory Error\n");
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
printf("Lack of Output buffer space Error\n");
|
||||
DEBUGGER("Lack of Output buffer space Error\n");
|
||||
break;
|
||||
case Z_DATA_ERROR:
|
||||
printf("Input Data is corrupt or not a compressed set Error\n");
|
||||
DEBUGGER("Input Data is corrupt or not a compressed set Error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -387,6 +387,7 @@ void MVHDAtom::OnProcessMetaData()
|
|||
theHeader.SelectionDuration = B_BENDIAN_TO_HOST_INT32(theHeader.SelectionDuration);
|
||||
theHeader.CurrentTime = B_BENDIAN_TO_HOST_INT32(theHeader.CurrentTime);
|
||||
theHeader.NextTrackID = B_BENDIAN_TO_HOST_INT32(theHeader.NextTrackID);
|
||||
|
||||
}
|
||||
|
||||
char *MVHDAtom::OnGetAtomName()
|
||||
|
@ -410,6 +411,8 @@ AtomBase *aAtomBase;
|
|||
STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
{
|
||||
theHeader.NoEntries = 0;
|
||||
SUMDurations = 0;
|
||||
SUMCounts = 0;
|
||||
}
|
||||
|
||||
STTSAtom::~STTSAtom()
|
||||
|
@ -434,6 +437,8 @@ TimeToSample *aTimeToSample;
|
|||
aTimeToSample->Duration = B_BENDIAN_TO_HOST_INT32(aTimeToSample->Duration);
|
||||
|
||||
theTimeToSampleArray[i] = aTimeToSample;
|
||||
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
SUMCounts += theTimeToSampleArray[i]->Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,39 +447,14 @@ char *STTSAtom::OnGetAtomName()
|
|||
return "Time to Sample Atom";
|
||||
}
|
||||
|
||||
uint64 STTSAtom::getSUMCounts()
|
||||
{
|
||||
uint64 SUMCounts = 0;
|
||||
uint64 SUMDurations = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
SUMCounts += theTimeToSampleArray[i]->Count;
|
||||
}
|
||||
|
||||
return SUMCounts;
|
||||
}
|
||||
|
||||
uint64 STTSAtom::getSUMDurations()
|
||||
{
|
||||
// this Duration is not scaled to timescale
|
||||
uint64 SUMDurations = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
}
|
||||
|
||||
return SUMDurations;
|
||||
}
|
||||
|
||||
uint32 STTSAtom::getSampleForTime(uint32 pTime)
|
||||
{
|
||||
// TODO this is too slow. PreCalc SUMCounts when loading this.
|
||||
uint64 SUMDurations = 0;
|
||||
// TODO this is too slow. PreCalc when loading this?
|
||||
uint64 Duration = 0;
|
||||
|
||||
for (uint32 i=0;i<theHeader.NoEntries;i++) {
|
||||
SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
if (SUMDurations > pTime) {
|
||||
Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
|
||||
if (Duration > pTime) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -528,7 +508,6 @@ SampleToChunk *aSampleToChunk;
|
|||
}
|
||||
|
||||
theSampleToChunkArray[i] = aSampleToChunk;
|
||||
// printf("%ld/%ld/%ld\n",aSampleToChunk->FirstChunk,aSampleToChunk->SamplesPerChunk,aSampleToChunk->TotalPrevFrames);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,7 +706,7 @@ ChunkToOffset *aChunkToOffset;
|
|||
theChunkToOffsetArray[i] = aChunkToOffset;
|
||||
}
|
||||
|
||||
printf("Chunk to Offset Array has %ld entries\n",theHeader.NoEntries);
|
||||
PRINT(("Chunk to Offset Array has %ld entries\n",theHeader.NoEntries));
|
||||
}
|
||||
|
||||
char *STCOAtom::OnGetAtomName()
|
||||
|
@ -742,11 +721,10 @@ uint64 STCOAtom::getOffsetForChunk(uint32 pChunkID)
|
|||
return theChunkToOffsetArray[pChunkID - 1]->Offset;
|
||||
}
|
||||
|
||||
printf("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries);
|
||||
DEBUGGER(("Bad Chunk ID %ld / %ld\n",pChunkID,theHeader.NoEntries));
|
||||
|
||||
// TODO Yes this will seg fault. But I get a very bad lock up if I don't :-(
|
||||
return theChunkToOffsetArray[pChunkID - 1]->Offset;
|
||||
// return theChunkToOffsetArray[0]->Offset;
|
||||
TRESPASS();
|
||||
return theChunkToOffsetArray[0]->Offset;
|
||||
}
|
||||
|
||||
STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
|
||||
|
@ -843,7 +821,7 @@ void STSDAtom::ReadSoundDescription()
|
|||
if (aAtomBase->getAtomSize() > 0) {
|
||||
descBytesLeft = descBytesLeft - aAtomBase->getAtomSize();
|
||||
} else {
|
||||
printf("Invalid Atom found when reading Sound Description\n");
|
||||
DEBUGGER("Invalid Atom found when reading Sound Description\n");
|
||||
descBytesLeft = 0;
|
||||
}
|
||||
|
||||
|
@ -855,7 +833,7 @@ void STSDAtom::ReadSoundDescription()
|
|||
|
||||
theStream->Seek(descBytesLeft,0);
|
||||
|
||||
printf("Size:Format=%ld:%ld %ld\n",aSoundDescriptionV1->basefields.Size,aSoundDescriptionV1->basefields.DataFormat,descBytesLeft);
|
||||
PRINT(("Size:Format=%ld:%ld %ld\n",aSoundDescriptionV1->basefields.Size,aSoundDescriptionV1->basefields.DataFormat,descBytesLeft));
|
||||
}
|
||||
|
||||
void STSDAtom::ReadVideoDescription()
|
||||
|
@ -896,7 +874,7 @@ void STSDAtom::ReadVideoDescription()
|
|||
// We seem to have read 2 bytes too many???
|
||||
theStream->Seek(descBytesLeft,0);
|
||||
|
||||
printf("Size:Format=%ld:%ld %ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,descBytesLeft);
|
||||
PRINT(("Size:Format=%ld:%ld %ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,descBytesLeft));
|
||||
}
|
||||
|
||||
void STSDAtom::OnProcessMetaData()
|
||||
|
@ -1157,17 +1135,45 @@ TKHDAtom::~TKHDAtom()
|
|||
|
||||
void TKHDAtom::OnProcessMetaData()
|
||||
{
|
||||
theStream->Read(&theHeader,sizeof(tkhd));
|
||||
theStream->Read(&Version,sizeof(uint8));
|
||||
|
||||
if (Version == 0) {
|
||||
tkhdV0 aHeaderV0;
|
||||
theStream->Read(&aHeaderV0,sizeof(tkhdV0));
|
||||
|
||||
theHeader.Flags1 = aHeaderV0.Flags1;
|
||||
theHeader.Flags2 = aHeaderV0.Flags2;
|
||||
theHeader.Flags3 = aHeaderV0.Flags3;
|
||||
|
||||
for (uint32 i=0;i<36;i++) {
|
||||
theHeader.MatrixStructure[i] = aHeaderV0.MatrixStructure[i];
|
||||
}
|
||||
|
||||
// upconvert to V1 header
|
||||
theHeader.CreationTime = B_BENDIAN_TO_HOST_INT32(aHeaderV0.CreationTime);
|
||||
theHeader.ModificationTime = B_BENDIAN_TO_HOST_INT32(aHeaderV0.ModificationTime);
|
||||
theHeader.TrackID = B_BENDIAN_TO_HOST_INT32(aHeaderV0.TrackID);
|
||||
theHeader.Duration = B_BENDIAN_TO_HOST_INT32(aHeaderV0.Duration);
|
||||
theHeader.Layer = B_BENDIAN_TO_HOST_INT16(aHeaderV0.Layer);
|
||||
theHeader.AlternateGroup = B_BENDIAN_TO_HOST_INT16(aHeaderV0.AlternateGroup);
|
||||
theHeader.Volume = B_BENDIAN_TO_HOST_INT16(aHeaderV0.Volume);
|
||||
theHeader.TrackWidth = B_BENDIAN_TO_HOST_INT32(aHeaderV0.TrackWidth);
|
||||
theHeader.TrackHeight = B_BENDIAN_TO_HOST_INT32(aHeaderV0.TrackHeight);
|
||||
|
||||
} else {
|
||||
theStream->Read(&theHeader,sizeof(tkhdV1));
|
||||
|
||||
theHeader.CreationTime = B_BENDIAN_TO_HOST_INT64(theHeader.CreationTime);
|
||||
theHeader.ModificationTime = B_BENDIAN_TO_HOST_INT64(theHeader.ModificationTime);
|
||||
theHeader.TrackID = B_BENDIAN_TO_HOST_INT32(theHeader.TrackID);
|
||||
theHeader.Duration = B_BENDIAN_TO_HOST_INT32(theHeader.Duration);
|
||||
theHeader.Layer = B_BENDIAN_TO_HOST_INT16(theHeader.Layer);
|
||||
theHeader.AlternateGroup = B_BENDIAN_TO_HOST_INT16(theHeader.AlternateGroup);
|
||||
theHeader.Volume = B_BENDIAN_TO_HOST_INT16(theHeader.Volume);
|
||||
theHeader.TrackWidth = B_BENDIAN_TO_HOST_INT32(theHeader.TrackWidth);
|
||||
theHeader.TrackHeight = B_BENDIAN_TO_HOST_INT32(theHeader.TrackHeight);
|
||||
}
|
||||
|
||||
theHeader.CreationTime = B_BENDIAN_TO_HOST_INT32(theHeader.CreationTime);
|
||||
theHeader.ModificationTime = B_BENDIAN_TO_HOST_INT32(theHeader.ModificationTime);
|
||||
theHeader.TrackID = B_BENDIAN_TO_HOST_INT32(theHeader.TrackID);
|
||||
theHeader.Duration = B_BENDIAN_TO_HOST_INT32(theHeader.Duration);
|
||||
theHeader.Layer = B_BENDIAN_TO_HOST_INT16(theHeader.Layer);
|
||||
theHeader.AlternateGroup = B_BENDIAN_TO_HOST_INT16(theHeader.AlternateGroup);
|
||||
theHeader.Volume = B_BENDIAN_TO_HOST_INT16(theHeader.Volume);
|
||||
theHeader.TrackWidth = B_BENDIAN_TO_HOST_INT32(theHeader.TrackWidth);
|
||||
theHeader.TrackHeight = B_BENDIAN_TO_HOST_INT32(theHeader.TrackHeight);
|
||||
}
|
||||
|
||||
char *TKHDAtom::OnGetAtomName()
|
||||
|
@ -1232,7 +1238,7 @@ char *MDHDAtom::OnGetAtomName()
|
|||
|
||||
bigtime_t MDHDAtom::getDuration()
|
||||
{
|
||||
return (bigtime_t(theHeader.Duration) * 1000000) / (theHeader.TimeScale);
|
||||
return bigtime_t((uint64(theHeader.Duration) * 1000000L) / theHeader.TimeScale);
|
||||
}
|
||||
|
||||
uint32 MDHDAtom::getTimeScale()
|
||||
|
|
|
@ -168,13 +168,15 @@ public:
|
|||
void OnProcessMetaData();
|
||||
char *OnGetAtomName();
|
||||
|
||||
uint64 getSUMCounts();
|
||||
uint64 getSUMDurations();
|
||||
uint64 getSUMCounts() {return SUMCounts;};
|
||||
uint64 getSUMDurations() {return SUMDurations;};
|
||||
uint32 getSampleForTime(uint32 pTime);
|
||||
uint32 getSampleForFrame(uint32 pFrame);
|
||||
private:
|
||||
array_header theHeader;
|
||||
TimeToSampleArray theTimeToSampleArray;
|
||||
uint64 SUMDurations;
|
||||
uint64 SUMCounts;
|
||||
};
|
||||
|
||||
// Atom class for reading the sample to chunk atom
|
||||
|
@ -292,9 +294,19 @@ public:
|
|||
char *OnGetAtomName();
|
||||
|
||||
uint32 getDuration() {return theHeader.Duration;}; // duration is in the scale of the media
|
||||
|
||||
|
||||
// Flags3 should contain the following
|
||||
// 0x001 Track enabled
|
||||
// 0x002 Track in Movie
|
||||
// 0x004 Track in Preview
|
||||
// 0x008 Track in Poster
|
||||
// It seems active tracks have all 4 flags set?
|
||||
|
||||
bool IsActive() {return (theHeader.Flags3 == 0x0f);};
|
||||
|
||||
private:
|
||||
tkhd theHeader;
|
||||
tkhdV1 theHeader;
|
||||
uint8 Version;
|
||||
|
||||
};
|
||||
|
||||
|
@ -361,6 +373,7 @@ public:
|
|||
uint32 getNoSamplesInChunk(uint32 pChunkID);
|
||||
bool IsSyncSample(uint32 pSampleNo);
|
||||
bool IsSingleSampleSize();
|
||||
bool IsActive();
|
||||
|
||||
TKHDAtom *getTKHDAtom();
|
||||
MDHDAtom *getMDHDAtom();
|
||||
|
|
|
@ -77,7 +77,7 @@ bigtime_t TRAKAtom::Duration(uint32 TimeScale)
|
|||
return getMDHDAtom()->getDuration();
|
||||
}
|
||||
|
||||
return bigtime_t(getTKHDAtom()->getDuration() * 1000000) / TimeScale;
|
||||
return bigtime_t(getTKHDAtom()->getDuration() * 1000000L) / TimeScale;
|
||||
}
|
||||
|
||||
void TRAKAtom::OnChildProcessingComplete()
|
||||
|
@ -221,5 +221,10 @@ bool TRAKAtom::IsSingleSampleSize()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TRAKAtom::IsActive()
|
||||
{
|
||||
return getTKHDAtom()->IsActive();
|
||||
}
|
||||
|
||||
// GetAudioMetaData() // If this is a audio track get the audio meta data
|
||||
// GetVideoMetaData() // If this is a video track get the video meta data
|
||||
|
|
|
@ -179,8 +179,7 @@ struct mvhd {
|
|||
uint32 NextTrackID;
|
||||
};
|
||||
|
||||
struct tkhd {
|
||||
uint8 Version;
|
||||
struct tkhdV0 {
|
||||
uint8 Flags1;
|
||||
uint8 Flags2;
|
||||
uint8 Flags3;
|
||||
|
@ -199,6 +198,25 @@ struct tkhd {
|
|||
uint32 TrackHeight;
|
||||
};
|
||||
|
||||
struct tkhdV1 {
|
||||
uint8 Flags1;
|
||||
uint8 Flags2;
|
||||
uint8 Flags3;
|
||||
uint64 CreationTime;
|
||||
uint64 ModificationTime;
|
||||
uint32 TrackID;
|
||||
uint32 Reserved1;
|
||||
uint32 Duration;
|
||||
uint64 Reserved2;
|
||||
uint16 Layer;
|
||||
uint16 AlternateGroup;
|
||||
uint16 Volume;
|
||||
uint16 Reserved3;
|
||||
uint8 MatrixStructure[36];
|
||||
uint32 TrackWidth;
|
||||
uint32 TrackHeight;
|
||||
};
|
||||
|
||||
struct mdhd {
|
||||
uint8 Version;
|
||||
uint8 Flags1;
|
||||
|
|
|
@ -146,11 +146,17 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||
BMediaFormats formats;
|
||||
media_format *format = &cookie->format;
|
||||
media_format_description description;
|
||||
|
||||
if (theFileReader->IsActive(cookie->stream) == false) {
|
||||
ERROR("movReader::AllocateCookie: stream %d is not active\n", cookie->stream);
|
||||
delete cookie;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
const mov_stream_header *stream_header;
|
||||
stream_header = theFileReader->StreamFormat(cookie->stream);
|
||||
if (!stream_header) {
|
||||
ERROR("movReader::GetStreamInfo: stream %d has no header\n", cookie->stream);
|
||||
ERROR("movReader::AllocateCookie: stream %d has no header\n", cookie->stream);
|
||||
delete cookie;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
@ -160,13 +166,13 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||
if (theFileReader->IsAudio(cookie->stream)) {
|
||||
const AudioMetaData *audio_format = theFileReader->AudioFormat(cookie->stream);
|
||||
if (!audio_format) {
|
||||
ERROR("movReader::GetStreamInfo: audio stream %d has no format\n", cookie->stream);
|
||||
ERROR("movReader::AllocateCookie: audio stream %d has no format\n", cookie->stream);
|
||||
delete cookie;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
cookie->frame_count = theFileReader->getAudioFrameCount();
|
||||
cookie->duration = theFileReader->getAudioDuration();
|
||||
cookie->frame_count = theFileReader->getAudioFrameCount(cookie->stream);
|
||||
cookie->duration = theFileReader->getAudioDuration(cookie->stream);
|
||||
|
||||
cookie->audio = true;
|
||||
cookie->byte_pos = 0;
|
||||
|
@ -336,7 +342,7 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||
if (theFileReader->IsVideo(cookie->stream)) {
|
||||
const VideoMetaData *video_format = theFileReader->VideoFormat(cookie->stream);
|
||||
if (!video_format) {
|
||||
ERROR("movReader::GetStreamInfo: video stream %d has no format\n", cookie->stream);
|
||||
ERROR("movReader::AllocateCookie: video stream %d has no format\n", cookie->stream);
|
||||
delete cookie;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
@ -363,6 +369,7 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie)
|
|||
|
||||
TRACE("frame_count %Ld\n", cookie->frame_count);
|
||||
TRACE("duration %.6f (%Ld)\n", cookie->duration / 1E6, cookie->duration);
|
||||
TRACE("compression %s\n", &video_format->compression);
|
||||
|
||||
description.family = B_QUICKTIME_FORMAT_FAMILY;
|
||||
if (stream_header->fourcc_handler == 'ekaf' || stream_header->fourcc_handler == 0) // 'fake' or 0 fourcc => used compression id
|
||||
|
|
Loading…
Reference in New Issue