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:
@@ -55,16 +55,17 @@ MediaTrackAudioSupplier::Buffer::CompareOffset(const void* a, const void* b)
|
|||||||
|
|
||||||
MediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack,
|
MediaTrackAudioSupplier::MediaTrackAudioSupplier(BMediaTrack* mediaTrack,
|
||||||
int32 trackIndex)
|
int32 trackIndex)
|
||||||
: AudioTrackSupplier(),
|
:
|
||||||
fMediaTrack(mediaTrack),
|
AudioTrackSupplier(),
|
||||||
fBuffer(NULL),
|
fMediaTrack(mediaTrack),
|
||||||
fBufferOffset(0),
|
fBuffer(NULL),
|
||||||
fBufferSize(0),
|
fBufferOffset(0),
|
||||||
fBuffers(10),
|
fBufferSize(0),
|
||||||
fHasKeyFrames(false),
|
fBuffers(10),
|
||||||
fCountFrames(0),
|
fHasKeyFrames(false),
|
||||||
fReportSeekError(true),
|
fCountFrames(0),
|
||||||
fTrackIndex(trackIndex)
|
fReportSeekError(true),
|
||||||
|
fTrackIndex(trackIndex)
|
||||||
{
|
{
|
||||||
_InitFromTrack();
|
_InitFromTrack();
|
||||||
}
|
}
|
||||||
@@ -235,13 +236,18 @@ MediaTrackAudioSupplier::InitCheck() const
|
|||||||
void
|
void
|
||||||
MediaTrackAudioSupplier::_InitFromTrack()
|
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
|
if (fMediaTrack && fMediaTrack->DecodedFormat(&fFormat) == B_OK
|
||||||
&& fFormat.type == B_MEDIA_RAW_AUDIO) {
|
&& fFormat.type == B_MEDIA_RAW_AUDIO) {
|
||||||
|
|
||||||
#ifdef TRACE_AUDIO_SUPPLIER
|
#ifdef TRACE_AUDIO_SUPPLIER
|
||||||
char formatString[256];
|
char formatString[256];
|
||||||
string_for_format(fFormat, 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
|
#endif
|
||||||
|
|
||||||
fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size];
|
fBuffer = new (nothrow) char[fFormat.u.raw_audio.buffer_size];
|
||||||
@@ -263,9 +269,9 @@ MediaTrackAudioSupplier::_InitFromTrack()
|
|||||||
// get the length of the track
|
// get the length of the track
|
||||||
fCountFrames = fMediaTrack->CountFrames();
|
fCountFrames = fMediaTrack->CountFrames();
|
||||||
|
|
||||||
TRACE("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
|
TRACE("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
|
||||||
fHasKeyFrames, fCountFrames);
|
fHasKeyFrames, fCountFrames);
|
||||||
printf("MediaTrackAudioSupplier: keyframes: %d, frame count: %lld\n",
|
printf("_InitFromTrack(): keyframes: %d, frame count: %lld\n",
|
||||||
fHasKeyFrames, fCountFrames);
|
fHasKeyFrames, fCountFrames);
|
||||||
} else
|
} else
|
||||||
fMediaTrack = NULL;
|
fMediaTrack = NULL;
|
||||||
@@ -384,7 +390,8 @@ MediaTrackAudioSupplier::Buffer*
|
|||||||
MediaTrackAudioSupplier::_FindUnusedBuffer() const
|
MediaTrackAudioSupplier::_FindUnusedBuffer() const
|
||||||
{
|
{
|
||||||
Buffer* buffer = NULL;
|
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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +425,7 @@ MediaTrackAudioSupplier::Buffer*
|
|||||||
MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const
|
MediaTrackAudioSupplier::_FindUsableBufferFor(int64 position) const
|
||||||
{
|
{
|
||||||
Buffer* buffer = _FindBufferAtFrame(position);
|
Buffer* buffer = _FindBufferAtFrame(position);
|
||||||
if (!buffer)
|
if (buffer == NULL)
|
||||||
buffer = _FindUsableBuffer();
|
buffer = _FindUsableBuffer();
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@@ -471,7 +478,8 @@ MediaTrackAudioSupplier::_ReadBuffer(Buffer* buffer, int64 position,
|
|||||||
{
|
{
|
||||||
status_t error = fMediaTrack->ReadFrames(buffer->data, &buffer->size);
|
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->offset = position;
|
||||||
buffer->time_stamp = time;
|
buffer->time_stamp = time;
|
||||||
@@ -542,16 +550,21 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
|
|||||||
if (frames > 0) {
|
if (frames > 0) {
|
||||||
error = _SeekToKeyFrameBackward(currentPos);
|
error = _SeekToKeyFrameBackward(currentPos);
|
||||||
TRACE("_ReadUncachedFrames() - seeked to position: %lld\n", 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
|
// read the frames
|
||||||
|
// TODO: Calculate timeout, 0.25 times duration of "frames" seems good.
|
||||||
|
bigtime_t timeout = 10000;
|
||||||
while (error == B_OK && frames > 0) {
|
while (error == B_OK && frames > 0) {
|
||||||
Buffer* cacheBuffer = _FindUsableBufferFor(currentPos);
|
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);
|
error = _ReadBuffer(cacheBuffer, currentPos, time);
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
int64 size = min(position + frames,
|
int64 size = min(position + frames,
|
||||||
cacheBuffer->offset + cacheBuffer->size)
|
cacheBuffer->offset + cacheBuffer->size) - position;
|
||||||
- position;
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
_CopyFrames(cacheBuffer, buffer, position, position, size);
|
_CopyFrames(cacheBuffer, buffer, position, position, size);
|
||||||
buffer = SkipFrames(buffer, size);
|
buffer = SkipFrames(buffer, size);
|
||||||
@@ -560,9 +573,13 @@ MediaTrackAudioSupplier::_ReadUncachedFrames(void* buffer, int64 position,
|
|||||||
}
|
}
|
||||||
currentPos += cacheBuffer->size;
|
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.
|
// Ensure that all frames up to the next key frame are cached.
|
||||||
// This avoids, that each read reaches the BMediaTrack.
|
// This avoids, that each read reaches the BMediaTrack.
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
@@ -652,21 +669,29 @@ MediaTrackAudioSupplier::_SeekToKeyFrameForward(int64& position)
|
|||||||
status_t
|
status_t
|
||||||
MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
|
MediaTrackAudioSupplier::_SeekToKeyFrameBackward(int64& position)
|
||||||
{
|
{
|
||||||
if (position == fMediaTrack->CurrentFrame())
|
int64 currentPosition = fMediaTrack->CurrentFrame();
|
||||||
|
if (position == currentPosition)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
if (fHasKeyFrames) {
|
if (fHasKeyFrames) {
|
||||||
int64 oldPosition = position;
|
int64 wantedPosition = position;
|
||||||
error = fMediaTrack->FindKeyFrameForFrame(&position,
|
error = fMediaTrack->FindKeyFrameForFrame(&position,
|
||||||
B_MEDIA_SEEK_CLOSEST_BACKWARD);
|
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)
|
if (error == B_OK)
|
||||||
error = fMediaTrack->SeekToFrame(&position, 0);
|
error = fMediaTrack->SeekToFrame(&position, 0);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
position = fMediaTrack->CurrentFrame();
|
position = fMediaTrack->CurrentFrame();
|
||||||
// if (fReportSeekError) {
|
// if (fReportSeekError) {
|
||||||
printf(" seek to key frame backward: %lld -> %lld (%lld) "
|
printf(" seek to key frame backward: %lld -> %lld (%lld) "
|
||||||
"- %s\n", oldPosition, position,
|
"- %s\n", wantedPosition, position,
|
||||||
fMediaTrack->CurrentFrame(), strerror(error));
|
fMediaTrack->CurrentFrame(), strerror(error));
|
||||||
fReportSeekError = false;
|
fReportSeekError = false;
|
||||||
// }
|
// }
|
||||||
|
|||||||
Reference in New Issue
Block a user