hrev47719 adds 4 changesets to branch 'master' old head: 37bea90971b01478dbd89d2d8165a6a6471be3cc new head: b82ef8bc15614a52394f5f5626b719530e01cfa5 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=b82ef8b+%5E37bea90 ---------------------------------------------------------------------------- 54b392b: FFMPEG Plugin: Some cleanups. - Use name that correctly reflects the return value of avcodec_decode_video2(). - Make DO_PROFILING code path of AVCodecDecoder compile again. - No functional change intended. 8537123: FFMPEG Plugin: Refactor audio decoding method into two. - First method is solely responsible to fill the audio output buffer with already decoded audio frames. Second method is solely responsible for decoding the encoded audio data and put it in the decoded audio output buffer for further processing with the first method. This prepares auto detection of audio frame properties for audio formats where the properties are contained within the encoded audio frame (e.g. MP3), instead within the audio container format (e.g. WMA). Implementing auto detection is scheduled for a later commit though. - Added documentation accordingly. - No functional change intended. 3bca609: FFMPEG Plugin: Rename some variables in audio path. - Make the difference between fDecodedData and fDecodedDataBuffer more clear. - No functional change intended. b82ef8b: FFMPEG Plugin: Refactor scope of fTempPacket in audio path. - There are two main reasons for this refactoring: 1. Prepare using FFMPEGs functionality of audio frame start time assignment (instead of rolling it ourself) like already done for the video path (see _LoadNextVideoChunkIfNeededAndAssignStartTime() for reference). 2. Get rid of fChunkBufferOffset (this is a minor reason though). - Untangle some of the conditional checks to increase readability. - No functional change intended. [ Colin Günther <coling@xxxxxx> ] ---------------------------------------------------------------------------- 2 files changed, 203 insertions(+), 127 deletions(-) .../media/plugins/ffmpeg/AVCodecDecoder.cpp | 316 ++++++++++++------- .../media/plugins/ffmpeg/AVCodecDecoder.h | 14 +- ############################################################################ Commit: 54b392b4cc060fffd7ae2cb10be7bea28ff8b301 URL: http://cgit.haiku-os.org/haiku/commit/?id=54b392b Author: Colin Günther <coling@xxxxxx> Date: Wed Aug 20 10:45:01 2014 UTC FFMPEG Plugin: Some cleanups. - Use name that correctly reflects the return value of avcodec_decode_video2(). - Make DO_PROFILING code path of AVCodecDecoder compile again. - No functional change intended. ---------------------------------------------------------------------------- diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index 28cc577..38d25c2 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -771,9 +771,9 @@ AVCodecDecoder::_DecodeNextVideoFrame() // required to buffer the packets between different calls to // _DecodeNextVideoFrame(). int gotVideoFrame = 0; - int decodedDataSizeInBytes = avcodec_decode_video2(fContext, + int encodedDataSizeInBytes = avcodec_decode_video2(fContext, fRawDecodedPicture, &gotVideoFrame, &fTempPacket); - if (decodedDataSizeInBytes < 0) { + if (encodedDataSizeInBytes < 0) { TRACE("[v] AVCodecDecoder: ignoring error in decoding frame %lld:" " %d\n", fFrame, len); // NOTE: An error from avcodec_decode_video2() is ignored by the @@ -784,13 +784,13 @@ AVCodecDecoder::_DecodeNextVideoFrame() continue; } - fTempPacket.size -= decodedDataSizeInBytes; - fTempPacket.data += decodedDataSizeInBytes; + fTempPacket.size -= encodedDataSizeInBytes; + fTempPacket.data += encodedDataSizeInBytes; bool gotNoVideoFrame = gotVideoFrame == 0; if (gotNoVideoFrame) { - TRACE("frame %lld - no picture yet, decodedDataSizeInBytes: %d, " - "chunk size: %ld\n", fFrame, decodedDataSizeInBytes, + TRACE("frame %lld - no picture yet, encodedDataSizeInBytes: %d, " + "chunk size: %ld\n", fFrame, encodedDataSizeInBytes, fChunkBufferSize); continue; } @@ -807,19 +807,9 @@ AVCodecDecoder::_DecodeNextVideoFrame() conversionTime += doneTime - formatConversionStart; profileCounter++; if (!(fFrame % 5)) { - if (info) { - printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required " - "%Ld\n", - decodingTime / profileCounter, - conversionTime / profileCounter, - fFrame, info->time_to_decode); - } else { - printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required " - "%Ld\n", - decodingTime / profileCounter, - conversionTime / profileCounter, - fFrame, bigtime_t(1000000LL / fOutputFrameRate)); - } + printf("[v] profile: d1 = %lld, d2 = %lld (%lld) required %Ld\n", + decodingTime / profileCounter, conversionTime / profileCounter, + fFrame, bigtime_t(1000000LL / fOutputFrameRate)); decodingTime = 0; conversionTime = 0; profileCounter = 0; ############################################################################ Commit: 85371234ea80acd42cfbcc64d82ce0df79fb1e7b URL: http://cgit.haiku-os.org/haiku/commit/?id=8537123 Author: Colin Günther <coling@xxxxxx> Date: Wed Aug 20 19:25:19 2014 UTC FFMPEG Plugin: Refactor audio decoding method into two. - First method is solely responsible to fill the audio output buffer with already decoded audio frames. Second method is solely responsible for decoding the encoded audio data and put it in the decoded audio output buffer for further processing with the first method. This prepares auto detection of audio frame properties for audio formats where the properties are contained within the encoded audio frame (e.g. MP3), instead within the audio container format (e.g. WMA). Implementing auto detection is scheduled for a later commit though. - Added documentation accordingly. - No functional change intended. ---------------------------------------------------------------------------- diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index 38d25c2..cfae30a 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -545,17 +545,135 @@ AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat) } +/*! \brief Fills the outBuffer with one or more already decoded audio frames. + + Besides the main duty described above, this method also fills out the other + output parameters as documented below. + + \param outBuffer Pointer to the output buffer to copy the decoded audio + frames to. + \param outFrameCount Pointer to the output variable to assign the number of + copied audio frames (usually several audio frames at once). + \param mediaHeader Pointer to the output media header that contains the + properties of the decoded audio frame being the first in the outBuffer. + \param info Specifies additional decoding parameters. (Note: unused). + + \returns B_OK Decoding audio frames succeeded. + \returns B_LAST_BUFFER_ERROR There are no more audio frames available. + \returns Other error codes +*/ status_t -AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount, +AVCodecDecoder::_DecodeAudio(void* outBuffer, int64* outFrameCount, media_header* mediaHeader, media_decode_info* info) { TRACE_AUDIO("AVCodecDecoder::_DecodeAudio(audio start_time %.6fs)\n", mediaHeader->start_time / 1000000.0); - *outFrameCount = 0; + status_t audioDecodingStatus + = fDecodedDataSizeInBytes > 0 ? B_OK : _DecodeNextAudioFrame(); + + if (audioDecodingStatus != B_OK) + return audioDecodingStatus; + + *outFrameCount = fDecodedDataSizeInBytes / fOutputFrameSize; + memcpy(outBuffer, fDecodedData, fDecodedDataSizeInBytes); + + fDecodedDataSizeInBytes = 0; + + return B_OK; +} + + +/*! \brief Fills the outBuffer with an already decoded video frame. + + Besides the main duty described above, this method also fills out the other + output parameters as documented below. + + \param outBuffer Pointer to the output buffer to copy the decoded video + frame to. + \param outFrameCount Pointer to the output variable to assign the number of + copied video frames (usually one video frame). + \param mediaHeader Pointer to the output media header that contains the + decoded video frame properties. + \param info Specifies additional decoding parameters. (Note: unused). + + \returns B_OK Decoding a video frame succeeded. + \returns B_LAST_BUFFER_ERROR There are no more video frames available. + \returns Other error codes +*/ +status_t +AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, + media_header* mediaHeader, media_decode_info* info) +{ + status_t videoDecodingStatus + = fDecodedDataSizeInBytes > 0 ? B_OK : _DecodeNextVideoFrame(); + + if (videoDecodingStatus != B_OK) + return videoDecodingStatus; + + *outFrameCount = 1; + *mediaHeader = fHeader; + memcpy(outBuffer, fDecodedData, mediaHeader->size_used); + + fDecodedDataSizeInBytes = 0; + + return B_OK; +} + + +/*! \brief Decodes next audio frame. - uint8* buffer = reinterpret_cast<uint8*>(_buffer); - while (*outFrameCount < fOutputFrameCount) { + We decode at least one audio frame into fDecodedData. To achieve this goal, + we might need to request several chunks of encoded data resulting in a + variable execution time of this function. + + The length of the decoded audio frame(s) is stored in + fDecodedDataSizeInBytes. If this variable is greater than zero you can + assert that all audio frames in fDecodedData are valid. + + It is assumed that the number of expected audio frames is stored in + fOutputFrameCount. So _DecodeNextAudioFrame() must be called only after + fOutputFrameCount has been set. + + Note: fOutputFrameCount contains the maximum number of frames a caller + of BMediaDecoder::Decode() expects to receive. There is a direct + relationship between fOutputFrameCount and the buffer size a caller of + BMediaDecoder::Decode() will provide so we make sure to respect this limit + for fDecodedDataSizeInBytes. + + On return with status code B_OK the following conditions hold true: + 1. fDecodedData contains as much audio frames as the caller of + BMediaDecoder::Decode() expects. + 2. fDecodedData contains lesser audio frames as the caller of + BMediaDecoder::Decode() expects only when there are no more audio + frames left. Consecutive calls to _DecodeNextAudioFrame will then + result in the return of status code B_LAST_BUFFER_ERROR. + 3. TODO: make the following statement hold true, too: + fHeader is populated with the audio frame properties of the first + audio frame in fDecodedData. Especially the start_time field of + fHeader relates to that first audio frame. Start times of + consecutive audio frames in fDecodedData have to be calculated + manually (using the frame rate and the frame duration) if the + caller needs them. + + + \returns B_OK when we successfully decoded enough audio frames + \returns B_LAST_BUFFER_ERROR when there are no more audio frames available. + \returns B_NO_MEMORY when we have no memory left for correct operation. + \returns Other Errors +*/ +status_t +AVCodecDecoder::_DecodeNextAudioFrame() +{ + fDecodedDataSizeInBytes = 0; + size_t maximumSizeOfDecodedData = fOutputFrameCount * fOutputFrameSize; + if (fDecodedData == NULL) + fDecodedData + = static_cast<uint8_t*>(malloc(maximumSizeOfDecodedData)); + uint8_t* decodedData = fDecodedData; + + int64 currentFrameCount = 0; + while (currentFrameCount < fOutputFrameCount) { // Check conditions which would hint at broken code below. if (fOutputBufferSize < 0) { fprintf(stderr, "Decoding read past the end of the output buffer! " @@ -573,17 +691,17 @@ AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount, // invokation, which start at fOutputBufferOffset // and are of fOutputBufferSize. Copy those into the buffer, // but not more than it can hold. - int32 frames = min_c(fOutputFrameCount - *outFrameCount, + int32 frames = min_c(fOutputFrameCount - currentFrameCount, fOutputBufferSize / fOutputFrameSize); if (frames == 0) debugger("fOutputBufferSize not multiple of frame size!"); size_t remainingSize = frames * fOutputFrameSize; - memcpy(buffer, fOutputFrame->data[0] + fOutputBufferOffset, + memcpy(decodedData, fOutputFrame->data[0] + fOutputBufferOffset, remainingSize); fOutputBufferOffset += remainingSize; fOutputBufferSize -= remainingSize; - buffer += remainingSize; - *outFrameCount += frames; + decodedData += remainingSize; + currentFrameCount += frames; fStartTime += (bigtime_t)((1000000LL * frames) / fOutputFrameRate); continue; } @@ -632,7 +750,7 @@ AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount, usedBytes = fChunkBufferSize; fOutputBufferSize = 0; // Assume the audio decoded until now is broken. - memset(_buffer, 0, buffer - (uint8*)_buffer); + memset(fDecodedData, 0, decodedData - fDecodedData); } else { // Success fAudioDecodeError = false; @@ -652,45 +770,9 @@ AVCodecDecoder::_DecodeAudio(void* _buffer, int64* outFrameCount, fChunkBufferSize -= usedBytes; fOutputBufferOffset = 0; } - fFrame += *outFrameCount; - TRACE_AUDIO(" frame count: %lld current: %lld\n", *outFrameCount, fFrame); - - return B_OK; -} - - -/*! \brief Fills the outBuffer with an already decoded video frame. - - Besides the main duty described above, this method also fills out the other - output parameters as documented below. - - \param outBuffer Pointer to the output buffer to copy the decoded video - frame to. - \param outFrameCount Pointer to the output variable to assign the number of - copied video frames (usually one video frame). - \param mediaHeader Pointer to the output media header that contains the - decoded video frame properties. - \param info TODO (not used at the moment) - - \returns B_OK Decoding a video frame succeeded. - \returns B_LAST_BUFFER_ERROR There are no more video frames available. - \returns other error codes -*/ -status_t -AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, - media_header* mediaHeader, media_decode_info* info) -{ - status_t videoDecodingStatus - = fDecodedDataSizeInBytes > 0 ? B_OK : _DecodeNextVideoFrame(); - - if (videoDecodingStatus != B_OK) - return videoDecodingStatus; - - *outFrameCount = 1; - *mediaHeader = fHeader; - memcpy(outBuffer, fDecodedData, mediaHeader->size_used); - - fDecodedDataSizeInBytes = 0; + fFrame += currentFrameCount; + fDecodedDataSizeInBytes = currentFrameCount * fOutputFrameSize; + TRACE_AUDIO(" frame count: %lld current: %lld\n", currentFrameCount, fFrame); return B_OK; } @@ -948,7 +1030,7 @@ AVCodecDecoder::_LoadNextVideoChunkIfNeededAndAssignStartTime() Also update fChunkBufferSize to reflect the size of the contained video data (leaving out the padding). - + \param chunk The chunk to copy. \param chunkSize Size of the chunk in bytes diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index 8f00b95..40256bd 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -60,6 +60,7 @@ private: status_t _DecodeVideo(void* outBuffer, int64* outFrameCount, media_header* mediaHeader, media_decode_info* info); + status_t _DecodeNextAudioFrame(); status_t _DecodeNextVideoFrame(); void _ApplyEssentialVideoContainerPropertiesToContext(); status_t _LoadNextVideoChunkIfNeededAndAssignStartTime(); ############################################################################ Commit: 3bca609810310998daf639e27fbdcaa22cf49210 URL: http://cgit.haiku-os.org/haiku/commit/?id=3bca609 Author: Colin Günther <coling@xxxxxx> Date: Wed Aug 20 19:54:42 2014 UTC FFMPEG Plugin: Rename some variables in audio path. - Make the difference between fDecodedData and fDecodedDataBuffer more clear. - No functional change intended. ---------------------------------------------------------------------------- diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index cfae30a..7f18585 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -111,9 +111,9 @@ AVCodecDecoder::AVCodecDecoder() fChunkBufferSize(0), fAudioDecodeError(false), - fOutputFrame(avcodec_alloc_frame()), - fOutputBufferOffset(0), - fOutputBufferSize(0) + fDecodedDataBuffer(avcodec_alloc_frame()), + fDecodedDataBufferOffset(0), + fDecodedDataBufferSize(0) { TRACE("AVCodecDecoder::AVCodecDecoder()\n"); @@ -149,7 +149,7 @@ AVCodecDecoder::~AVCodecDecoder() av_free(fPostProcessedDecodedPicture); av_free(fRawDecodedPicture); av_free(fContext); - av_free(fOutputFrame); + av_free(fDecodedDataBuffer); #if USE_SWS_FOR_COLOR_SPACE_CONVERSION if (fSwsContext != NULL) @@ -271,8 +271,8 @@ AVCodecDecoder::SeekedTo(int64 frame, bigtime_t time) fChunkBuffer = NULL; fChunkBufferOffset = 0; fChunkBufferSize = 0; - fOutputBufferOffset = 0; - fOutputBufferSize = 0; + fDecodedDataBufferOffset = 0; + fDecodedDataBufferSize = 0; fDecodedDataSizeInBytes = 0; fFrame = frame; @@ -418,8 +418,8 @@ AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat) fChunkBufferOffset = 0; fChunkBufferSize = 0; fAudioDecodeError = false; - fOutputBufferOffset = 0; - fOutputBufferSize = 0; + fDecodedDataBufferOffset = 0; + fDecodedDataBufferSize = 0; _ResetTempPacket(); @@ -655,7 +655,7 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, consecutive audio frames in fDecodedData have to be calculated manually (using the frame rate and the frame duration) if the caller needs them. - + \returns B_OK when we successfully decoded enough audio frames \returns B_LAST_BUFFER_ERROR when there are no more audio frames available. @@ -675,10 +675,10 @@ AVCodecDecoder::_DecodeNextAudioFrame() int64 currentFrameCount = 0; while (currentFrameCount < fOutputFrameCount) { // Check conditions which would hint at broken code below. - if (fOutputBufferSize < 0) { - fprintf(stderr, "Decoding read past the end of the output buffer! " - "%ld\n", fOutputBufferSize); - fOutputBufferSize = 0; + if (fDecodedDataBufferSize < 0) { + fprintf(stderr, "Decoding read past the end of the decoded data " + "buffer! %ld\n", fDecodedDataBufferSize); + fDecodedDataBufferSize = 0; } if (fChunkBufferSize < 0) { fprintf(stderr, "Decoding read past the end of the chunk buffer! " @@ -686,20 +686,20 @@ AVCodecDecoder::_DecodeNextAudioFrame() fChunkBufferSize = 0; } - if (fOutputBufferSize > 0) { + if (fDecodedDataBufferSize > 0) { // We still have decoded audio frames from the last - // invokation, which start at fOutputBufferOffset - // and are of fOutputBufferSize. Copy those into the buffer, + // 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 - currentFrameCount, - fOutputBufferSize / fOutputFrameSize); + fDecodedDataBufferSize / fOutputFrameSize); if (frames == 0) - debugger("fOutputBufferSize not multiple of frame size!"); + debugger("fDecodedDataBufferSize not multiple of frame size!"); size_t remainingSize = frames * fOutputFrameSize; - memcpy(decodedData, fOutputFrame->data[0] + fOutputBufferOffset, - remainingSize); - fOutputBufferOffset += remainingSize; - fOutputBufferSize -= remainingSize; + memcpy(decodedData, fDecodedDataBuffer->data[0] + + fDecodedDataBufferOffset, remainingSize); + fDecodedDataBufferOffset += remainingSize; + fDecodedDataBufferSize -= remainingSize; decodedData += remainingSize; currentFrameCount += frames; fStartTime += (bigtime_t)((1000000LL * frames) / fOutputFrameRate); @@ -733,10 +733,10 @@ AVCodecDecoder::_DecodeNextAudioFrame() fTempPacket.data = (uint8_t*)fChunkBuffer + fChunkBufferOffset; fTempPacket.size = fChunkBufferSize; - avcodec_get_frame_defaults(fOutputFrame); + avcodec_get_frame_defaults(fDecodedDataBuffer); int gotFrame = 0; int usedBytes = avcodec_decode_audio4(fContext, - fOutputFrame, &gotFrame, &fTempPacket); + fDecodedDataBuffer, &gotFrame, &fTempPacket); if (usedBytes < 0 && !fAudioDecodeError) { // Report failure if not done already printf("########### audio decode error, " @@ -748,27 +748,27 @@ AVCodecDecoder::_DecodeNextAudioFrame() // Error or failure to produce decompressed output. // Skip the chunk buffer data entirely. usedBytes = fChunkBufferSize; - fOutputBufferSize = 0; + fDecodedDataBufferSize = 0; // Assume the audio decoded until now is broken. memset(fDecodedData, 0, decodedData - fDecodedData); } else { // Success fAudioDecodeError = false; if (gotFrame == 1) { - fOutputBufferSize = av_samples_get_buffer_size(NULL, - fContext->channels, fOutputFrame->nb_samples, + fDecodedDataBufferSize = av_samples_get_buffer_size(NULL, + fContext->channels, fDecodedDataBuffer->nb_samples, fContext->sample_fmt, 1); - if (fOutputBufferSize < 0) - fOutputBufferSize = 0; + if (fDecodedDataBufferSize < 0) + fDecodedDataBufferSize = 0; } else - fOutputBufferSize = 0; + fDecodedDataBufferSize = 0; } //printf(" chunk size: %d, decoded: %d, used: %d\n", //fTempPacket.size, decodedBytes, usedBytes); fChunkBufferOffset += usedBytes; fChunkBufferSize -= usedBytes; - fOutputBufferOffset = 0; + fDecodedDataBufferOffset = 0; } fFrame += currentFrameCount; fDecodedDataSizeInBytes = currentFrameCount * fOutputFrameSize; diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index 40256bd..cccd935 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -121,9 +121,9 @@ private: size_t fChunkBufferSize; bool fAudioDecodeError; - AVFrame* fOutputFrame; - int32 fOutputBufferOffset; - int32 fOutputBufferSize; + AVFrame* fDecodedDataBuffer; + int32 fDecodedDataBufferOffset; + int32 fDecodedDataBufferSize; AVPacket fTempPacket; }; ############################################################################ Revision: hrev47719 Commit: b82ef8bc15614a52394f5f5626b719530e01cfa5 URL: http://cgit.haiku-os.org/haiku/commit/?id=b82ef8b Author: Colin Günther <coling@xxxxxx> Date: Wed Aug 20 22:32:21 2014 UTC FFMPEG Plugin: Refactor scope of fTempPacket in audio path. - There are two main reasons for this refactoring: 1. Prepare using FFMPEGs functionality of audio frame start time assignment (instead of rolling it ourself) like already done for the video path (see _LoadNextVideoChunkIfNeededAndAssignStartTime() for reference). 2. Get rid of fChunkBufferOffset (this is a minor reason though). - Untangle some of the conditional checks to increase readability. - No functional change intended. ---------------------------------------------------------------------------- diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp index 7f18585..8031990 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.cpp @@ -107,7 +107,6 @@ AVCodecDecoder::AVCodecDecoder() fChunkBuffer(NULL), fVideoChunkBuffer(NULL), - fChunkBufferOffset(0), fChunkBufferSize(0), fAudioDecodeError(false), @@ -269,7 +268,6 @@ AVCodecDecoder::SeekedTo(int64 frame, bigtime_t time) // responsible for freeing the chunk buffer, too. fVideoChunkBuffer = NULL; fChunkBuffer = NULL; - fChunkBufferOffset = 0; fChunkBufferSize = 0; fDecodedDataBufferOffset = 0; fDecodedDataBufferSize = 0; @@ -415,7 +413,6 @@ AVCodecDecoder::_NegotiateAudioOutputFormat(media_format* inOutFormat) result, fOutputFrameSize, fOutputFrameCount, fOutputFrameRate); fChunkBuffer = NULL; - fChunkBufferOffset = 0; fChunkBufferSize = 0; fAudioDecodeError = false; fDecodedDataBufferOffset = 0; @@ -665,7 +662,11 @@ AVCodecDecoder::_DecodeVideo(void* outBuffer, int64* outFrameCount, status_t AVCodecDecoder::_DecodeNextAudioFrame() { - fDecodedDataSizeInBytes = 0; + assert(fTempPacket.size >= 0); + assert(fDecodedDataSizeInBytes == 0); + // _DecodeNextAudioFrame needs to be called on empty fDecodedData only! + // If this assert holds wrong we have a bug somewhere. + size_t maximumSizeOfDecodedData = fOutputFrameCount * fOutputFrameSize; if (fDecodedData == NULL) fDecodedData @@ -680,10 +681,10 @@ AVCodecDecoder::_DecodeNextAudioFrame() "buffer! %ld\n", fDecodedDataBufferSize); fDecodedDataBufferSize = 0; } - if (fChunkBufferSize < 0) { - fprintf(stderr, "Decoding read past the end of the chunk buffer! " - "%ld\n", fChunkBufferSize); - fChunkBufferSize = 0; + if (fTempPacket.size < 0) { + fprintf(stderr, "Decoding read past the end of the temp packet! " + "%d\n", fTempPacket.size); + fTempPacket.size = 0; } if (fDecodedDataBufferSize > 0) { @@ -705,7 +706,7 @@ AVCodecDecoder::_DecodeNextAudioFrame() fStartTime += (bigtime_t)((1000000LL * frames) / fOutputFrameRate); continue; } - if (fChunkBufferSize == 0) { + if (fTempPacket.size == 0) { // Time to read the next chunk buffer. We use a separate // media_header, since the chunk header may not belong to // the start of the decoded audio frames we return. For @@ -726,50 +727,53 @@ AVCodecDecoder::_DecodeNextAudioFrame() fChunkBufferSize = 0; break; } - fChunkBufferOffset = 0; + fTempPacket.data + = static_cast<uint8_t*>(const_cast<void*>(fChunkBuffer)); + fTempPacket.size = fChunkBufferSize; fStartTime = chunkMediaHeader.start_time; } - fTempPacket.data = (uint8_t*)fChunkBuffer + fChunkBufferOffset; - fTempPacket.size = fChunkBufferSize; - avcodec_get_frame_defaults(fDecodedDataBuffer); int gotFrame = 0; int usedBytes = avcodec_decode_audio4(fContext, fDecodedDataBuffer, &gotFrame, &fTempPacket); if (usedBytes < 0 && !fAudioDecodeError) { // Report failure if not done already + int32 chunkBufferOffset = fTempPacket.data + - static_cast<uint8_t*>(const_cast<void*>(fChunkBuffer)); printf("########### audio decode error, " - "fChunkBufferSize %ld, fChunkBufferOffset %ld\n", - fChunkBufferSize, fChunkBufferOffset); + "fTempPacket.size %d, fChunkBuffer data offset %ld\n", + fTempPacket.size, chunkBufferOffset); fAudioDecodeError = true; } if (usedBytes <= 0) { // Error or failure to produce decompressed output. - // Skip the chunk buffer data entirely. - usedBytes = fChunkBufferSize; - fDecodedDataBufferSize = 0; + // Skip the temp packet data entirely. + fTempPacket.size = 0; // Assume the audio decoded until now is broken. memset(fDecodedData, 0, decodedData - fDecodedData); - } else { - // Success - fAudioDecodeError = false; - if (gotFrame == 1) { - fDecodedDataBufferSize = av_samples_get_buffer_size(NULL, - fContext->channels, fDecodedDataBuffer->nb_samples, - fContext->sample_fmt, 1); - if (fDecodedDataBufferSize < 0) - fDecodedDataBufferSize = 0; - } else - fDecodedDataBufferSize = 0; + fDecodedDataBufferOffset = 0; + continue; } -//printf(" chunk size: %d, decoded: %d, used: %d\n", -//fTempPacket.size, decodedBytes, usedBytes); - fChunkBufferOffset += usedBytes; - fChunkBufferSize -= usedBytes; + fAudioDecodeError = false; + fDecodedDataBufferSize = 0; fDecodedDataBufferOffset = 0; + + fTempPacket.data += usedBytes; + fTempPacket.size -= usedBytes; + + bool gotNoAudioFrame = gotFrame == 0; + if (gotNoAudioFrame) + continue; + + fDecodedDataBufferSize = av_samples_get_buffer_size(NULL, + fContext->channels, fDecodedDataBuffer->nb_samples, + fContext->sample_fmt, 1); + if (fDecodedDataBufferSize < 0) + fDecodedDataBufferSize = 0; } + fFrame += currentFrameCount; fDecodedDataSizeInBytes = currentFrameCount * fOutputFrameSize; TRACE_AUDIO(" frame count: %lld current: %lld\n", currentFrameCount, fFrame); diff --git a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h index cccd935..8a4dd2f 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h +++ b/src/add-ons/media/plugins/ffmpeg/AVCodecDecoder.h @@ -114,10 +114,9 @@ private: const void* fChunkBuffer; uint8_t* fVideoChunkBuffer; // TODO: Remove and use fChunkBuffer again - // (with type uint8_t*) once the audio path is - // responsible for freeing the chunk buffer, - // too. - int32 fChunkBufferOffset; + // (with type uint8_t*) once the audio path + // is responsible for freeing the chunk + // buffer, too. size_t fChunkBufferSize; bool fAudioDecodeError;