Squashed commit of the following:

commit 4abf16bb04dc9695fedf4007a84f903074312ccd
Author: Andreas Huber <andih@google.com>
Date:   Tue Jul 20 09:21:17 2010 -0700

    Support a single format change at the beginning of audio playback. This way the AAC+ decoder may change its output format from what is originally encoded in the audio stream and we'll still play it back correctly.

    Change-Id: Icc790122744745e9a88099788d4818ca1e265a82
    related-to-bug: 2826841

commit 09c74da63e6ad5cb5dafb70f62696d75d2978967
Author: James Dong <jdong@google.com>
Date:   Sun Jul 18 17:57:01 2010 -0700

    Fix MPEG4Extractor to extract sampling frequency correctly when SBR is enabled.

    Change-Id: I883c81dad3ea465e71cb5590e89d763671a90ff8

commit f672bf2a782dc7d5fb6325d611a7fe17045dfe9a
Author: James Dong <jdong@google.com>
Date:   Thu Jul 8 20:56:13 2010 -0700

    Enable the support for decoding audio with AAC+ and eAAC+ features

    bug - 282684

    Change-Id: I73c8377af3cc4edd3ee7cea86dc3b1c369fbd78b

Change-Id: I012f1179e933b6d1345d2368f357576c722485f7
This commit is contained in:
Andreas Huber
2010-07-20 09:44:34 -07:00
parent 3bf5c4cd30
commit 16263d9f8c
4 changed files with 136 additions and 48 deletions

View File

@@ -86,6 +86,10 @@ private:
bool mStarted; bool mStarted;
bool mIsFirstBuffer;
status_t mFirstBufferResult;
MediaBuffer *mFirstBuffer;
sp<MediaPlayerBase::AudioSink> mAudioSink; sp<MediaPlayerBase::AudioSink> mAudioSink;
static void AudioCallback(int event, void *user, void *info); static void AudioCallback(int event, void *user, void *info);

View File

