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
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 9af5871..9a09586 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -86,6 +86,10 @@
 
     bool mStarted;
 
+    bool mIsFirstBuffer;
+    status_t mFirstBufferResult;
+    MediaBuffer *mFirstBuffer;
+
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
     static void AudioCallback(int event, void *user, void *info);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index b79ba13..b7bde6b 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -41,6 +41,9 @@
       mReachedEOS(false),
       mFinalStatus(OK),
       mStarted(false),
+      mIsFirstBuffer(false),
+      mFirstBufferResult(OK),
+      mFirstBuffer(NULL),
       mAudioSink(audioSink) {
 }
 
@@ -68,6 +71,24 @@
         }
     }
 
+    // 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 @@
                 DEFAULT_AUDIOSINK_BUFFERCOUNT,
                 &AudioPlayer::AudioSinkCallback, this);
         if (err != OK) {
+            if (mFirstBuffer != NULL) {
+                mFirstBuffer->release();
+                mFirstBuffer = NULL;
+            }
+
             if (!sourceAlreadyStarted) {
                 mSource->stop();
             }
@@ -110,6 +136,11 @@
             delete mAudioTrack;
             mAudioTrack = NULL;
 
+            if (mFirstBuffer != NULL) {
+                mFirstBuffer->release();
+                mFirstBuffer = NULL;
+            }
+
             if (!sourceAlreadyStarted) {
                 mSource->stop();
             }
@@ -163,6 +194,12 @@
 
     // 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 @@
             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 @@
         }
 
         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));
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 65d0146..0c2f1e6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1287,11 +1287,6 @@
     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 @@
                         | (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 @@
 
         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) {