From dd6c620b53272e2eb4b091a835cd250309f04cad Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 28 Oct 2012 18:24:50 +0100 Subject: player: Recover from AAC decoding error Decoding errors are usually not fatal, so we can recover by skipping the broken frame. This also fixes invalid memory reads caused by sampleSizeCurr >= sampleSizeN. See issue #304. --- src/player.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/player.c b/src/player.c index 0e249dc..92524c7 100644 --- a/src/player.c +++ b/src/player.c @@ -28,6 +28,7 @@ THE SOFTWARE. #include #include #include +#include #include #include "player.h" @@ -135,17 +136,31 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, NeAACDecFrameInfo frameInfo; size_t i; - while ((player->bufferFilled - player->bufferRead) > - player->sampleSize[player->sampleSizeCurr]) { + while (player->sampleSizeCurr < player->sampleSizeN && + (player->bufferFilled - player->bufferRead) >= + player->sampleSize[player->sampleSizeCurr]) { + /* going through this loop can take up to a few seconds => + * allow earlier thread abort */ + QUIT_PAUSE_CHECK; + /* decode frame */ aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, - player->buffer + player->bufferRead, + &player->buffer[player->bufferRead], player->sampleSize[player->sampleSizeCurr]); + player->bufferRead += player->sampleSize[player->sampleSizeCurr]; + ++player->sampleSizeCurr; + if (frameInfo.error != 0) { + /* skip this frame, songPlayed will be slightly off if this + * happens */ BarUiMsg (player->settings, MSG_ERR, "Decoding error: %s\n", NeAACDecGetErrorMessage (frameInfo.error)); - break; + continue; } + /* assuming data in stsz atom is correct */ + assert (frameInfo.bytesconsumed == + player->sampleSize[player->sampleSizeCurr-1]); + for (i = 0; i < frameInfo.samples; i++) { aacDecoded[i] = applyReplayGain (aacDecoded[i], player->scale); } @@ -157,11 +172,10 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, (unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR / (unsigned long long int) player->samplerate / (unsigned long long int) player->channels; - player->bufferRead += frameInfo.bytesconsumed; - player->sampleSizeCurr++; - /* going through this loop can take up to a few seconds => - * allow earlier thread abort */ - QUIT_PAUSE_CHECK; + } + if (player->sampleSizeCurr >= player->sampleSizeN) { + /* no more frames, drop data */ + player->bufferRead = player->bufferFilled; } } else { if (player->mode == PLAYER_INITIALIZED) { -- cgit v1.2.3