OSDN Git Service

Merge "AAC buffer decode to PCM buffer queue"
authorJean-Michel Trivi <jmtrivi@google.com>
Sun, 14 Aug 2011 21:24:43 +0000 (14:24 -0700)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Sun, 14 Aug 2011 21:24:43 +0000 (14:24 -0700)
17 files changed:
wilhelm/src/Android.mk
wilhelm/src/android/AacBqToPcmCbRenderer.cpp [new file with mode: 0644]
wilhelm/src/android/AudioPlayer_to_android.cpp
wilhelm/src/android/AudioPlayer_to_android.h
wilhelm/src/android/BufferQueueSource.cpp [new file with mode: 0644]
wilhelm/src/android/BufferQueueSource.h [new file with mode: 0644]
wilhelm/src/android/android_AudioSfDecoder.cpp
wilhelm/src/android/android_AudioSfDecoder.h
wilhelm/src/android/android_AudioToCbRenderer.h
wilhelm/src/android/android_defs.h
wilhelm/src/android/include/AacAdtsExtractor.h [new file with mode: 0644]
wilhelm/src/android/include/AacBqToPcmCbRenderer.h [new file with mode: 0644]
wilhelm/src/android/util/AacAdtsExtractor.cpp [new file with mode: 0644]
wilhelm/src/data.c
wilhelm/src/itf/IAndroidBufferQueue.c
wilhelm/src/itf/IEngine.c
wilhelm/src/sles_allinclusive.h

index de848e6..8b42b35 100644 (file)
@@ -66,7 +66,9 @@ LOCAL_SRC_FILES:=                     \
         android/MediaPlayer_to_android.cpp    \
         android/OutputMix_to_android.cpp      \
         android/VideoCodec_to_android.cpp     \
+        android/BufferQueueSource.cpp         \
         android/CallbackProtector.cpp         \
+        android/AacBqToPcmCbRenderer.cpp      \
         android/android_AudioSfDecoder.cpp    \
         android/android_AudioToCbRenderer.cpp \
         android/android_GenericMediaPlayer.cpp\
@@ -74,6 +76,7 @@ LOCAL_SRC_FILES:=                     \
         android/android_LocAVPlayer.cpp       \
         android/android_StreamPlayer.cpp      \
         android/android_Effect.cpp            \
+        android/util/AacAdtsExtractor.cpp     \
         autogen/IID_to_MPH.c                  \
         objects/C3DGroup.c                    \
         objects/CAudioPlayer.c                \
diff --git a/wilhelm/src/android/AacBqToPcmCbRenderer.cpp b/wilhelm/src/android/AacBqToPcmCbRenderer.cpp
new file mode 100644 (file)
index 0000000..30a1ded
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define USE_LOG SLAndroidLogLevel_Debug
+
+#include "sles_allinclusive.h"
+#include "android/include/AacBqToPcmCbRenderer.h"
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+// ADTS header size is 7, but frame size information ends on byte 6 (when counting from byte 1)
+#define ADTS_HEADER_SIZE_UP_TO_FRAMESIZE 6
+
+/**
+ * Returns the size of an AAC ADTS frame.
+ * Note that if the returned value + offset > size, it means that a partial frame starts at that
+ *   offset, but this function will still return the size of the full frame.
+ * @param data pointer to the compressed audio data
+ * @param offset offset in bytes relative to data of where the frame is supposed to start
+ * @param size the size in bytes of the data block starting at data
+ * @return the size in bytes of the AAC ADTS frame starting at the given offset of the given
+ *    memory address, 0 if the frame couldn't be parsed.
+ */
+static size_t getAdtsFrameSize(const uint8_t *data, off64_t offset, size_t size) {
+    size_t frameSize = 0;
+
+    if (!(offset + ADTS_HEADER_SIZE_UP_TO_FRAMESIZE < size)) {
+        SL_LOGE("AacBqToPcmCbRenderer::getAdtsFrameSize() returns 0 (can't read syncword or header)"
+                );
+        return 0;
+    }
+
+    const uint8_t *syncword = data + offset;
+    if ((syncword[0] != 0xff) || ((syncword[1] & 0xf6) != 0xf0)) {
+        SL_LOGE("AacBqToPcmCbRenderer::getAdtsFrameSize() returns 0 (wrong syncword)");
+        return 0;
+    }
+
+    const uint8_t protectionAbsent = data[offset+1] & 0x1;
+
+    const uint8_t* header = data + offset + 3;
+    frameSize = (header[0] & 0x3) << 11 | header[1] << 3 | header[2] >> 5;
+    // the frame size read already contains the size of the header, so no need to add it here
+    frameSize += protectionAbsent ? 0 : 2;
+
+    SL_LOGV("AacBqToPcmCbRenderer::getAdtsFrameSize() returns %u", frameSize);
+
+    return frameSize;
+}
+
+/**
+ * Returns whether a block of memory starts and ends on AAC ADTS frame boundaries
+ * @param data pointer to the compressed audio data
+ * @param size the size in bytes of the data block to validate
+ * @return true if there is AAC ADTS data, and it starts and ends on frame boundaries,
+ *    false otherwise
+ */
+bool AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(void* data, size_t size)
+{
+    off64_t offset = 0;
+    size_t frameSize = 0;
+
+    if ((NULL == data) || (size == 0)) {
+        SL_LOGE("No ADTS to validate");
+        return false;
+    }
+
+    while (offset < size) {
+        if ((frameSize = getAdtsFrameSize((uint8_t *)data, offset, size)) == 0) {
+            SL_LOGE("found ADTS frame of size 0 at offset %llu", offset);
+            return false;
+        }
+        //SL_LOGV("last good offset %llu", offset);
+        offset += frameSize;
+        if (offset > size) {
+            SL_LOGE("found incomplete ADTS frame at end of data");
+            return false;
+        }
+    }
+    if (offset != size) { SL_LOGE("ADTS parsing error: reached end of incomplete frame"); }
+    assert(offset == size);
+    return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+AacBqToPcmCbRenderer::AacBqToPcmCbRenderer(AudioPlayback_Parameters* params) :
+        AudioToCbRenderer(params),
+        mBqSource(0)
+{
+    SL_LOGD("AacBqToPcmCbRenderer::AacBqToPcmCbRenderer()");
+
+}
+
+
+AacBqToPcmCbRenderer::~AacBqToPcmCbRenderer() {
+    SL_LOGD("AacBqToPcmCbRenderer::~AacBqToPcmCbRenderer()");
+
+}
+
+
+//--------------------------------------------------
+void AacBqToPcmCbRenderer::registerSourceQueueCallback(
+        const void* user, void *context,  const void *caller) {
+    SL_LOGD("AacBqToPcmCbRenderer::registerQueueCallback");
+
+    Mutex::Autolock _l(mBqSourceLock);
+
+    mBqSource = new BufferQueueSource(user, context, caller);
+
+    CHECK(mBqSource != 0);
+    SL_LOGD("AacBqToPcmCbRenderer::registerSourceQueueCallback end");
+}
+
+
+//--------------------------------------------------
+// Event handlers
+void AacBqToPcmCbRenderer::onPrepare() {
+    SL_LOGD("AacBqToPcmCbRenderer::onPrepare()");
+    Mutex::Autolock _l(mBufferSourceLock);
+
+    // Initialize the PCM format info with the known parameters before the start of the decode
+    {
+        android::Mutex::Autolock autoLock(mPcmFormatLock);
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_BITSPERSAMPLE] = SL_PCMSAMPLEFORMAT_FIXED_16;
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_CONTAINERSIZE] = 16;
+        //FIXME not true on all platforms
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_ENDIANNESS] = SL_BYTEORDER_LITTLEENDIAN;
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_CHANNELMASK] = 0;
+        //    initialization with the default values: they will be replaced by the actual values
+        //      once the decoder has figured them out
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_NUMCHANNELS] = mChannelCount;
+        mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_SAMPLESPERSEC] = mSampleRateHz;
+    }
+
+    sp<DataSource> dataSource;
+    {
+        Mutex::Autolock _l(mBqSourceLock);
+        dataSource = mBqSource;
+    }
+    if (dataSource == 0) {
+        SL_LOGE("AacBqToPcmCbRenderer::onPrepare(): Error no data source");
+        notifyPrepared(MEDIA_ERROR_BASE);
+        return;
+    }
+
+    sp<MediaExtractor> extractor = new AacAdtsExtractor(dataSource);
+    if (extractor == 0) {
+        SL_LOGE("AacBqToPcmCbRenderer::onPrepare: Could not instantiate AAC extractor.");
+        notifyPrepared(ERROR_UNSUPPORTED);
+        return;
+    }
+
+    // only decoding a single track of data
+    const size_t kTrackToDecode = 0;
+
+    sp<MediaSource> source = extractor->getTrack(kTrackToDecode);
+    if (source == 0) {
+        SL_LOGE("AacBqToPcmCbRenderer::onPrepare: error getting source from extractor");
+        notifyPrepared(ERROR_UNSUPPORTED);
+        return;
+    }
+    sp<MetaData> meta = extractor->getTrackMetaData(kTrackToDecode);
+
+    // the audio content is not raw PCM, so we need a decoder
+    OMXClient client;
+    CHECK_EQ(client.connect(), (status_t)OK);
+
+    source = OMXCodec::Create(
+            client.interface(), meta, false /* createEncoder */,
+            source);
+
+    if (source == NULL) {
+        SL_LOGE("AudioSfDecoder::onPrepare: Could not instantiate decoder.");
+        notifyPrepared(ERROR_UNSUPPORTED);
+        return;
+    }
+
+    meta = source->getFormat();
+
+    SL_LOGD("AacBqToPcmCbRenderer::onPrepare() after instantiating decoder");
+
+    if (source->start() != OK) {
+        SL_LOGE("AacBqToPcmCbRenderer::onPrepare() Failed to start source/decoder.");
+        notifyPrepared(MEDIA_ERROR_BASE);
+        return;
+    }
+
+    //---------------------------------
+    CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
+    int32_t sr;
+    CHECK(meta->findInt32(kKeySampleRate, &sr));
+    mSampleRateHz = (uint32_t) sr;
+    {
+            android::Mutex::Autolock autoLock(mPcmFormatLock);
+            mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_SAMPLESPERSEC] = mSampleRateHz;
+            mPcmFormatValues[ANDROID_KEY_INDEX_PCMFORMAT_NUMCHANNELS] = mChannelCount;
+    }
+    SL_LOGV("AacBqToPcmCbRenderer::onPrepare() channel count=%d SR=%d",
+            mChannelCount, mSampleRateHz);
+
+    //---------------------------------
+    // The data source, and audio source (a decoder) are ready to be used
+    mDataSource = dataSource;
+    mAudioSource = source;
+    mAudioSourceStarted = true;
+
+    //-------------------------------------
+    // signal successful completion of prepare
+    mStateFlags |= kFlagPrepared;
+
+    GenericPlayer::onPrepare();
+
+    SL_LOGD("AacBqToPcmCbRenderer::onPrepare() done, mStateFlags=0x%x", mStateFlags);
+}
+
+} // namespace android
index 2ee872e..859a624 100644 (file)
@@ -19,6 +19,7 @@
 #include "android/android_AudioToCbRenderer.h"
 #include "android/android_StreamPlayer.h"
 #include "android/android_LocAVPlayer.h"
