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
This commit is contained in:
shatty 2004-01-26 10:51:54 +00:00
parent c4e3ef09c4
commit 97a08414e0
2 changed files with 39 additions and 16 deletions

View File

@ -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<ogg_packet *>(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<ogg_packet *>(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<ogg_packet *>(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;
}

View File

@ -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