From ca5c686d9352a8b178549b06fcb2a74488bb5caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20G=C3=BCnther?= Date: Fri, 22 Aug 2014 13:36:38 +0200 Subject: [PATCH] FFMPEG Plugin: Refactor out moving audio frames from buffer. - Main reason for this refactoring is to increase readability and thus make the audio decode path more comprehensible. - Added documentation for the new method accordingly. - No functional change intended. --- .../media/plugins/ffmpeg/AVCodecDecoder.cpp | 130 ++++++++++++------ .../media/plugins/ffmpeg/AVCodecDecoder.h | 1 + 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index ce1dd15144..d7dd2e5457 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -684,47 +684,9 @@ AVCodecDecoder::_DecodeNextAudioFrame() fTempPacket.size = 0; } - if (fDecodedDataBufferSize > 0) { - // We still have decoded audio frames from the last - // invokation, which start at fDecodedDataBufferOffset - // and are of fDecodedDataBufferSize. Copy those into the buffer, - // but not more than it can hold. - int32 frames - = min_c(fOutputFrameCount - fRawDecodedAudio->nb_samples, - fDecodedDataBufferSize / fOutputFrameSize); - if (frames == 0) - debugger("fDecodedDataBufferSize not multiple of frame size!"); - size_t remainingSize = frames * fOutputFrameSize; - - memcpy(fRawDecodedAudio->data[0], fDecodedDataBuffer->data[0] - + fDecodedDataBufferOffset, remainingSize); - - bool firstAudioFramesCopiedToRawDecodedAudio - = fRawDecodedAudio->data[0] != fDecodedData; - if (!firstAudioFramesCopiedToRawDecodedAudio) { - fRawDecodedAudio->format = fDecodedDataBuffer->format; - fRawDecodedAudio->pkt_dts = fDecodedDataBuffer->pkt_dts; - - // TODO: also store the following fContext fields in the - // opaque field of fRawDecodedAudio: - // - fContext->channels - // - fContext->sample_rate - // Those fields a are needed to allow the client of - // BMediaDecoder::Decode() to detect an audio format change. - } - - fDecodedDataBufferOffset += remainingSize; - fDecodedDataBufferSize -= remainingSize; - fRawDecodedAudio->data[0] += remainingSize; - fRawDecodedAudio->nb_samples += frames; - - // Update start times - bigtime_t framesTimeInterval = static_cast( - (1000000LL * frames) / fOutputFrameRate); - fDecodedDataBuffer->pkt_dts += framesTimeInterval; - fTempPacket.dts += framesTimeInterval; - // Note: Start time of fTempPacket is updated in case the - // fTempPacket contains more audio frames to decode. + bool decodedDataBufferHasData = fDecodedDataBufferSize > 0; + if (decodedDataBufferHasData) { + _MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes(); continue; } @@ -768,6 +730,92 @@ AVCodecDecoder::_DecodeNextAudioFrame() } +/*! \brief Moves audio frames from fDecodedDataBuffer to fRawDecodedAudio (and + thus to fDecodedData) and updates the start times of fRawDecodedAudio, + fDecodedDataBuffer and fTempPacket accordingly. + + When moving audio frames to fRawDecodedAudio this method also makes sure + that the following important fields of fRawDecodedAudio are populated and + updated with correct values: + - fRawDecodedAudio->format: Format of first audio frame + - fRawDecodedAudio->pkt_dts: Start time of first audio frame + - fRawDecodedAudio->nb_samples: Number of audio frames + - fRawDecodedAudio->opaque: TODO: Will contain the following fields + from fContext for the first audio frame: + - fContext->channels: Channel count of first audio frame + - fContext->sample_rate: Frame rate of first audio frame + + This function assumes to be called only when the following assumptions + hold true: + 1. There are decoded audio frames available in fDecodedDataBuffer + meaning that fDecodedDataBufferSize is greater than zero. + 2. There is space left in fRawDecodedAudio to move some audio frames + in. This means that fRawDecodedAudio has lesser audio frames than + the maximum allowed (specified by fOutputFrameCount). + 3. The audio frame rate is known so that we can calculate the time + range (covered by the moved audio frames) to update the start times + accordingly. + + After this function returns the caller can safely make the following + assumptions: + 1. The number of decoded audio frames in fDecodedDataBuffer is + decreased though it may still be greater then zero. + 2. The number of frames in fRawDecodedAudio has increased and all + important fields are updated (see listing above). + 3. Start times of fDecodedDataBuffer and fTempPacket were increased + with the time range covered by the moved audio frames. + + Note: This function raises an exception (by calling the debugger), when + fDecodedDataBufferSize is not a multiple of fOutputFrameSize. +*/ +void +AVCodecDecoder::_MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes() +{ + assert(fDecodedDataBufferSize > 0); + assert(fRawDecodedAudio->nb_samples < fOutputFrameCount); + assert(fOutputFrameRate > 0); + + int32 frames = min_c(fOutputFrameCount - fRawDecodedAudio->nb_samples, + fDecodedDataBufferSize / fOutputFrameSize); + if (frames == 0) + debugger("fDecodedDataBufferSize not multiple of frame size!"); + + size_t remainingSize = frames * fOutputFrameSize; + memcpy(fRawDecodedAudio->data[0], fDecodedDataBuffer->data[0] + + fDecodedDataBufferOffset, remainingSize); + + bool firstAudioFramesCopiedToRawDecodedAudio + = fRawDecodedAudio->data[0] != fDecodedData; + if (!firstAudioFramesCopiedToRawDecodedAudio) { + fRawDecodedAudio->format = fDecodedDataBuffer->format; + fRawDecodedAudio->pkt_dts = fDecodedDataBuffer->pkt_dts; + + // TODO: also store the following fContext fields in the + // opaque field of fRawDecodedAudio: + // - fContext->channels + // - fContext->sample_rate + // Those fields a are needed to allow the client of + // BMediaDecoder::Decode() to detect an audio format change. + } + + fRawDecodedAudio->data[0] += remainingSize; + fRawDecodedAudio->nb_samples += frames; + + fDecodedDataBufferOffset += remainingSize; + fDecodedDataBufferSize -= remainingSize; + + // Update start times accordingly + bigtime_t framesTimeInterval = static_cast( + (1000000LL * frames) / fOutputFrameRate); + fDecodedDataBuffer->pkt_dts += framesTimeInterval; + // Start time of buffer is updated in case that it contains + // more audio frames to move. + fTempPacket.dts += framesTimeInterval; + // Start time of fTempPacket is updated in case the fTempPacket + // contains more audio frames to decode. +} + + /*! \brief Loads the next audio chunk into fChunkBuffer and assigns it (including the start time) to fTempPacket accordingly only if fTempPacket is empty. diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index 61f9ac61bd..8034104e2a 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -61,6 +61,7 @@ private: media_header* mediaHeader, media_decode_info* info); status_t _DecodeNextAudioFrame(); + void _MoveAudioFramesToRawDecodedAudioAndUpdateStartTimes(); status_t _LoadNextAudioChunkIfNeededAndAssignStartTime(); status_t _DecodeSomeAudioFramesIntoEmptyDecodedDataBuffer(); status_t _DecodeNextVideoFrame();