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
This commit is contained in:
@@ -86,6 +86,10 @@ private:
|
||||
|
||||
bool mStarted;
|
||||
|
||||
bool mIsFirstBuffer;
|
||||
status_t mFirstBufferResult;
|
||||
MediaBuffer *mFirstBuffer;
|
||||
|
||||
sp<MediaPlayerBase::AudioSink> mAudioSink;
|
||||
|
||||
static void AudioCallback(int event, void *user, void *info);
|
||||
|
||||
@@ -41,6 +41,9 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
|
||||
mReachedEOS(false),
|
||||
mFinalStatus(OK),
|
||||
mStarted(false),
|
||||
mIsFirstBuffer(false),
|
||||
mFirstBufferResult(OK),
|
||||
mFirstBuffer(NULL),
|
||||
mAudioSink(audioSink) {
|
||||
}
|
||||
|
||||
@@ -68,6 +71,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();
|
||||
const char *mime;
|
||||
bool success = format->findCString(kKeyMIMEType, &mime);
|
||||
@@ -87,6 +108,11 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
|
||||
DEFAULT_AUDIOSINK_BUFFERCOUNT,
|
||||
&AudioPlayer::AudioSinkCallback, this);
|
||||
if (err != OK) {
|
||||
if (mFirstBuffer != NULL) {
|
||||
mFirstBuffer->release();
|
||||
mFirstBuffer = NULL;
|
||||
}
|
||||
|
||||
if (!sourceAlreadyStarted) {
|
||||
mSource->stop();
|
||||
}
|
||||
@@ -110,6 +136,11 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
|
||||
delete mAudioTrack;
|
||||
mAudioTrack = NULL;
|
||||
|
||||
if (mFirstBuffer != NULL) {
|
||||
mFirstBuffer->release();
|
||||
mFirstBuffer = NULL;
|
||||
}
|
||||
|
||||
if (!sourceAlreadyStarted) {
|
||||
mSource->stop();
|
||||
}
|
||||
@@ -163,6 +194,12 @@ void AudioPlayer::stop() {
|
||||
|
||||
// Make sure to release any buffer we hold onto so that the
|
||||
// source is able to stop().
|
||||
|
||||
if (mFirstBuffer != NULL) {
|
||||
mFirstBuffer->release();
|
||||
mFirstBuffer = NULL;
|
||||
}
|
||||
|
||||
if (mInputBuffer != NULL) {
|
||||
LOGV("AudioPlayer releasing input buffer.");
|
||||
|
||||
@@ -247,6 +284,14 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mSeeking) {
|
||||
if (mIsFirstBuffer) {
|
||||
if (mFirstBuffer != NULL) {
|
||||
mFirstBuffer->release();
|
||||
mFirstBuffer = NULL;
|
||||
}
|
||||
mIsFirstBuffer = false;
|
||||
}
|
||||
|
||||
options.setSeekTo(mSeekTimeUs);
|
||||
|
||||
if (mInputBuffer != NULL) {
|
||||
@@ -259,7 +304,17 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
|
||||
}
|
||||
|
||||
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)
|
||||
|| (err != OK && mInputBuffer == NULL));
|
||||
|
||||
@@ -1287,11 +1287,6 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
|
||||
uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
|
||||
int32_t sampleRate = 0;
|
||||
int32_t numChannels = 0;
|
||||
uint8_t offset = 0;
|
||||
static uint32_t kSamplingRate[] = {
|
||||
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
||||
16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
if (freqIndex == 15) {
|
||||
if (csd_size < 5) {
|
||||
return ERROR_MALFORMED;
|
||||
@@ -1303,8 +1298,11 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
|
||||
| (csd[4] >> 7);
|
||||
|
||||
numChannels = (csd[4] >> 3) & 15;
|
||||
offset = 4;
|
||||
} else {
|
||||
static uint32_t kSamplingRate[] = {
|
||||
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
||||
16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
|
||||
if (freqIndex == 13 || freqIndex == 14) {
|
||||
return ERROR_MALFORMED;
|
||||
@@ -1312,66 +1310,6 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
|
||||
|
||||
sampleRate = kSamplingRate[freqIndex];
|
||||
numChannels = (csd[1] >> 3) & 15;
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
uint8_t sbrPresentFlag = -1;
|
||||
uint8_t extensionAudioObjectType = 0;
|
||||
if (objectType == 5) {
|
||||
extensionAudioObjectType = objectType;
|
||||
sbrPresentFlag = 1;
|
||||
freqIndex = ((csd[offset] & 7) << 1) | (csd[offset + 1] >> 7);
|
||||
offset += 1;
|
||||
if (freqIndex == 15) {
|
||||
sampleRate = (((csd[offset] & 0x7f) << 17)
|
||||
| (csd[offset + 1] << 9)
|
||||
| (csd[offset + 2] << 1)
|
||||
| (csd[offset + 3] >> 7));
|
||||
offset += 3;
|
||||
}
|
||||
objectType = csd[offset] >> 3;
|
||||
}
|
||||
|
||||
if (((objectType >= 1 && objectType <= 4) ||
|
||||
(objectType >= 6 && objectType <= 7) ||
|
||||
(objectType == 17) ||
|
||||
(objectType >= 19 || objectType <= 23)) &&
|
||||
(0x00 == (csd[offset] & 7)) &&
|
||||
numChannels != 0) {
|
||||
|
||||
// XXX: We are not handling coreCoderDelay,
|
||||
// program_config_element(),
|
||||
// extensionFlag, scalable profile, etc.
|
||||
if (objectType != 6 && objectType != 20) {
|
||||
if (objectType != 5 && csd_size - offset >= 2) {
|
||||
uint32_t syncExtensionType =
|
||||
(csd[offset + 1] << 3) | (csd[offset + 2] >> 5);
|
||||
if (syncExtensionType == 0x2b7) {
|
||||
extensionAudioObjectType =
|
||||
csd[offset + 2] & 0x1F;
|
||||
if (extensionAudioObjectType == 0x05) {
|
||||
if (csd_size - offset < 3) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
uint8_t sbrPresentFlag = csd[offset + 3] & 0x80;
|
||||
if (sbrPresentFlag) {
|
||||
freqIndex = (csd[offset + 3] & 0x78) >> 3;
|
||||
if (freqIndex == 15) {
|
||||
if (csd_size - offset < 6) {
|
||||
return ERROR_MALFORMED;
|
||||
}
|
||||
sampleRate = (csd[offset + 3] & 0x07) << 21
|
||||
| csd[offset + 4] << 13
|
||||
| csd[offset + 5] << 5
|
||||
| csd[offset + 6] >> 3;
|
||||
} else {
|
||||
sampleRate = kSamplingRate[freqIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numChannels == 0) {
|
||||
|
||||
Reference in New Issue
Block a user