From 97a08414e0734b788b742f6ac5512dec0b952972 Mon Sep 17 00:00:00 2001 From: shatty Date: Mon, 26 Jan 2004 10:51:54 +0000 Subject: [PATCH] accurate frame count and duration computation. SoundPlay seems to behave /slightly/ better now. At least it stopped machine-gun playing the files. unfortunately the caching packet implementation seems to come with a drawback. the granulepos is only valid on the initial traversal through the file. not sure why but this means that we only get one shot at computing the frame count and duration, so I cached them for the time being. it would be nice to be clever about recomputing the frame count and duration in the face of changing file sizes (downloads) and not traverse the whole file anyway, but this will require some more work. also we may (will?) need those granulepos for seek. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6327 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/plugins/ogg/OggVorbisStream.cpp | 52 +++++++++++++------ .../media/plugins/ogg/OggVorbisStream.h | 3 ++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/add-ons/media/plugins/ogg/OggVorbisStream.cpp b/src/add-ons/media/plugins/ogg/OggVorbisStream.cpp index 82fcce2654..cb1ff41fff 100644 --- a/src/add-ons/media/plugins/ogg/OggVorbisStream.cpp +++ b/src/add-ons/media/plugins/ogg/OggVorbisStream.cpp @@ -87,6 +87,8 @@ OggVorbisStream::OggVorbisStream(long serialno) : OggStream(serialno) { TRACE("OggVorbisStream::OggVorbisStream\n"); + fFrameCount = -1; + fDuration = -1; } OggVorbisStream::~OggVorbisStream() @@ -182,29 +184,47 @@ OggVorbisStream::GetStreamInfo(int64 *frameCount, bigtime_t *duration, format->SetMetaData((void*)&fHeaderPackets,sizeof(fHeaderPackets)); - // compute duration/frameCount + // use cached frame count and duration for now + if (fDuration >= 0) { + *frameCount = fFrameCount; + *duration = fDuration; + return B_OK; + } -#ifdef STREAMING_COMPATIBLE_HARDCODED_DURATION - *duration = 100000000; - *frameCount = 60000; -#else - int64 frame = 0; - bigtime_t time = 0; void *chunkBuffer = 0; int32 chunkSize = 0; media_header mediaHeader; - off_t bytes = 0; - while (GetNextChunk(&chunkBuffer, &chunkSize, &mediaHeader) == B_OK) { - ogg_packet * packet = static_cast(chunkBuffer); - bytes += packet->bytes; - frame++; + if (GetNextChunk(&chunkBuffer, &chunkSize, &mediaHeader) != B_OK) { + *frameCount = 0; + *duration = 0; + return B_OK; } - time += (8000000 * bytes) / format->u.encoded_audio.bit_rate; - *frameCount = frame; - *duration = time; + ogg_packet * chunk_packet = static_cast(chunkBuffer); + ogg_int64_t first_packet_granulepos = chunk_packet->granulepos; + ogg_int64_t last_packet_granulepos = chunk_packet->granulepos; + ogg_int64_t next_packet = chunk_packet->packetno + 1; + int64 samples = 0; + while (GetNextChunk(&chunkBuffer, &chunkSize, &mediaHeader) == B_OK) { + chunk_packet = static_cast(chunkBuffer); + if (chunk_packet->packetno != next_packet) { + // there's a hole in the data, add samples so far, and start counting again + TRACE("OggVorbisStream::GetStreamInfo: substream end\n"); + samples += last_packet_granulepos - first_packet_granulepos; + first_packet_granulepos = chunk_packet->granulepos; + } + last_packet_granulepos = chunk_packet->granulepos; + next_packet = chunk_packet->packetno + 1; + } + samples += last_packet_granulepos - first_packet_granulepos; + + // compute frame count and duration from sample count + *frameCount = fFrameCount = samples; + *duration = fDuration = (1000000LL * samples) / (long long)format->u.encoded_audio.output.frame_rate; + + // restore our position to the start int64 start_frame = 0; bigtime_t start_time = 0; Seek(B_MEDIA_SEEK_TO_FRAME, &start_frame, &start_time); -#endif + return B_OK; } diff --git a/src/add-ons/media/plugins/ogg/OggVorbisStream.h b/src/add-ons/media/plugins/ogg/OggVorbisStream.h index 7d13c7712a..647f2cce8b 100644 --- a/src/add-ons/media/plugins/ogg/OggVorbisStream.h +++ b/src/add-ons/media/plugins/ogg/OggVorbisStream.h @@ -14,6 +14,9 @@ public: virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration, media_format *format); +private: + int64 fFrameCount; + bigtime_t fDuration; }; } } // namespace BPrivate::media