+#include "android/include/AacBqToPcmCbRenderer.h"
 
 #include <system/audio.h>
 
@@ -633,6 +634,7 @@ AndroidObjectType audioPlayer_getAndroidObjectTypeForSourceSink(CAudioPlayer *ap
     //     SL_DATALOCATOR_URI                        / SL_DATALOCATOR_OUTPUTMIX
     //     SL_DATALOCATOR_ANDROIDFD                  / SL_DATALOCATOR_OUTPUTMIX
     //     SL_DATALOCATOR_ANDROIDBUFFERQUEUE         / SL_DATALOCATOR_OUTPUTMIX
+    //     SL_DATALOCATOR_ANDROIDBUFFERQUEUE         / SL_DATALOCATOR_BUFFERQUEUE
     //     SL_DATALOCATOR_URI                        / SL_DATALOCATOR_BUFFERQUEUE
     //     SL_DATALOCATOR_ANDROIDFD                  / SL_DATALOCATOR_BUFFERQUEUE
     //     SL_DATALOCATOR_URI                        / SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
@@ -677,6 +679,11 @@ AndroidObjectType audioPlayer_getAndroidObjectTypeForSourceSink(CAudioPlayer *ap
             type = AUDIOPLAYER_FROM_URIFD_TO_PCM_BUFFERQUEUE;
             break;
 
+        //   AAC ADTS Android buffer queue decoded to PCM in a buffer queue
+        case SL_DATALOCATOR_ANDROIDBUFFERQUEUE:
+            type = AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE;
+            break;
+
         default:
             SL_LOGE("Source data locator 0x%x not supported with SL_DATALOCATOR_BUFFERQUEUE sink",
                     (unsigned)sourceLocatorType);
@@ -1076,9 +1083,33 @@ SLresult android_audioPlayer_checkSourceSink(CAudioPlayer *pAudioPlayer)
         case SL_DATAFORMAT_MIME:
         {
             SLDataFormat_MIME *df_mime = (SLDataFormat_MIME *) pAudioSrc->pFormat;
-            if (SL_CONTAINERTYPE_MPEG_TS != df_mime->containerType) {
+            if (NULL == df_mime) {
+                SL_LOGE("MIME type null invalid");
+                return SL_RESULT_CONTENT_UNSUPPORTED;
+            }
+            SL_LOGD("source MIME is %s", (char*)df_mime->mimeType);
+            switch(df_mime->containerType) {
+            case SL_CONTAINERTYPE_MPEG_TS:
+                if (strcasecmp((char*)df_mime->mimeType, ANDROID_MIME_MP2TS)) {
+                    SL_LOGE("Invalid MIME (%s) for container SL_CONTAINERTYPE_MPEG_TS, expects %s",
+                            (char*)df_mime->mimeType, ANDROID_MIME_MP2TS);
+                    return SL_RESULT_CONTENT_UNSUPPORTED;
+                }
+                break;
+            case SL_CONTAINERTYPE_RAW:
+            case SL_CONTAINERTYPE_AAC:
+                if (strcasecmp((char*)df_mime->mimeType, ANDROID_MIME_AACADTS) &&
+                        strcasecmp((char*)df_mime->mimeType,
+                                ANDROID_MIME_AACADTS_ANDROID_FRAMEWORK)) {
+                    SL_LOGE("Invalid MIME (%s) for container type %d, expects %s",
+                            (char*)df_mime->mimeType, df_mime->containerType,
+                            ANDROID_MIME_AACADTS);
+                    return SL_RESULT_CONTENT_UNSUPPORTED;
+                }
+                break;
+            default:
                 SL_LOGE("Cannot create player with SL_DATALOCATOR_ANDROIDBUFFERQUEUE data source "
-                        "that is not fed MPEG-2 TS data");
+                                        "that is not fed MPEG-2 TS data or AAC ADTS data");
                 return SL_RESULT_CONTENT_UNSUPPORTED;
             }
         }
@@ -1485,7 +1516,9 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async
 
         android::AudioToCbRenderer* decoder = new android::AudioToCbRenderer(&app);
         pAudioPlayer->mAPlayer = decoder;
+        // configures the callback for the sink buffer queue
         decoder->setDataPushListener(adecoder_writeToBufferQueue, (void*)pAudioPlayer);
+        // configures the callback for the notifications coming from the SF code
         decoder->init(sfplayer_handlePrefetchEvent, (void*)pAudioPlayer);
 
         switch (pAudioPlayer->mDataSource.mLocator.mLocatorType) {
@@ -1511,6 +1544,27 @@ SLresult android_audioPlayer_realize(CAudioPlayer *pAudioPlayer, SLboolean async
         }
         break;
     //-----------------------------------
+    // AacBqToPcmCbRenderer
+    case AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE: {
+        object_lock_exclusive(&pAudioPlayer->mObject);
+
+        AudioPlayback_Parameters app;
+        app.sessionId = pAudioPlayer->mSessionId;
+        app.streamType = pAudioPlayer->mStreamType;
+        app.trackcb = NULL;
+        app.trackcbUser = NULL;
+        android::AacBqToPcmCbRenderer* bqtobq = new android::AacBqToPcmCbRenderer(&app);
+        // configures the callback for the sink buffer queue
+        bqtobq->setDataPushListener(adecoder_writeToBufferQueue, (void*)pAudioPlayer);
+        pAudioPlayer->mAPlayer = bqtobq;
+        // configures the callback for the notifications coming from the SF code,
+        // but also implicitly configures the AndroidBufferQueue from which ADTS data is read
+        pAudioPlayer->mAPlayer->init(sfplayer_handlePrefetchEvent, (void*)pAudioPlayer);
+
+        object_unlock_exclusive(&pAudioPlayer->mObject);
+        }
+        break;
+    //-----------------------------------
     default:
         SL_LOGE(ERROR_PLAYERREALIZE_UNEXPECTED_OBJECT_TYPE_D, pAudioPlayer->mAndroidObjType);
         result = SL_RESULT_INTERNAL_ERROR;
@@ -1586,7 +1640,8 @@ SLresult android_audioPlayer_destroy(CAudioPlayer *pAudioPlayer) {
 
     case AUDIOPLAYER_FROM_URIFD:     // intended fall-through
     case AUDIOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE:    // intended fall-through
-    case AUDIOPLAYER_FROM_URIFD_TO_PCM_BUFFERQUEUE:
+    case AUDIOPLAYER_FROM_URIFD_TO_PCM_BUFFERQUEUE: // intended fall-through
+    case AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE:
         pAudioPlayer->mAPlayer.clear();
         break;
     //-----------------------------------
@@ -1857,7 +1912,8 @@ void android_audioPlayer_setPlayState(CAudioPlayer *ap) {
 
     case AUDIOPLAYER_FROM_URIFD:      // intended fall-through
     case AUDIOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE:     // intended fall-through
-    case AUDIOPLAYER_FROM_URIFD_TO_PCM_BUFFERQUEUE:
+    case AUDIOPLAYER_FROM_URIFD_TO_PCM_BUFFERQUEUE:  // intended fall-through
+    case AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE:
         // FIXME report and use the return code to the lock mechanism, which is where play state
         //   changes are updated (see object_unlock_exclusive_attributes())
         aplayer_setPlayState(ap->mAPlayer, playState, &(ap->mAndroidObjState));
@@ -2073,14 +2129,31 @@ SLresult android_audioPlayer_bufferQueue_onClear(CAudioPlayer *ap) {
 
 
 //-----------------------------------------------------------------------------
-void android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *ap) {
-    if ((ap->mAndroidObjType == AUDIOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE) && (ap->mAPlayer != 0)) {
-        android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(ap->mAPlayer.get());
-        splr->registerQueueCallback(
-                (const void*)ap, true /*userIsAudioPlayer*/,
-                ap->mAndroidBufferQueue.mContext,
-                (const void*)&(ap->mAndroidBufferQueue.mItf));
+SLresult android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *ap) {
+    SLresult result = SL_RESULT_SUCCESS;
+    assert(ap->mAPlayer != 0);
+    switch (ap->mAndroidObjType) {
+      case AUDIOPLAYER_FROM_TS_ANDROIDBUFFERQUEUE: {
+          android::StreamPlayer* splr = static_cast<android::StreamPlayer*>(ap->mAPlayer.get());
+          splr->registerQueueCallback(
+                  (const void*)ap /*user*/, true /*userIsAudioPlayer*/,
+                  ap->mAndroidBufferQueue.mContext /*context*/,
+                  (const void*)&(ap->mAndroidBufferQueue.mItf) /*caller*/);
+        } break;
+      case AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE: {
+          android::AacBqToPcmCbRenderer* dec =
+                  static_cast<android::AacBqToPcmCbRenderer*>(ap->mAPlayer.get());
+          dec->registerSourceQueueCallback((const void*)ap /*user*/,
+                  ap->mAndroidBufferQueue.mContext /*context*/,
+                  (const void*)&(ap->mAndroidBufferQueue.mItf) /*caller*/);
+        } break;
+      default:
+        SL_LOGE("Error registering AndroidBufferQueue callback: unexpected object type %d",
+                ap->mAndroidObjType);
+        result = SL_RESULT_INTERNAL_ERROR;
+        break;
     }
+    return result;
 }
 
 //-----------------------------------------------------------------------------
index bdf8be4..a9f00a3 100644 (file)
@@ -138,7 +138,8 @@ extern SLresult android_audioPlayer_bufferQueue_onClear(CAudioPlayer *pAudioPlay
  * Android Buffer Queue
  ****************************/
 /* must be called with a lock on pAudioPlayer->mThis */
-extern void android_audioPlayer_androidBufferQueue_registerCallback_l(CAudioPlayer *pAudioPlayer);
+extern SLresult android_audioPlayer_androidBufferQueue_registerCallback_l(
+        CAudioPlayer *pAudioPlayer);
 /* must be called with a lock on pAudioPlayer->mThis */
 extern void android_audioPlayer_androidBufferQueue_clear_l(CAudioPlayer *pAudioPlayer);
 /* must be called with a lock on pAudioPlayer->mThis */
diff --git a/wilhelm/src/android/BufferQueueSource.cpp b/wilhelm/src/android/BufferQueueSource.cpp
new file mode 100644 (file)
index 0000000..0adf1ee
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define USE_LOG SLAndroidLogLevel_Verbose
+
+#include "sles_allinclusive.h"
+#include "android/BufferQueueSource.h"
+
+#include <media/stagefright/MediaDebug.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+
+const SLuint32 BufferQueueSource::kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS] = {
+        SL_ANDROID_ITEMKEY_BUFFERQUEUEEVENT, // item key
+        sizeof(SLuint32),                    // item size
+        SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED // item data
+};
+
+
+BufferQueueSource::BufferQueueSource(const void* user, void *context,  const void *caller) :
+          mAndroidBufferQueueSource(NULL),
+          mStreamToBqOffset(0)
+{
+    if (NULL != user) {
+        mAndroidBufferQueueSource = &((CAudioPlayer*)user)->mAndroidBufferQueue;
+    } else {
+        SL_LOGE("Can't create BufferQueueSource with NULL user");
+    }
+
+}
+
+
+BufferQueueSource::~BufferQueueSource() {
+    SL_LOGD("BufferQueueSource::~BufferQueueSource");
+}
+
+
+//--------------------------------------------------------------------------
+status_t BufferQueueSource::initCheck() const {
+    return mAndroidBufferQueueSource != NULL ? OK : NO_INIT;
+}
+
+ssize_t BufferQueueSource::readAt(off64_t offset, void *data, size_t size) {
+    SL_LOGD("BufferQueueSource::readAt(offset=%lld, data=%p, size=%d)", offset, data, size);
+
+    ssize_t readSize = 0;
+    slAndroidBufferQueueCallback callback = NULL;
+    void* pBufferContext, *pBufferData, *callbackPContext = NULL;
+    AdvancedBufferHeader *oldFront = NULL;
+    uint32_t dataSize, dataUsed = 0;
+
+    interface_lock_exclusive(mAndroidBufferQueueSource);
+
+    if (mAndroidBufferQueueSource->mState.count == 0) {
+        readSize = 0;
+    } else {
+        assert(mAndroidBufferQueueSource->mFront != mAndroidBufferQueueSource->mRear);
+
+        oldFront = mAndroidBufferQueueSource->mFront;
+        AdvancedBufferHeader *newFront = &oldFront[1];
+
+        // consume events when starting to read data from a buffer for the first time
+        if (oldFront->mDataSizeConsumed == 0) {
+            if (oldFront->mItems.mAdtsCmdData.mAdtsCmdCode & ANDROID_ADTSEVENT_EOS) {
+                // FIXME handle EOS
+                SL_LOGE("---> FIXME: handle ANDROID_ADTSEVENT_EOS <---");
+            }
+            oldFront->mItems.mAdtsCmdData.mAdtsCmdCode = ANDROID_ADTSEVENT_NONE;
+        }
+
+        // where to read from
+        char *pSrc = NULL;
+        // can this read operation cause us to call the buffer queue callback
+        bool queueCallbackCandidate = false;
+
+        //assert(mStreamToBqOffset <= offset);
+        CHECK(mStreamToBqOffset <= offset);
+
+        if (offset + size <= mStreamToBqOffset + oldFront->mDataSize) {
+            pSrc = ((char*)oldFront->mDataBuffer) + (offset - mStreamToBqOffset);
+
+            if (offset - mStreamToBqOffset + size == oldFront->mDataSize) {
+                // consumed buffer entirely
+                oldFront->mDataSizeConsumed = oldFront->mDataSize;
+                mStreamToBqOffset += oldFront->mDataSize;
+                queueCallbackCandidate = true;
+
+                // move queue to next buffer
+                if (newFront == &mAndroidBufferQueueSource->
+                        mBufferArray[mAndroidBufferQueueSource->mNumBuffers + 1]) {
+                    // reached the end, circle back
+                    newFront = mAndroidBufferQueueSource->mBufferArray;
+                }
+                mAndroidBufferQueueSource->mFront = newFront;
+                // update the queue state
+                mAndroidBufferQueueSource->mState.count--;
+                mAndroidBufferQueueSource->mState.index++;
+                SL_LOGV("BufferQueueSource moving to next buffer");
+            }
+        }
+
+        // consume data: copy to given destination
+        if (NULL != pSrc) {
+            memcpy(data, pSrc, size);
+            readSize = size;
+        } else {
+            readSize = 0;
+        }
+
+        if (queueCallbackCandidate) {
+            // data has been consumed, and the buffer queue state has been updated
+            // we will notify the client if applicable
+            if (mAndroidBufferQueueSource->mCallbackEventsMask &
+                    SL_ANDROIDBUFFERQUEUEEVENT_PROCESSED) {
+                callback = mAndroidBufferQueueSource->mCallback;
+                // save callback data while under lock
+                callbackPContext = mAndroidBufferQueueSource->mContext;
+                pBufferContext = (void *)oldFront->mBufferContext;
+                pBufferData    = (void *)oldFront->mDataBuffer;
+                dataSize       = oldFront->mDataSize;
+                dataUsed       = oldFront->mDataSizeConsumed;
+            }
+        }
+    }
+
+    interface_unlock_exclusive(mAndroidBufferQueueSource);
+
+    // notify client
+    if (NULL != callback) {
+        (*callback)(&mAndroidBufferQueueSource->mItf, callbackPContext,
+                pBufferContext, pBufferData, dataSize, dataUsed,
+                // no messages during playback other than marking the buffer as processed
+                (const SLAndroidBufferItem*)(&kItemProcessed) /* pItems */,
+                NB_BUFFEREVENT_ITEM_FIELDS * sizeof(SLuint32) /* itemsLength */ );
+    }
+
+    return readSize;
+}
+
+
+status_t BufferQueueSource::getSize(off64_t *size) {
+    SL_LOGD("BufferQueueSource::getSize()");
+    // we're streaming, we don't know how much there is
+    *size = 0;
+    return OK;
+}
+
+}  // namespace android
diff --git a/wilhelm/src/android/BufferQueueSource.h b/wilhelm/src/android/BufferQueueSource.h
new file mode 100644 (file)
index 0000000..61ec27b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BUFFERQUEUE_SOURCE_H_
+#define BUFFERQUEUE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+#include "include/AacAdtsExtractor.h"
+
+// number of SLuint32 fields to store a buffer event message in an item, by mapping each
+//   to the item key (SLuint32), the item size (SLuint32), and the item data (mask on SLuint32)
+#define NB_BUFFEREVENT_ITEM_FIELDS 3
+
+namespace android {
+
+// a Stagefright DataSource that pulls data from an AndroidBufferQueue
+
+class BufferQueueSource : public DataSource {
+public:
+
+    // store an item structure to indicate a processed buffer
+    static const SLuint32 kItemProcessed[NB_BUFFEREVENT_ITEM_FIELDS];
+
+    BufferQueueSource(const void* user, void *context,  const void *caller);
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual ~BufferQueueSource();
+
+private:
+    // the Android Buffer Queue from which data is consumed
+    IAndroidBufferQueue* mAndroidBufferQueueSource;
+
+    // a monotonically increasing offset used to translate an offset from the beginning
+    // of the stream, to an offset in each buffer from the buffer queue source
+    off64_t mStreamToBqOffset;
+
+    BufferQueueSource(const BufferQueueSource &);
+    BufferQueueSource &operator=(const BufferQueueSource &);
+};
+
+}  // namespace android
+
+#endif  // BUFFERQUEUE_SOURCE_H_
+
index dcba3df..4168b1b 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-//#define USE_LOG SLAndroidLogLevel_Debug
+//#define USE_LOG SLAndroidLogLevel_Verbose
 
 #include "sles_allinclusive.h"
 #include "android/android_AudioSfDecoder.h"
 
 namespace android {
 
-// keep in sync with the entries of kPcmDecodeMetadataKeys[] defined in android_AudioSfDecoder.h
-#define ANDROID_KEY_INDEX_PCMFORMAT_NUMCHANNELS   0
-#define ANDROID_KEY_INDEX_PCMFORMAT_SAMPLESPERSEC 1
-#define ANDROID_KEY_INDEX_PCMFORMAT_BITSPERSAMPLE 2
-#define ANDROID_KEY_INDEX_PCMFORMAT_CONTAINERSIZE 3
-#define ANDROID_KEY_INDEX_PCMFORMAT_CHANNELMASK   4
-#define ANDROID_KEY_INDEX_PCMFORMAT_ENDIANNESS    5
-
 //--------------------------------------------------------------------------------------------------
 AudioSfDecoder::AudioSfDecoder(const AudioPlayback_Parameters* params) : GenericPlayer(params),
         mDataSource(0),
@@ -361,6 +353,7 @@ void AudioSfDecoder::onPrepare() {
 
     // signal successful completion of prepare
     mStateFlags |= kFlagPrepared;
+
     GenericPlayer::onPrepare();
     SL_LOGD("AudioSfDecoder::onPrepare() done, mStateFlags=0x%x", mStateFlags);
 }
@@ -786,13 +779,14 @@ void AudioSfDecoder::hasNewDecodeParams() {
     if ((mAudioSource != 0) && mAudioSourceStarted) {
         sp<MetaData> meta = mAudioSource->getFormat();
 
-        CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
+        SL_LOGV("old sample rate = %d, channel count = %d", mSampleRateHz, mChannelCount);
 
-        SL_LOGV("old sample rate = %d", mSampleRateHz);
+        CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
         int32_t sr;
         CHECK(meta->findInt32(kKeySampleRate, &sr));
         mSampleRateHz = (uint32_t) sr;
-        SL_LOGV("found new sample rate = %d", mSampleRateHz);
+        SL_LOGV("format changed: new sample rate = %d, channel count = %d",
+                mSampleRateHz, mChannelCount);
 
         {
             android::Mutex::Autolock autoLock(mPcmFormatLock);
index e6fb460..d2b45c2 100644 (file)
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef AUDIO_SF_DECODER_H_
+#define AUDIO_SF_DECODER_H_
+
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/FileSource.h>
 //--------------------------------------------------------------------------------------------------
 namespace android {
 
+// keep in sync with the entries of kPcmDecodeMetadataKeys[]
+#define ANDROID_KEY_INDEX_PCMFORMAT_NUMCHANNELS   0
+#define ANDROID_KEY_INDEX_PCMFORMAT_SAMPLESPERSEC 1
+#define ANDROID_KEY_INDEX_PCMFORMAT_BITSPERSAMPLE 2
+#define ANDROID_KEY_INDEX_PCMFORMAT_CONTAINERSIZE 3
+#define ANDROID_KEY_INDEX_PCMFORMAT_CHANNELMASK   4
+#define ANDROID_KEY_INDEX_PCMFORMAT_ENDIANNESS    5
+
 // to keep in sync with the ANDROID_KEY_INDEX_PCMFORMAT_* constants in android_AudioSfDecoder.cpp
 static const char* const kPcmDecodeMetadataKeys[] = {
         ANDROID_KEY_PCMFORMAT_NUMCHANNELS, ANDROID_KEY_PCMFORMAT_SAMPLESPERSEC,
@@ -106,8 +117,6 @@ protected:
     // mutex used to protect the decode buffer, the audio source and its running state
     Mutex       mBufferSourceLock;
 
-private:
-
     void notifyPrepared(status_t prepareRes);
 
     int64_t mSeekTimeMsec;
@@ -123,6 +132,7 @@ private:
     // protects mPcmFormatKeyCount and mPcmFormatValues
     Mutex    mPcmFormatLock;
 
+private:
     bool wantPrefetch();
     CacheStatus_t getCacheRemaining(bool *eos);
     int64_t getPositionUsec(); // ANDROID_UNKNOWN_TIME if unknown
@@ -137,3 +147,5 @@ private:
 };
 
 } // namespace android
+
+#endif // AUDIO_SF_DECODER_H_
index 7f3ad4a..26709d0 100644 (file)
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#ifndef AUDIO_TO_CB_RENDERER_H_
+#define AUDIO_TO_CB_RENDERER_H_
+
 #include "android/android_AudioSfDecoder.h"
 
 //--------------------------------------------------------------------------------------------------
@@ -51,3 +54,5 @@ private:
 };
 
 } // namespace android
+
+#endif //AUDIO_TO_CB_RENDERER_H_
index 14fe967..890a2c6 100644 (file)
@@ -36,6 +36,9 @@ enum AndroidObjectType {
     // audio recorder, recording from an input device data source, streamed into a
     //   PCM buffer queue data sink
     AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE   = 6,
+    // audio player, decoding from an Android buffer queue with ADTS data,
+    //   to a buffer queue data sink in PCM format
+    AUDIOPLAYER_FROM_ADTS_ABQ_TO_PCM_BUFFERQUEUE = 7,
     NUM_AUDIOPLAYER_MAP_TYPES
 };
 
@@ -135,6 +138,12 @@ typedef size_t (*data_push_cbf_t)(const uint8_t *data, size_t size, void* user);
 // buffer marks a format change with previous TS data, resume display as soon as possible
 #define ANDROID_MP2TSEVENT_FORMAT_CHANGE ((SLuint32) 0x1 << 3)
 
+/**
+ * Event mask for AAC ADTS events associated with ADTS data
+ */
+#define ANDROID_ADTSEVENT_NONE           ANDROID_MP2TSEVENT_NONE
+// buffer is at End Of Stream
+#define ANDROID_ADTSEVENT_EOS            ANDROID_MP2TSEVENT_EOS
 
 /**
  * Additional metadata keys
@@ -156,9 +165,19 @@ typedef size_t (*data_push_cbf_t)(const uint8_t *data, size_t size, void* user);
 enum AndroidBufferType_type {
     kAndroidBufferTypeInvalid = ((SLuint16) 0x0),
     kAndroidBufferTypeMpeg2Ts = ((SLuint16) 0x1),
+    kAndroidBufferTypeAacadts = ((SLuint16) 0x2),
 };
 
 /**
+ * MIME types required for data in Android Buffer Queues
+ */
+#define ANDROID_MIME_MP2TS                     "video/mp2ts"
+// the MIME type used elsewhere in the Android framework for AAC ADTS
+#define ANDROID_MIME_AACADTS_ANDROID_FRAMEWORK "audio/aac-adts"
+// the MIME type applications should use for AAC ADTS
+#define ANDROID_MIME_AACADTS                   "audio/vnd.android.aac-adts"
+
+/**
  * Notification thresholds relative to content duration in the cache
  */
 #define DURATION_CACHED_HIGH_MS  30000 // 30s
diff --git a/wilhelm/src/android/include/AacAdtsExtractor.h b/wilhelm/src/android/include/AacAdtsExtractor.h
new file mode 100644 (file)
index 0000000..af0b38b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAC_ADTS_EXTRACTOR_H_
+#define AAC_ADTS_EXTRACTOR_H_
+
+#include <utils/Vector.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct AMessage;
+class String8;
+
+
+class AacAdtsSource : public MediaSource {
+public:
+    AacAdtsSource(const sp<DataSource> &source,
+              const sp<MetaData> &meta,
+              //const Vector<uint64_t> &offset_vector,
+              int64_t frame_duration_us);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~AacAdtsSource();
+
+private:
+    static const size_t kMaxFrameSize;
+    sp<DataSource> mDataSource;
+    sp<MetaData> mMeta;
+
+    off64_t mOffset;
+    int64_t mCurrentTimeUs;
+    bool mStarted;
+    MediaBufferGroup *mGroup;
+
+    int64_t mFrameDurationUs;
+
+    AacAdtsSource(const AacAdtsSource &);
+    AacAdtsSource &operator=(const AacAdtsSource &);
+};
+
+
+class AacAdtsExtractor : public MediaExtractor {
+public:
+    AacAdtsExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+protected:
+    virtual ~AacAdtsExtractor();
+
+private:
+    sp<DataSource> mDataSource;
+    sp<MetaData> mMeta;
+    status_t mInitCheck;
+
+    int64_t mFrameDurationUs;
+
+    AacAdtsExtractor(const AacAdtsExtractor &);
+    AacAdtsExtractor &operator=(const AacAdtsExtractor &);
+
+};
+
+}  // namespace android
+
+#endif  // AAC_ADTS_EXTRACTOR_H_
diff --git a/wilhelm/src/android/include/AacBqToPcmCbRenderer.h b/wilhelm/src/android/include/AacBqToPcmCbRenderer.h
new file mode 100644 (file)
index 0000000..3b11547
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAC_BQ_TO_PCM_H_
+#define AAC_BQ_TO_PCM_H_
+
+#include "android/android_AudioToCbRenderer.h"
+#include "android/BufferQueueSource.h"
+#include "android/include/AacAdtsExtractor.h"
+
+//--------------------------------------------------------------------------------------------------
+namespace android {
+
+// Class to receive AAC ADTS data through an Android Buffer Queue, decode it and output
+// the PCM samples through a registered callback (just like its superclass, AudioToCbRenderer).
+// The implementation mainly overrides AudioSfDecoder::onPrepare() for the specificities
+// of the data source creation, but all other behavior remains the same (e.g. PCM format metadata)
+
+class AacBqToPcmCbRenderer : public AudioToCbRenderer
+{
+public:
+
+    AacBqToPcmCbRenderer(AudioPlayback_Parameters* params);
+    virtual ~AacBqToPcmCbRenderer();
+
+    void registerSourceQueueCallback(const void* user, void *context,  const void *caller);
+
+    // verifies the given memory starts and ends on ADTS frame boundaries.
+    // This is for instance used whenever ADTS data is being enqueued through an
+    // SL / XA AndroidBufferQueue interface so only parseable ADTS data goes in
+    // the buffer queue, and no ADTS frame is stored across two buffers.
+    static bool validateBufferStartEndOnFrameBoundaries(void* data, size_t size);
+
+protected:
+
+    // Async event handlers (called from GenericPlayer's event loop)
+    virtual void onPrepare();
+
+
+private:
+    // mutex used to protect mBqSource
+    Mutex                 mBqSourceLock;
+    sp<BufferQueueSource> mBqSource;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(AacBqToPcmCbRenderer);
+
+};
+
+} // namespace android
+
+#endif //AAC_BQ_TO_PCM_H_
diff --git a/wilhelm/src/android/util/AacAdtsExtractor.cpp b/wilhelm/src/android/util/AacAdtsExtractor.cpp
new file mode 100644 (file)
index 0000000..90bc967
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sllog.h"
+#include <utils/Log.h>
+
+#include "android/include/AacAdtsExtractor.h"
+#include "include/avc_utils.h"
+
+
+namespace android {
+
+#define ADTS_HEADER_LENGTH 7
+// ADTS header size is 7, but frame size information ends on byte 6 (when counting from byte 1)
+#define ADTS_HEADER_SIZE_UP_TO_FRAMESIZE 6
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Returns the sample rate based on the sampling frequency index
+static uint32_t get_sample_rate(const uint8_t sf_index)
+{
+    static const uint32_t sample_rates[] =
+    {
+        96000, 88200, 64000, 48000, 44100, 32000,
+        24000, 22050, 16000, 12000, 11025, 8000
+    };
+
+    if (sf_index < sizeof(sample_rates) / sizeof(sample_rates[0])) {
+        return sample_rates[sf_index];
+    }
+
+    return 0;
+}
+
+static size_t getFrameSize(const sp<DataSource> &source, off64_t offset) {
+    size_t frameSize = 0;
+
+    uint8_t syncHeader[ADTS_HEADER_SIZE_UP_TO_FRAMESIZE];
+    const uint8_t *syncword = syncHeader;
+    const uint8_t *header = syncHeader + 3;
+
+    if (source->readAt(offset, &syncHeader, ADTS_HEADER_SIZE_UP_TO_FRAMESIZE)
+            != ADTS_HEADER_SIZE_UP_TO_FRAMESIZE) {
+        SL_LOGE("AacAdtsExtractor:: getFrameSize() returns 0 (syncword and header read error)");
+        return 0;
+    }
+
+    if ((syncword[0] != 0xff) || ((syncword[1] & 0xf6) != 0xf0)) {
+        SL_LOGE("AacAdtsExtractor:: getFrameSize() returns 0 (syncword pb)");
+        return 0;
+    }
+
+    const uint8_t protectionAbsent = syncword[1] & 0x1;
+
+    frameSize = (header[0] & 0x3) << 11 | header[1] << 3 | header[2] >> 5;
+    // the frame size read already contains the size of the ADTS header, so no need to add it here
+    frameSize += protectionAbsent ? 0 : 2;
+
+    //SL_LOGV("AacAdtsExtractor:: getFrameSize() returns %u", frameSize);
+
+    return frameSize;
+}
+
+
+AacAdtsExtractor::AacAdtsExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mInitCheck(NO_INIT),
+      mFrameDurationUs(0) {
+
+    // difference with framework's AAC Extractor: we have already validated the data
+    // upon enqueueing, so no need to sniff the data:
+    //    String8 mimeType;
+    //    float confidence;
+    //    if (!SniffAAC(mDataSource, &mimeType, &confidence, NULL)) {
+    //        return;
+    //    }
+
+    uint8_t profile, sf_index, channel, header[2];
+    if (mDataSource->readAt(2, &header, 2) < 2) {
+        return;
+    }
+
+    profile = (header[0] >> 6) & 0x3;
+    sf_index = (header[0] >> 2) & 0xf;
+    uint32_t sr = get_sample_rate(sf_index);
+
+    if (sr == 0) {
+        return;
+    }
+    channel = (header[0] & 0x1) << 2 | (header[1] >> 6);
+
+    SL_LOGV("AacAdtsExtractor has found sr=%d channel=%d", sr, channel);
+
+    mMeta = MakeAACCodecSpecificData(profile, sf_index, channel);
+
+    off64_t offset = 0;
+    off64_t streamSize, numFrames = 0;
+    size_t frameSize = 0;
+    int64_t duration = 0;
+
+    if (mDataSource->getSize(&streamSize) == OK) {
+        while (offset < streamSize) {
+            if ((frameSize = getFrameSize(mDataSource, offset)) == 0) {
+                //SL_LOGV("AacAdtsExtractor() querying framesize at offset=%lld", offset);
+                return;
+            }
+
+            offset += frameSize;
+            numFrames ++;
+        }
+
+        // Round up and get the duration
+        mFrameDurationUs = (1024 * 1000000ll + (sr - 1)) / sr;
+        duration = numFrames * mFrameDurationUs;
+        mMeta->setInt64(kKeyDuration, duration);
+    }
+
+    mInitCheck = OK;
+
+}
+
+
+AacAdtsExtractor::~AacAdtsExtractor() {
+}
+
+
+sp<MetaData> AacAdtsExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+
+    if (mInitCheck != OK) {
+        return meta;
+    }
+
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
+
+    return meta;
+}
+
+
+size_t AacAdtsExtractor::countTracks() {
+    return mInitCheck == OK ? 1 : 0;
+}
+
+
+sp<MediaSource> AacAdtsExtractor::getTrack(size_t index) {
+    if (mInitCheck != OK || index != 0) {
+        return NULL;
+    }
+
+    return new AacAdtsSource(mDataSource, mMeta, mFrameDurationUs);
+}
+
+
+sp<MetaData> AacAdtsExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+    if (mInitCheck != OK || index != 0) {
+        return NULL;
+    }
+
+    return mMeta;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+// 8192 = 2^13, 13bit AAC frame size (in bytes)
+const size_t AacAdtsSource::kMaxFrameSize = 8192;
+
+AacAdtsSource::AacAdtsSource(
+        const sp<DataSource> &source, const sp<MetaData> &meta,
+        int64_t frame_duration_us)
+    : mDataSource(source),
+      mMeta(meta),
+      mOffset(0),
+      mCurrentTimeUs(0),
+      mStarted(false),
+      mGroup(NULL),
+      mFrameDurationUs(frame_duration_us) {
+}
+
+
+AacAdtsSource::~AacAdtsSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+
+status_t AacAdtsSource::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mOffset = 0;
+    mCurrentTimeUs = 0;
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+    mStarted = true;
+
+    return OK;
+}
+
+
+status_t AacAdtsSource::stop() {
+    CHECK(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+    return OK;
+}
+
+
+sp<MetaData> AacAdtsSource::getFormat() {
+    return mMeta;
+}
+
+
+status_t AacAdtsSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode mode;
+    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+        // difference with framework's AAC Extractor: no seeking
+        SL_LOGE("Can't seek in AAC ADTS buffer queue");
+    }
+
+    size_t frameSize, frameSizeWithoutHeader;
+    SL_LOGV("AacAdtsSource::read() offset=%lld", mOffset);
+    if ((frameSize = getFrameSize(mDataSource, mOffset)) == 0) {
+        LOGE("AacAdtsSource::read() returns EOS");
+        return ERROR_END_OF_STREAM;
+        // FIXME if we return EOS here, verify we can restart decoding when we get new data
+        //  with start()
+        //LOGE("AacAdtsSource::read() should return EOS, but returning OK");
+        //return OK;
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
+    frameSizeWithoutHeader = frameSize - ADTS_HEADER_LENGTH;
+    size_t readSize = mDataSource->readAt(mOffset + ADTS_HEADER_LENGTH, buffer->data(),
+            frameSizeWithoutHeader);
+    //SL_LOGV("AacAdtsSource::read() readAt returned %u bytes", readSize);
+    if (readSize != (ssize_t)frameSizeWithoutHeader) {
+        SL_LOGW("AacAdtsSource::read() readSize != frameSizeWithoutHeader");
+        buffer->release();
+        buffer = NULL;
+        return ERROR_IO;
+    }
+
+    buffer->set_range(0, frameSizeWithoutHeader);
+    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
+    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+
+    mOffset += frameSize;
+    mCurrentTimeUs += mFrameDurationUs;
+
+    *out = buffer;
+    return OK;
+}
+
+}  // namespace android
index 64b1d20..383991e 100644 (file)
@@ -658,6 +658,19 @@ SLresult checkSourceSinkVsInterfacesCompatibility(const DataLocatorFormat *pSrcD
 
 #ifdef ANDROID
     case SL_DATALOCATOR_ANDROIDBUFFERQUEUE:
+        // if the source is SLAndroidBufferQueueItf for AAC decode, the sink must be a buffer queue
+        switch (pSinkDataLocatorFormat->mLocator.mLocatorType) {
+        case SL_DATALOCATOR_BUFFERQUEUE:
+        case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
+            break;
+        default:
+            // FIXME more mph index business to worry about?
+            // FIXME does this break OpenMAX AL?
+            SL_LOGE("Source is SL_DATALOCATOR_ANDROIDBUFFERQUEUE, sink is not a buffer queue");
+            return SL_RESULT_FEATURE_UNSUPPORTED;
+            break;
+        }
+        break;
 #endif
     case SL_DATALOCATOR_ADDRESS:
     case SL_DATALOCATOR_MIDIBUFFERQUEUE:
index b669fa7..585b8b8 100644 (file)
 
 /* AndroidBufferQueue implementation */
 
-#include "sles_allinclusive.h"
+//#define USE_LOG SLAndroidLogLevel_Verbose
 
+#include "sles_allinclusive.h"
+// for AAC ADTS verification on enqueue:
+#include "android/include/AacBqToPcmCbRenderer.h"
 
 /**
  * Determine the state of the audio player or audio recorder associated with a buffer queue.
@@ -130,12 +133,13 @@ static SLresult IAndroidBufferQueue_RegisterCallback(SLAndroidBufferQueueItf sel
 
         switch (InterfaceToObjectID(thiz)) {
           case SL_OBJECTID_AUDIOPLAYER:
-            result = SL_RESULT_SUCCESS;
-            android_audioPlayer_androidBufferQueue_registerCallback_l((CAudioPlayer*) thiz->mThis);
+            result = android_audioPlayer_androidBufferQueue_registerCallback_l(
+                    (CAudioPlayer*) thiz->mThis);
             break;
           case XA_OBJECTID_MEDIAPLAYER:
             SL_LOGV("IAndroidBufferQueue_RegisterCallback()");
             result = SL_RESULT_SUCCESS;
+            //FIXME return error code
             android_Player_androidBufferQueue_registerCallback_l((CMediaPlayer*) thiz->mThis);
             break;
           default:
@@ -214,6 +218,7 @@ static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
         SLuint32 itemsLength)
 {
     SL_ENTER_INTERFACE
+    SL_LOGD("IAndroidBufferQueue_Enqueue pData=%p dataLength=%d", pData, dataLength);
 
     if ( ((NULL == pData) || (0 == dataLength))
             && ((NULL == pItems) || (0 == itemsLength))) {
@@ -229,9 +234,20 @@ static SLresult IAndroidBufferQueue_Enqueue(SLAndroidBufferQueueItf self,
             if (dataLength % MPEG2_TS_BLOCK_SIZE == 0) {
                 break;
             }
-            // intended fall-through if test failed
             SL_LOGE("Error enqueueing MPEG-2 TS data: size must be a multiple of %d (block size)",
                     MPEG2_TS_BLOCK_SIZE);
+            result = SL_RESULT_PARAMETER_INVALID;
+            SL_LEAVE_INTERFACE
+            break;
+          case kAndroidBufferTypeAacadts:
+            // FIXME allow commands as for mp2ts
+            if (!android::AacBqToPcmCbRenderer::validateBufferStartEndOnFrameBoundaries(
+                    pData, dataLength)) {
+                SL_LOGE("Error enqueueing ADTS data: data must start and end on frame boundaries");
+                result = SL_RESULT_PARAMETER_INVALID;
+                SL_LEAVE_INTERFACE
+            }
+            break;
           case kAndroidBufferTypeInvalid:
           default:
             result = SL_RESULT_PARAMETER_INVALID;
index 75fc0ba..d099809 100644 (file)
 
 #include "sles_allinclusive.h"
 
+
+/* Utility functions */
+
+static SLresult initializeBufferQueueMembers(CAudioPlayer *ap) {
+    // inline allocation of circular mArray, up to a typical max
+    if (BUFFER_HEADER_TYPICAL >= ap->mBufferQueue.mNumBuffers) {
+        ap->mBufferQueue.mArray = ap->mBufferQueue.mTypical;
+    } else {
+        // Avoid possible integer overflow during multiplication; this arbitrary
+        // maximum is big enough to not interfere with real applications, but
+        // small enough to not overflow.
+        if (ap->mBufferQueue.mNumBuffers >= 256) {
+            return SL_RESULT_MEMORY_FAILURE;
+        }
+        ap->mBufferQueue.mArray = (BufferHeader *)
+                malloc((ap->mBufferQueue.mNumBuffers + 1) * sizeof(BufferHeader));
+        if (NULL == ap->mBufferQueue.mArray) {
+            return SL_RESULT_MEMORY_FAILURE;
+        }
+    }
+    ap->mBufferQueue.mFront = ap->mBufferQueue.mArray;
+    ap->mBufferQueue.mRear = ap->mBufferQueue.mArray;
+    return SL_RESULT_SUCCESS;
+}
+
+#ifdef ANDROID
+static SLresult initializeAndroidBufferQueueMembers(CAudioPlayer *ap) {
+    // Avoid possible integer overflow during multiplication; this arbitrary
+    // maximum is big enough to not interfere with real applications, but
+    // small enough to not overflow.
+    if (ap->mAndroidBufferQueue.mNumBuffers >= 256) {
+        return SL_RESULT_MEMORY_FAILURE;
+    }
+    ap->mAndroidBufferQueue.mBufferArray = (AdvancedBufferHeader *)
+            malloc( (ap->mAndroidBufferQueue.mNumBuffers + 1) * sizeof(AdvancedBufferHeader));
+    if (NULL == ap->mAndroidBufferQueue.mBufferArray) {
+        return SL_RESULT_MEMORY_FAILURE;
+    } else {
+
+        // initialize ABQ buffer type
+        // assert below has been checked in android_audioPlayer_checkSourceSink
+        assert(SL_DATAFORMAT_MIME == ap->mDataSource.mFormat.mFormatType);
+        switch(ap->mDataSource.mFormat.mMIME.containerType) {
+          case SL_CONTAINERTYPE_MPEG_TS:
+            ap->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeMpeg2Ts;
+            break;
+          case SL_CONTAINERTYPE_AAC:
+          case SL_CONTAINERTYPE_RAW: {
+            const char* mime = (char*)ap->mDataSource.mFormat.mMIME.mimeType;
+            if ((mime != NULL) && !(strcasecmp(mime, ANDROID_MIME_AACADTS) &&
+                    strcasecmp(mime, ANDROID_MIME_AACADTS_ANDROID_FRAMEWORK))) {
+                ap->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeAacadts;
+            } else {
+                ap->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeInvalid;
+                SL_LOGE("CreateAudioPlayer: Invalid buffer type in Android Buffer Queue");
+                return SL_RESULT_CONTENT_UNSUPPORTED;
+            }
+          } break;
+          default:
+            ap->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeInvalid;
+            SL_LOGE("CreateAudioPlayer: Invalid buffer type in Android Buffer Queue");
+            return SL_RESULT_CONTENT_UNSUPPORTED;
+        }
+
+        // initialize ABQ memory
+        for (SLuint16 i=0 ; i<(ap->mAndroidBufferQueue.mNumBuffers + 1) ; i++) {
+            AdvancedBufferHeader *pBuf = &ap->mAndroidBufferQueue.mBufferArray[i];
+            pBuf->mDataBuffer = NULL;
+            pBuf->mDataSize = 0;
+            pBuf->mDataSizeConsumed = 0;
+            pBuf->mBufferContext = NULL;
+            pBuf->mBufferState = SL_ANDROIDBUFFERQUEUEEVENT_NONE;
+            switch (ap->mAndroidBufferQueue.mBufferType) {
+              case kAndroidBufferTypeMpeg2Ts:
+                pBuf->mItems.mTsCmdData.mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
+                pBuf->mItems.mTsCmdData.mPts = 0;
+                break;
+              case kAndroidBufferTypeAacadts:
+                pBuf->mItems.mTsCmdData.mTsCmdCode = ANDROID_ADTSEVENT_NONE;
+                break;
+              default:
+                return SL_RESULT_CONTENT_UNSUPPORTED;
+            }
+        }
+        ap->mAndroidBufferQueue.mFront = ap->mAndroidBufferQueue.mBufferArray;
+        ap->mAndroidBufferQueue.mRear  = ap->mAndroidBufferQueue.mBufferArray;
+    }
+
+    return SL_RESULT_SUCCESS;
+}
+#endif
+
+
 static SLresult IEngine_CreateLEDDevice(SLEngineItf self, SLObjectItf *pDevice, SLuint32 deviceID,
     SLuint32 numInterfaces, const SLInterfaceID *pInterfaceIds, const SLboolean *pInterfaceRequired)
 {
@@ -216,11 +309,15 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
                     // we have already range-checked the value down to a smaller width
                     SLuint16 nbBuffers = 0;
                     bool usesAdvancedBufferHeaders = false;
+                    bool usesSimpleBufferQueue = false;
+                    // creating an AudioPlayer which decodes AAC ADTS buffers to a PCM buffer queue
+                    //  will cause usesAdvancedBufferHeaders and usesSimpleBufferQueue to be true
                     switch (thiz->mDataSource.mLocator.mLocatorType) {
                     case SL_DATALOCATOR_BUFFERQUEUE:
 #ifdef ANDROID
                     case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
 #endif
+                        usesSimpleBufferQueue = true;
                         nbBuffers = (SLuint16) thiz->mDataSource.mLocator.mBufferQueue.numBuffers;
                         assert(SL_DATAFORMAT_PCM == thiz->mDataSource.mFormat.mFormatType);
                         thiz->mNumChannels = thiz->mDataSource.mFormat.mPCM.numChannels;
@@ -228,8 +325,8 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
                         break;
 #ifdef ANDROID
                     case SL_DATALOCATOR_ANDROIDBUFFERQUEUE:
-                        nbBuffers = (SLuint16) thiz->mDataSource.mLocator.mABQ.numBuffers;
                         usesAdvancedBufferHeaders = true;
+                        nbBuffers = (SLuint16) thiz->mDataSource.mLocator.mABQ.numBuffers;
                         thiz->mAndroidBufferQueue.mNumBuffers = nbBuffers;
                         break;
 #endif
@@ -241,6 +338,7 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
                     switch(thiz->mDataSink.mLocator.mLocatorType) {
                     case SL_DATALOCATOR_BUFFERQUEUE:
                     case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
+                        usesSimpleBufferQueue = true;
                         nbBuffers = thiz->mDataSink.mLocator.mBufferQueue.numBuffers;
                         assert(SL_DATAFORMAT_PCM == thiz->mDataSink.mFormat.mFormatType);
                         // FIXME The values specified by the app are meaningless. We get the
@@ -285,85 +383,16 @@ static SLresult IEngine_CreateAudioPlayer(SLEngineItf self, SLObjectItf *pPlayer
                     if (usesAdvancedBufferHeaders) {
 #ifdef ANDROID
                         // locator is SL_DATALOCATOR_ANDROIDBUFFERQUEUE
-                        // Avoid possible integer overflow during multiplication; this arbitrary
-                        // maximum is big enough to not interfere with real applications, but
-                        // small enough to not overflow.
-                        if (thiz->mAndroidBufferQueue.mNumBuffers >= 256) {
-                            result = SL_RESULT_MEMORY_FAILURE;
-                            break;
-                        }
-                        thiz->mAndroidBufferQueue.mBufferArray = (AdvancedBufferHeader *)
-                                malloc( (thiz->mAndroidBufferQueue.mNumBuffers + 1)
-                                        * sizeof(AdvancedBufferHeader));
-                        if (NULL == thiz->mAndroidBufferQueue.mBufferArray) {
-                            result = SL_RESULT_MEMORY_FAILURE;
-                            break;
-                        } else {
-
-                            // initialize ABQ buffer type
-                            // assert below has been checked in android_audioPlayer_checkSourceSink
-                            assert(SL_DATAFORMAT_MIME == thiz->mDataSource.mFormat.mFormatType);
-                            if (SL_CONTAINERTYPE_MPEG_TS ==
-                                    thiz->mDataSource.mFormat.mMIME.containerType) {
-                                thiz->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeMpeg2Ts;
-                            } else {
-                                thiz->mAndroidBufferQueue.mBufferType = kAndroidBufferTypeInvalid;
-                                SL_LOGE("Invalid buffer type in Android Buffer Queue");
-                                result = SL_RESULT_CONTENT_UNSUPPORTED;
-                            }
-
-                            // initialize ABQ memory
-                            for (SLuint16 i=0 ; i<(thiz->mAndroidBufferQueue.mNumBuffers + 1) ;
-                                    i++) {
-                                thiz->mAndroidBufferQueue.mBufferArray[i].mDataBuffer = NULL;
-                                thiz->mAndroidBufferQueue.mBufferArray[i].mDataSize = 0;
-                                thiz->mAndroidBufferQueue.mBufferArray[i].mDataSizeConsumed = 0;
-                                thiz->mAndroidBufferQueue.mBufferArray[i].mBufferContext = NULL;
-                                thiz->mAndroidBufferQueue.mBufferArray[i].mBufferState =
-                                        SL_ANDROIDBUFFERQUEUEEVENT_NONE;
-                                switch (thiz->mAndroidBufferQueue.mBufferType) {
-                                  case kAndroidBufferTypeMpeg2Ts:
-                                    thiz->mAndroidBufferQueue.mBufferArray[i].mItems.mTsCmdData.
-                                             mTsCmdCode = ANDROID_MP2TSEVENT_NONE;
-                                    thiz->mAndroidBufferQueue.mBufferArray[i].mItems.mTsCmdData.
-                                             mPts = 0;
-                                    break;
-                                  default:
-                                    result = SL_RESULT_CONTENT_UNSUPPORTED;
-                                    break;
-                                }
-                            }
-                            thiz->mAndroidBufferQueue.mFront =
-                                    thiz->mAndroidBufferQueue.mBufferArray;
-                            thiz->mAndroidBufferQueue.mRear =
-                                    thiz->mAndroidBufferQueue.mBufferArray;
-                        }
+                        result = initializeAndroidBufferQueueMembers(thiz);
 #else
                         assert(false);
 #endif
-                    } else {
+                    }
+
+                    if (usesSimpleBufferQueue) {
                         // locator is SL_DATALOCATOR_BUFFERQUEUE
                         //         or SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE
-                        // inline allocation of circular mArray, up to a typical max
-                        if (BUFFER_HEADER_TYPICAL >= thiz->mBufferQueue.mNumBuffers) {
-                            thiz->mBufferQueue.mArray = thiz->mBufferQueue.mTypical;
-                        } else {
-                            // Avoid possible integer overflow during multiplication; this arbitrary
-                            // maximum is big enough to not interfere with real applications, but
-                            // small enough to not overflow.
-                            if (thiz->mBufferQueue.mNumBuffers >= 256) {
-                                result = SL_RESULT_MEMORY_FAILURE;
-                                break;
-                            }
-                            thiz->mBufferQueue.mArray = (BufferHeader *) malloc((thiz->mBufferQueue.
-                                    mNumBuffers + 1) * sizeof(BufferHeader));
-                            if (NULL == thiz->mBufferQueue.mArray) {
-                                result = SL_RESULT_MEMORY_FAILURE;
-                                break;
-                            }
-                        }
-                        thiz->mBufferQueue.mFront = thiz->mBufferQueue.mArray;
-                        thiz->mBufferQueue.mRear = thiz->mBufferQueue.mArray;
+                        result = initializeBufferQueueMembers(thiz);
                     }
 
                     // used to store the data source of our audio player
index 4884ccc..6e21ee4 100644 (file)
@@ -234,11 +234,18 @@ typedef struct {
     SLAuint64 mPts;
 } Mpeg2TsCommands;
 
+// Holds information about all commands that can be passed alongside an AAC ADTS buffer
+// Is used with buffers of type kAndroidBufferTypeAacadts
+typedef struct {
+    SLuint32 mAdtsCmdCode;
+} AdtsCommands;
+
 // Union of the different structures to hold items stored in an AdvancedBufferHeader
 //   when an item comes from an AndroidBufferQueue as the data source, it's a command
 //   when an item is output to an AndroidBufferQueue as the data sink, it's a message (or metadata)
 typedef union {
     Mpeg2TsCommands mTsCmdData;
+    AdtsCommands    mAdtsCmdData;
 } AdvancedBufferItems;
 
 // AdvancedBufferHeader describes each element of an AndroidBufferQueue, other than the data