From 9658f6abbafe55fb0c4d967b07278585358e8096 Mon Sep 17 00:00:00 2001 From: David McPaul Date: Sun, 19 Jun 2005 06:02:57 +0000 Subject: [PATCH] Performance improvements to mov_reader git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13209 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../mov_reader/libMOV/MOVFileReader.cpp | 150 +++++++++--------- .../plugins/mov_reader/libMOV/MOVFileReader.h | 1 + .../plugins/mov_reader/libMOV/MOVParser.cpp | 25 +++ .../plugins/mov_reader/libMOV/MOVParser.h | 6 +- .../plugins/mov_reader/libMOV/MOVTrakAtom.cpp | 27 +++- .../media/plugins/mov_reader/mov_reader.cpp | 55 ++++--- 6 files changed, 162 insertions(+), 102 deletions(-) diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp index 2a33ffc812..05afbd6572 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.cpp @@ -231,35 +231,39 @@ bool MOVFileReader::IsAudio(uint32 stream_index) return false; } +uint32 MOVFileReader::getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID) +{ + // Find Track + AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); + if (aAtomBase) { + TRAKAtom *aTrakAtom = dynamic_cast(aAtomBase); + + return aTrakAtom->getFirstSampleInChunk(pChunkID); + } + + return 0; +} + uint32 MOVFileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo) { // Find Track AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); if (aAtomBase) { TRAKAtom *aTrakAtom = dynamic_cast(aAtomBase); - - uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); + uint32 ChunkNo = 1; if (IsAudio(stream_index)) { - uint32 OffsetInChunk; - uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk); - - // Go back to first Sample in Chunk - while (aTrakAtom->getChunkForSample(SampleNo-1, &OffsetInChunk) == ChunkNo) { - SampleNo--; - } - - // Add up all sample sizes in chunk - while (aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk) == ChunkNo) { - SampleNo++; - } - return SampleNo ; + ChunkNo = pFrameNo; } if (IsVideo(stream_index)) { - return 1; + uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); + + uint32 OffsetInChunk; + ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk); } + return aTrakAtom->getNoSamplesInChunk(ChunkNo); } return 0; @@ -267,54 +271,47 @@ uint32 MOVFileReader::getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo) uint64 MOVFileReader::getOffsetForFrame(uint32 stream_index, uint32 pFrameNo) { -// BStopWatch *watch; - // Find Track AtomBase *aAtomBase = GetChildAtom(uint32('trak'),stream_index); if (aAtomBase) { TRAKAtom *aTrakAtom = dynamic_cast(aAtomBase); - if (pFrameNo < aTrakAtom->FrameCount()) { - // Convert Frame to Track Time -// uint32 FrameTime = aTrakAtom->getTimeForFrame(pFrameNo, getMovieTimeScale()); - // Get Sample for Frame -// watch = new BStopWatch("getSampleForFrame"); - uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); -// delete watch; - // Get Chunk For Sample and the offset for the frame within that chunk -// watch = new BStopWatch("getChunkForSample"); - uint32 OffsetInChunk; - uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk); -// delete watch; - // Get Offset For Chunk -// printf("Stream: %ld Frame %ld %ld <%ld/%ld> (",stream_index, pFrameNo, SampleNo, ChunkNo, OffsetInChunk); -// watch = new BStopWatch("getOffsetForChunk"); - uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo); -// delete watch; -// printf("Frame %ld {%lld} <%ld/%ld> (",pFrameNo, OffsetNo, ChunkNo, OffsetInChunk); + if (IsAudio(stream_index)) { + // FrameNo is really chunk No for audio + uint32 ChunkNo = pFrameNo; - if (ChunkNo != 0) { - uint32 SampleSize; - // Adjust the Offset for the Offset in the chunk -// watch = new BStopWatch("getSizeForSample"); - if (aTrakAtom->IsSingleSampleSize()) { - SampleSize = aTrakAtom->getSizeForSample(SampleNo); - OffsetNo = OffsetNo + (OffsetInChunk * SampleSize); - } else { - // This is bad news performance wise - for (uint32 i=1;i<=OffsetInChunk;i++) { - SampleSize = aTrakAtom->getSizeForSample(SampleNo-i); -// printf(" %ld ",SampleSize); - OffsetNo = OffsetNo + SampleSize; + // Get Offset For Chunk + return aTrakAtom->getOffsetForChunk(ChunkNo); + } + + if (IsVideo(stream_index)) { + + if (pFrameNo < aTrakAtom->FrameCount()) { + // Get Sample for Frame + uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); + // Get Chunk For Sample and the offset for the frame within that chunk + uint32 OffsetInChunk; + uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk); + // Get Offset For Chunk + uint64 OffsetNo = aTrakAtom->getOffsetForChunk(ChunkNo); + + if (ChunkNo != 0) { + uint32 SampleSize; + // Adjust the Offset for the Offset in the chunk + if (aTrakAtom->IsSingleSampleSize()) { + SampleSize = aTrakAtom->getSizeForSample(SampleNo); + OffsetNo = OffsetNo + (OffsetInChunk * SampleSize); + } else { + // This is bad news performance wise + for (uint32 i=1;i<=OffsetInChunk;i++) { + SampleSize = aTrakAtom->getSizeForSample(SampleNo-i); + OffsetNo = OffsetNo + SampleSize; + } } } -// printf(") %lld\n",OffsetNo); -// delete watch; - } -// printf("%ld:%ld:%ld:%lld\n",pFrameNo, SampleNo, ChunkNo, OffsetNo); -// printf("\n"); - return OffsetNo; + return OffsetNo; + } } } @@ -495,33 +492,32 @@ uint32 MOVFileReader::getChunkSize(uint32 stream_index, uint32 pFrameNo) if (aAtomBase) { TRAKAtom *aTrakAtom = dynamic_cast(aAtomBase); - if (pFrameNo < aTrakAtom->FrameCount()) { - uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); + if (IsAudio(stream_index)) { - if (IsAudio(stream_index)) { - uint32 OffsetInChunk; - uint32 ChunkNo = aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk); - - // Go back to first Sample in Chunk - while (aTrakAtom->getChunkForSample(SampleNo-1, &OffsetInChunk) == ChunkNo) { - SampleNo--; - } - - // Add up all sample sizes in chunk - uint32 ChunkSize = 0; + // We read audio in chunk by chunk so chunk size is chunk size + uint32 ChunkNo = pFrameNo; - while (aTrakAtom->getChunkForSample(SampleNo, &OffsetInChunk) == ChunkNo) { - ChunkSize += aTrakAtom->getSizeForSample(SampleNo); - SampleNo++; - } - return ChunkSize; + // Get first sample in chunk + uint32 SampleNo = aTrakAtom->getFirstSampleInChunk(ChunkNo); + + // Add up all sample sizes in chunk + uint32 ChunkSize = 0; + for (uint32 i=0;igetNoSamplesInChunk(ChunkNo);i++) { + ChunkSize += aTrakAtom->getSizeForSample(SampleNo); + SampleNo++; } + + return ChunkSize; + } - if (IsVideo(stream_index)) { + if (IsVideo(stream_index)) { + if (pFrameNo < aTrakAtom->FrameCount()) { + // We read video in Sample by Sample so chunk size is Sample Size + uint32 SampleNo = aTrakAtom->getSampleForFrame(pFrameNo); return aTrakAtom->getSizeForSample(SampleNo); } - } + } return 0; @@ -550,9 +546,7 @@ bool MOVFileReader::GetNextChunkInfo(uint32 stream_index, uint32 pFrameNo, off_t *keyframe = IsKeyFrame(stream_index, pFrameNo); } - return ((*start > 0) && (*size > 0)); - -// return !(IsEndOfFile(*start) || *start < 0); + return ((*start > 0) && (*size > 0) && !(IsEndOfFile(*start))); } /* static */ diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h index 41f5d66e17..79fdc6ca48 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVFileReader.h @@ -93,6 +93,7 @@ public: bool IsAudio(uint32 stream_index); uint32 getNoFramesInChunk(uint32 stream_index, uint32 pFrameNo); + uint32 getFirstFrameInChunk(uint32 stream_index, uint32 pChunkID); uint64 getOffsetForFrame(uint32 stream_index, uint32 pFrameNo); uint32 getChunkSize(uint32 stream_index, uint32 pFrameNo); diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp index ed83a2ff84..a92cfc5a6a 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.cpp @@ -528,6 +528,7 @@ SampleToChunk *aSampleToChunk; } theSampleToChunkArray[i] = aSampleToChunk; +// printf("%ld/%ld/%ld\n",aSampleToChunk->FirstChunk,aSampleToChunk->SamplesPerChunk,aSampleToChunk->TotalPrevFrames); } } @@ -536,6 +537,30 @@ char *STSCAtom::OnGetAtomName() return "Sample to Chunk Atom"; } +uint32 STSCAtom::getNoSamplesInChunk(uint32 pChunkID) +{ + for (uint32 i=0;iFirstChunk > pChunkID) { + return theSampleToChunkArray[i-1]->SamplesPerChunk; + } + } + + return 0; +} + +uint32 STSCAtom::getFirstSampleInChunk(uint32 pChunkID) +{ + for (uint32 i=0;iFirstChunk > pChunkID) { + uint32 Diff = pChunkID - theSampleToChunkArray[i-1]->FirstChunk; + uint32 pSampleNo = (Diff * theSampleToChunkArray[i-1]->SamplesPerChunk) + theSampleToChunkArray[i-1]->TotalPrevFrames; + return pSampleNo; + } + } + + return 0; +} + uint32 STSCAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk) { uint32 ChunkID = 0; diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h index c1bd84c8d0..00d058bcb6 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVParser.h @@ -186,6 +186,8 @@ public: char *OnGetAtomName(); uint32 getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk); + uint32 getFirstSampleInChunk(uint32 pChunkID); + uint32 getNoSamplesInChunk(uint32 pChunkID); private: array_header theHeader; SampleToChunkArray theSampleToChunkArray; @@ -353,8 +355,10 @@ public: uint32 getSampleForTime(uint32 pTime); uint32 getSampleForFrame(uint32 pFrame); uint32 getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk); - uint64 getOffsetForChunk(uint32 pChunk); + uint64 getOffsetForChunk(uint32 pChunkID); + uint32 getFirstSampleInChunk(uint32 pChunkID); uint32 getSizeForSample(uint32 pSample); + uint32 getNoSamplesInChunk(uint32 pChunkID); bool IsSyncSample(uint32 pSampleNo); bool IsSingleSampleSize(); diff --git a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp index a8e2bfa0fd..b04fb690dd 100644 --- a/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp +++ b/src/add-ons/media/plugins/mov_reader/libMOV/MOVTrakAtom.cpp @@ -154,6 +154,17 @@ uint32 TRAKAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk) return 0; } +uint32 TRAKAtom::getNoSamplesInChunk(uint32 pChunkID) +{ + AtomBase *aAtomBase = GetChildAtom(uint32('stsc'),0); + + if (aAtomBase) { + return (dynamic_cast(aAtomBase))->getNoSamplesInChunk(pChunkID); + } + + return 0; +} + uint32 TRAKAtom::getSizeForSample(uint32 pSample) { AtomBase *aAtomBase = GetChildAtom(uint32('stsz'),0); @@ -165,17 +176,29 @@ uint32 TRAKAtom::getSizeForSample(uint32 pSample) return 0; } -uint64 TRAKAtom::getOffsetForChunk(uint32 pChunk) +uint64 TRAKAtom::getOffsetForChunk(uint32 pChunkID) { AtomBase *aAtomBase = GetChildAtom(uint32('stco'),0); if (aAtomBase) { - return (dynamic_cast(aAtomBase))->getOffsetForChunk(pChunk); + return (dynamic_cast(aAtomBase))->getOffsetForChunk(pChunkID); } return 0; } +uint32 TRAKAtom::getFirstSampleInChunk(uint32 pChunkID) +{ + AtomBase *aAtomBase = GetChildAtom(uint32('stsc'),0); + + if (aAtomBase) { + return (dynamic_cast(aAtomBase))->getFirstSampleInChunk(pChunkID); + } + + return 0; +} + + bool TRAKAtom::IsSyncSample(uint32 pSampleNo) { AtomBase *aAtomBase = GetChildAtom(uint32('stss'),0); diff --git a/src/add-ons/media/plugins/mov_reader/mov_reader.cpp b/src/add-ons/media/plugins/mov_reader/mov_reader.cpp index dace0bdcd6..242d73841e 100644 --- a/src/add-ons/media/plugins/mov_reader/mov_reader.cpp +++ b/src/add-ons/media/plugins/mov_reader/mov_reader.cpp @@ -54,16 +54,19 @@ struct mov_cookie bool audio; - // audio only: - int64 byte_pos; + // audio only: + off_t byte_pos; + uint32 chunk_pos; uint32 bytes_per_sec_rate; uint32 bytes_per_sec_scale; // video only: + uint32 line_count; + + // Common uint32 frame_pos; uint32 frames_per_sec_rate; uint32 frames_per_sec_scale; - uint32 line_count; }; @@ -138,6 +141,7 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie) cookie->stream = streamNumber; cookie->buffer = 0; cookie->buffer_size = 0; + cookie->frame_pos = 0; BMediaFormats formats; media_format *format = &cookie->format; @@ -188,10 +192,10 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie) */ cookie->audio = true; cookie->byte_pos = 0; - cookie->frame_pos = 0; + cookie->chunk_pos = 1; if (stream_header->scale && stream_header->rate && stream_header->sample_size) { - cookie->bytes_per_sec_rate = stream_header->rate * stream_header->sample_size; + cookie->bytes_per_sec_rate = stream_header->rate * stream_header->sample_size * audio_format->NoOfChannels / 8; cookie->bytes_per_sec_scale = stream_header->scale; cookie->frames_per_sec_rate = stream_header->rate; cookie->frames_per_sec_scale = stream_header->scale; @@ -202,9 +206,11 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie) cookie->frames_per_sec_rate = audio_format->SampleSize; cookie->frames_per_sec_scale = 1; TRACE("bytes_per_sec_rate %ld, bytes_per_sec_scale %ld (using avg_bytes_per_sec)\n", cookie->bytes_per_sec_rate, cookie->bytes_per_sec_scale); - } else if (stream_header->rate) { - cookie->bytes_per_sec_rate = stream_header->rate; + } else if (stream_header->rate && stream_header->sample_size) { + cookie->bytes_per_sec_rate = stream_header->rate * stream_header->sample_size * audio_format->NoOfChannels / 8; cookie->bytes_per_sec_scale = 1; + cookie->frames_per_sec_rate = stream_header->sample_size; + 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 { cookie->frames_per_sec_rate = 16000; @@ -324,7 +330,6 @@ movReader::AllocateCookie(int32 streamNumber, void **_cookie) } cookie->audio = false; - cookie->frame_pos = 0; cookie->line_count = theFileReader->MovMainHeader()->height; if (stream_header->scale && stream_header->rate) { @@ -458,8 +463,14 @@ movReader::GetNextChunk(void *_cookie, mov_cookie *cookie = (mov_cookie *)_cookie; int64 start; uint32 size; bool keyframe; - if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe)) - return B_LAST_BUFFER_ERROR; + + if (cookie->audio) { + if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->chunk_pos, &start, &size, &keyframe)) + return B_LAST_BUFFER_ERROR; + } else { + if (!theFileReader->GetNextChunkInfo(cookie->stream, cookie->frame_pos, &start, &size, &keyframe)) + return B_LAST_BUFFER_ERROR; + } if (cookie->buffer_size < size) { delete [] cookie->buffer; @@ -468,20 +479,22 @@ movReader::GetNextChunk(void *_cookie, } if (cookie->audio) { - TRACE("Audio stream %d: frame %ld start %lld Size %ld key %d\n",cookie->stream, cookie->frame_pos, start, size, keyframe); - mediaHeader->start_time = (cookie->byte_pos * 1000000LL * (int64)cookie->bytes_per_sec_scale) / cookie->bytes_per_sec_rate; + TRACE("Audio stream %d: chunk %ld expected start %lld Size %ld key %d\n",cookie->stream, cookie->chunk_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 * 1000000L * 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); - // Should be frame_pos += frames per chunk + // 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; - if ((int64)cookie->frames_per_sec_scale > 0) { - cookie->frame_pos = ((mediaHeader->start_time * cookie->frames_per_sec_rate) / (int64)cookie->frames_per_sec_scale) / 1000000LL; - } else { - cookie->frame_pos = 0; - } -// cookie->frame_pos += theFileReader->getNoFramesInChunk(cookie->stream,cookie->frame_pos); -// cookie->frame_pos += 2205; + // 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; @@ -490,7 +503,7 @@ movReader::GetNextChunk(void *_cookie, mediaHeader->u.encoded_video.first_active_line = 0; mediaHeader->u.encoded_video.line_count = cookie->line_count; - cookie->frame_pos += 1; + cookie->frame_pos++; } TRACE("stream %d: start_time %.6f\n", cookie->stream, mediaHeader->start_time / 1000000.0);