@@ -23,6 +23,7 @@
#include <media/stagefright/AudioPlayer.h> #include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h> #include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h> #include <media/stagefright/MetaData.h>
@@ -41,6 +42,9 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
mReachedEOS(false), mReachedEOS(false),
mFinalStatus(OK), mFinalStatus(OK),
mStarted(false), mStarted(false),
mIsFirstBuffer(false),
mFirstBufferResult(OK),
mFirstBuffer(NULL),
mAudioSink(audioSink) { mAudioSink(audioSink) {
} }
@@ -68,6 +72,24 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
} }
} }
// We allow an optional INFO_FORMAT_CHANGED at the very beginning
// of playback, if there is one, getFormat below will retrieve the
// updated format, if there isn't, we'll stash away the valid buffer
// of data to be used on the first audio callback.
CHECK(mFirstBuffer == NULL);
mFirstBufferResult = mSource->read(&mFirstBuffer);
if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
LOGV("INFO_FORMAT_CHANGED!!!");
CHECK(mFirstBuffer == NULL);
mFirstBufferResult = OK;
mIsFirstBuffer = false;
} else {
mIsFirstBuffer = true;
}
sp<MetaData> format = mSource->getFormat(); sp<MetaData> format = mSource->getFormat();
const char *mime; const char *mime;
bool success = format->findCString(kKeyMIMEType, &mime); bool success = format->findCString(kKeyMIMEType, &mime);
@@ -87,7 +109,14 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
DEFAULT_AUDIOSINK_BUFFERCOUNT, DEFAULT_AUDIOSINK_BUFFERCOUNT,
&AudioPlayer::AudioSinkCallback, this); &AudioPlayer::AudioSinkCallback, this);
if (err != OK) { if (err != OK) {
mSource->stop(); if (mFirstBuffer != NULL) {
mFirstBuffer->release();
mFirstBuffer = NULL;
}
if (!sourceAlreadyStarted) {
mSource->stop();
}
return err; return err;
} }
@@ -108,7 +137,14 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
delete mAudioTrack; delete mAudioTrack;
mAudioTrack = NULL; mAudioTrack = NULL;
mSource->stop(); if (mFirstBuffer != NULL) {
mFirstBuffer->release();
mFirstBuffer = NULL;
}
if (!sourceAlreadyStarted) {
mSource->stop();
}
return err; return err;
} }
@@ -159,6 +195,12 @@ void AudioPlayer::stop() {
// Make sure to release any buffer we hold onto so that the // Make sure to release any buffer we hold onto so that the
// source is able to stop(). // source is able to stop().
if (mFirstBuffer != NULL) {
mFirstBuffer->release();
mFirstBuffer = NULL;
}
if (mInputBuffer != NULL) { if (mInputBuffer != NULL) {
LOGV("AudioPlayer releasing input buffer."); LOGV("AudioPlayer releasing input buffer.");
@@ -243,6 +285,14 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
if (mSeeking) { if (mSeeking) {
if (mIsFirstBuffer) {
if (mFirstBuffer != NULL) {
mFirstBuffer->release();
mFirstBuffer = NULL;
}
mIsFirstBuffer = false;
}
options.setSeekTo(mSeekTimeUs); options.setSeekTo(mSeekTimeUs);
if (mInputBuffer != NULL) { if (mInputBuffer != NULL) {
@@ -255,7 +305,17 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
} }
if (mInputBuffer == NULL) { if (mInputBuffer == NULL) {
status_t err = mSource->read(&mInputBuffer, &options); status_t err;
if (mIsFirstBuffer) {
mInputBuffer = mFirstBuffer;
mFirstBuffer = NULL;
err = mFirstBufferResult;
mIsFirstBuffer = false;
} else {
err = mSource->read(&mInputBuffer, &options);
}
CHECK((err == OK && mInputBuffer != NULL) CHECK((err == OK && mInputBuffer != NULL)
|| (err != OK && mInputBuffer == NULL)); || (err != OK && mInputBuffer == NULL));

View File

@@ -15,6 +15,7 @@
*/ */
#include "AACDecoder.h" #include "AACDecoder.h"
#define LOG_TAG "AACDecoder"
#include "../../include/ESDS.h" #include "../../include/ESDS.h"
@@ -36,26 +37,33 @@ AACDecoder::AACDecoder(const sp<MediaSource> &source)
mAnchorTimeUs(0), mAnchorTimeUs(0),
mNumSamplesOutput(0), mNumSamplesOutput(0),
mInputBuffer(NULL) { mInputBuffer(NULL) {
}
AACDecoder::~AACDecoder() { sp<MetaData> srcFormat = mSource->getFormat();
if (mStarted) {
stop(); int32_t sampleRate;
CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
mMeta = new MetaData;
mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
// We'll always output stereo, regardless of how many channels are
// present in the input due to decoder limitations.
mMeta->setInt32(kKeyChannelCount, 2);
mMeta->setInt32(kKeySampleRate, sampleRate);
int64_t durationUs;
if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
mMeta->setInt64(kKeyDuration, durationUs);
} }
mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
delete mConfig; mInitCheck = initCheck();
mConfig = NULL;
} }
status_t AACDecoder::start(MetaData *params) { status_t AACDecoder::initCheck() {
CHECK(!mStarted); memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
mBufferGroup = new MediaBufferGroup;
mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED; mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
mConfig->aacPlusUpsamplingFactor = 0; mConfig->aacPlusEnabled = 1;
mConfig->aacPlusEnabled = false;
// The software decoder doesn't properly support mono output on // The software decoder doesn't properly support mono output on
// AACplus files. Always output stereo. // AACplus files. Always output stereo.
@@ -64,8 +72,11 @@ status_t AACDecoder::start(MetaData *params) {
UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements(); UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
mDecoderBuf = malloc(memRequirements); mDecoderBuf = malloc(memRequirements);
CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf), status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
MP4AUDEC_SUCCESS); if (err != MP4AUDEC_SUCCESS) {
LOGE("Failed to initialize MP4 audio decoder");
return UNKNOWN_ERROR;
}
uint32_t type; uint32_t type;
const void *data; const void *data;
@@ -83,18 +94,29 @@ status_t AACDecoder::start(MetaData *params) {
mConfig->pInputBuffer = (UChar *)codec_specific_data; mConfig->pInputBuffer = (UChar *)codec_specific_data;
mConfig->inputBufferCurrentLength = codec_specific_data_size; mConfig->inputBufferCurrentLength = codec_specific_data_size;
mConfig->inputBufferMaxLength = 0; mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
mConfig->remainderBits = 0;
mConfig->pOutputBuffer = NULL;
mConfig->pOutputBuffer_plus = NULL;
mConfig->repositionFlag = false;
if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf) if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
!= MP4AUDEC_SUCCESS) { != MP4AUDEC_SUCCESS) {
return ERROR_UNSUPPORTED; return ERROR_UNSUPPORTED;
} }
} }
return OK;
}
AACDecoder::~AACDecoder() {
if (mStarted) {
stop();
}
delete mConfig;
mConfig = NULL;
}
status_t AACDecoder::start(MetaData *params) {
CHECK(!mStarted);
mBufferGroup = new MediaBufferGroup;
mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
mSource->start(); mSource->start();
@@ -127,28 +149,7 @@ status_t AACDecoder::stop() {
} }
sp<MetaData> AACDecoder::getFormat() { sp<MetaData> AACDecoder::getFormat() {
sp<MetaData> srcFormat = mSource->getFormat(); return mMeta;
int32_t sampleRate;
CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
// We'll always output stereo, regardless of how many channels are
// present in the input due to decoder limitations.
meta->setInt32(kKeyChannelCount, 2);
meta->setInt32(kKeySampleRate, sampleRate);
int64_t durationUs;
if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
meta->setInt64(kKeyDuration, durationUs);
}
meta->setCString(kKeyDecoderComponent, "AACDecoder");
return meta;
} }
status_t AACDecoder::read( status_t AACDecoder::read(
@@ -200,13 +201,32 @@ status_t AACDecoder::read(
mConfig->remainderBits = 0; mConfig->remainderBits = 0;
mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data()); mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
mConfig->pOutputBuffer_plus = NULL; mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
mConfig->repositionFlag = false; mConfig->repositionFlag = false;
Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf); Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
// Check on the sampling rate to see whether it is changed.
int32_t sampleRate;
CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
if (mConfig->samplingRate != sampleRate) {
mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
LOGW("Sample rate was %d, but now is %d",
sampleRate, mConfig->samplingRate);
buffer->release();
mInputBuffer->release();
mInputBuffer = NULL;
return INFO_FORMAT_CHANGED;
}
size_t numOutBytes = size_t numOutBytes =
mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels; mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
if (mConfig->aacPlusUpsamplingFactor == 2) {
if (mConfig->desiredChannels == 1) {
memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
}
numOutBytes *= 2;
}
if (decoderErr != MP4AUDEC_SUCCESS) { if (decoderErr != MP4AUDEC_SUCCESS) {
LOGW("AAC decoder returned error %d, substituting silence", decoderErr); LOGW("AAC decoder returned error %d, substituting silence", decoderErr);

View File

@@ -25,6 +25,7 @@ struct tPVMP4AudioDecoderExternal;
namespace android { namespace android {
struct MediaBufferGroup; struct MediaBufferGroup;
struct MetaData;
struct AACDecoder : public MediaSource { struct AACDecoder : public MediaSource {
AACDecoder(const sp<MediaSource> &source); AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@ protected:
virtual ~AACDecoder(); virtual ~AACDecoder();
private: private:
sp<MetaData> mMeta;
sp<MediaSource> mSource; sp<MediaSource> mSource;
bool mStarted; bool mStarted;
@@ -50,9 +52,11 @@ private:
void *mDecoderBuf; void *mDecoderBuf;
int64_t mAnchorTimeUs; int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput; int64_t mNumSamplesOutput;
status_t mInitCheck;
MediaBuffer *mInputBuffer; MediaBuffer *mInputBuffer;
status_t initCheck();
AACDecoder(const AACDecoder &); AACDecoder(const AACDecoder &);
AACDecoder &operator=(const AACDecoder &); AACDecoder &operator=(const AACDecoder &);
}; };