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:
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 &);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user