Several improvements that make the audio playback

much more robust:
 * Use a much larger buffer size, since we cache
   a lot anyway.
 * When reading uncached frames, don't trip over the
   situation that the seekable keyframe was very far
   away from where we want to read. Don't get caught
   up in a loop decoding an entire movie, but return
   a time-out error instead. This will get us back
   on track eventually.
 * Before seeking to a keyframe, check if the current
   track position is actually nearer.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38498 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2010-09-01 16:02:42 +00:00
parent b4560be299
commit f96246077d

View File

@ -55,16 +55,17 @@ MediaTrackAudioSupplier::Buffer::CompareOffset(const void* a, const void* b)
MediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack,
int32 trackIndex)
: AudioTrackSupplier(),
fMediaTrack(mediaTrack),
fBuffer(NULL),
fBufferOffset(0),
fBufferSize(0),
fBuffers(10),
fHasKeyFrames(false),
fCountFrames(0),
fReportSeekError(true),
fTrackIndex(trackIndex)
:
AudioTrackSupplier(),
fMediaTrack(mediaTrack),
fBuffer(NULL),
fBufferOffset(0),
fBufferSize(0),
fBuffers(10),
fHasKeyFrames(false),
fCountFrames(0),
fReportSeekError(true),
fTrackIndex(trackIndex)
{
_InitFromTrack();
}
@ -235,13 +236,18 @@ MediaTrackAudioSupplier::InitCheck() const
void
MediaTrackAudioSupplier::_InitFromTrack()
{
TRACE("_InitFromTrack()\n");
// Try to suggest a big buffer size, we do a lot of caching...
fFormat.u.raw_audio.buffer_size = 16384;
if (fMediaTrack && fMediaTrack->DecodedFormat(&fFormat) == B_OK
&& fFormat.type == B_MEDIA_RAW_AUDIO) {
#ifdef TRACE_AUDIO_SUPPLIER
char formatString[256];
string_for_format(fFormat, formatString, 256);
TRACE("MediaTrackAudioSupplier: format is: %s\n", formatString);
TRACE("_InitFromTrack(): format is: %s\n", formatString);
TRACE("_InitFromTrack(): buffer size: %ld\n",
fFormat.u.raw_audio.buffer_size);
#endif
fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size];
@ -263,9 +269,9 @@ MediaTrackAudioSupplier::_InitFromTrack()
// get the length of the track
fCountFrames = fMediaTrack->CountFrames();
TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
TRACE("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames);
printf("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
printf("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
fHasKeyFrames, fCountFrames);
} else
fMediaTrack = NULL;
@ -384,7 +390,8 @@ MediaTrackAudioSupplier::Buffer*
MediaTrackAudioSupplier::_FindUnusedBuffer() const
{
Buffer* buffer = NULL;
for (int32 i = 0; ((buffer = _BufferAt(i))) && buffer->size != 0; i++);
for (int32 i = 0; ((buffer = _BufferAt(i))) && buffer->size != 0; i++)
;
return buffer;
}
@ -418,7 +425,7 @@ MediaTrackAudioSupplier::Buffer*
MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const
{
Buffer* buffer = _FindBufferAtFrame(position);
if (!buffer)
if (buffer == NULL)
buffer = _FindUsableBuffer();
return buffer;
}
@ -471,7 +478,8 @@ MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position,
{
status_t error = fMediaTrack->ReadFrames(buffer->data, &buffer->size);
TRACE("Read(%p, %lld): %s\n", buffer->data, buffer->size, strerror(error));
TRACE("_ReadBuffer(%p, %lld): %s\n", buffer->data, buffer->size,
strerror(error));
buffer->offset = position;
buffer->time_stamp = time;
@ -542,16 +550,21 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
if (frames > 0) {
error = _SeekToKeyFrameBackward(currentPos);
TRACE("_ReadUncachedFrames() - seeked to position: %lld\n", currentPos);
if (position - currentPos > 100000)
printf("MediaTrackAudioSupplier::_ReadUncachedFrames() - "
"keyframe was far away: %lld -> %lld\n", position, currentPos);
}
// read the frames
// TODO: Calculate timeout, 0.25 times duration of "frames" seems good.
bigtime_t timeout = 10000;
while (error == B_OK && frames > 0) {
Buffer* cacheBuffer = _FindUsableBufferFor(currentPos);
TRACE("_ReadUncachedFrames() - usable buffer found: %p\n", cacheBuffer);
TRACE("_ReadUncachedFrames() - usable buffer found: %p, "
"position: %lld/%lld\n", cacheBuffer, currentPos, position);
error = _ReadBuffer(cacheBuffer, currentPos, time);
if (error == B_OK) {
int64 size = min(position + frames,
cacheBuffer->offset + cacheBuffer->size)
- position;
cacheBuffer->offset + cacheBuffer->size) - position;
if (size > 0) {
_CopyFrames(cacheBuffer, buffer, position, position, size);
buffer = SkipFrames(buffer, size);
@ -560,9 +573,13 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
}
currentPos += cacheBuffer->size;
}
if (system_time() - time > timeout) {
error = B_TIMED_OUT;
break;
}
}
#if 1
#if 0
// Ensure that all frames up to the next key frame are cached.
// This avoids, that each read reaches the BMediaTrack.
if (error == B_OK) {
@ -652,21 +669,29 @@ MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
status_t
MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
{
if (position == fMediaTrack->CurrentFrame())
int64 currentPosition = fMediaTrack->CurrentFrame();
if (position == currentPosition)
return B_OK;
status_t error = B_OK;
if (fHasKeyFrames) {
int64 oldPosition = position;
int64 wantedPosition = position;
error = fMediaTrack->FindKeyFrameForFrame(&position,
B_MEDIA_SEEK_CLOSEST_BACKWARD);
if (error == B_OK && currentPosition > position
&& currentPosition < wantedPosition) {
// The current position is before the wanted position,
// but later than the keyframe, so seeking is worse.
position = currentPosition;
return B_OK;
}
if (error == B_OK)
error = fMediaTrack->SeekToFrame(&position, 0);
if (error != B_OK) {
position = fMediaTrack->CurrentFrame();
// if (fReportSeekError) {
printf(" seek to key frame backward: %lld -> %lld (%lld) "
"- %s\n", oldPosition, position,
"- %s\n", wantedPosition, position,
fMediaTrack->CurrentFrame(), strerror(error));
fReportSeekError = false;
// }