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.
This commit is contained in:
Colin Günther
2014-08-21 00:46:58 +02:00
parent 54b392b4cc
commit 85371234ea
2 changed files with 132 additions and 49 deletions
@@ -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();
uint8* buffer = reinterpret_cast<uint8*>(_buffer);
while (*outFrameCount < fOutputFrameCount) {
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.
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
@@ -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();