Merge "Fix issue 2667797: [Audio Effect Framework] new base class and binder interfaces for effect control." into kraken
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index ea8391d..b859e78 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -159,7 +159,6 @@
     SharedBufferBase(SharedClient* sharedClient, int surface,
             int32_t identity);
     ~SharedBufferBase();
-    uint32_t getIdentity();
     status_t getStatus() const;
     size_t getFrontBuffer() const;
     String8 dump(char const* prefix) const;
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index 3a5da4d..c08f4f5 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -20,6 +20,7 @@
 #include <cutils/log.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <string.h>
 #include <new>
 #include "AudioEqualizer.h"
 #include "AudioBiquadFilter.h"
diff --git a/media/libeffects/EffectsFactory.c b/media/libeffects/EffectsFactory.c
index 07c4d80..35a1001 100644
--- a/media/libeffects/EffectsFactory.c
+++ b/media/libeffects/EffectsFactory.c
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 
 #include "EffectsFactory.h"
+#include <string.h>
+#include <stdlib.h>
 #include <dlfcn.h>
 
 
@@ -277,7 +279,7 @@
     if (ret < 0) {
         return ret;
     }
-    if (libPath == NULL || strnlen(libPath, PATH_MAX) >= PATH_MAX) {
+    if (libPath == NULL) {
         return -EINVAL;
     }
     return loadLibrary(libPath, handle);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d0d1b14..bd16db9 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -78,6 +78,8 @@
 
     void init();
 
+    sp<MetaData> getFileMetaData() { return mFileMeta; }
+
 private:
     struct Page {
         uint64_t mGranulePosition;
@@ -100,6 +102,7 @@
     vorbis_comment mVc;
 
     sp<MetaData> mMeta;
+    sp<MetaData> mFileMeta;
 
     ssize_t readPage(off_t offset, Page *page);
     status_t findNextPage(off_t startOffset, off_t *pageOffset);
@@ -107,6 +110,9 @@
     void verifyHeader(
             MediaBuffer *buffer, uint8_t type);
 
+    void parseFileMetaData();
+    void extractAlbumArt(const void *data, size_t size);
+
     MyVorbisExtractor(const MyVorbisExtractor &);
     MyVorbisExtractor &operator=(const MyVorbisExtractor &);
 };
@@ -188,9 +194,14 @@
       mNextLaceIndex(0),
       mFirstDataOffset(-1) {
     mCurrentPage.mNumSegments = 0;
+
+    vorbis_info_init(&mVi);
+    vorbis_comment_init(&mVc);
 }
 
 MyVorbisExtractor::~MyVorbisExtractor() {
+    vorbis_comment_clear(&mVc);
+    vorbis_info_clear(&mVi);
 }
 
 sp<MetaData> MyVorbisExtractor::getFormat() const {
@@ -305,7 +316,7 @@
         tmp.append(x);
     }
 
-    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
+    // LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
 
     return sizeof(header) + page->mNumSegments + totalSize;
 }
@@ -422,10 +433,6 @@
 }
 
 void MyVorbisExtractor::init() {
-    vorbis_info_init(&mVi);
-
-    vorbis_comment mVc;
-
     mMeta = new MetaData;
     mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
 
@@ -509,6 +516,8 @@
         case 3:
         {
             CHECK_EQ(0, _vorbis_unpack_comment(&mVc, &bits));
+
+            parseFileMetaData();
             break;
         }
 
@@ -530,6 +539,192 @@
     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
 }
 
+void MyVorbisExtractor::parseFileMetaData() {
+    mFileMeta = new MetaData;
+    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
+
+    struct {
+        const char *const mTag;
+        uint32_t mKey;
+    } kMap[] = {
+        { "TITLE", kKeyTitle },
+        { "ARTIST", kKeyArtist },
+        { "ALBUM", kKeyAlbum },
+        { "COMPOSER", kKeyComposer },
+        { "GENRE", kKeyGenre },
+        { "AUTHOR", kKeyAuthor },
+        { "TRACKNUMBER", kKeyCDTrackNumber },
+        { "DISCNUMBER", kKeyDiscNumber },
+        { "DATE", kKeyDate },
+        { "LYRICIST", kKeyWriter },
+        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+    };
+
+    for (int i = 0; i < mVc.comments; ++i) {
+        const char *comment = mVc.user_comments[i];
+
+        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
+            size_t tagLen = strlen(kMap[j].mTag);
+            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
+                    && comment[tagLen] == '=') {
+                if (kMap[j].mKey == kKeyAlbumArt) {
+                    extractAlbumArt(
+                            &comment[tagLen + 1],
+                            mVc.comment_lengths[i] - tagLen - 1);
+                } else {
+                    mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
+                }
+            }
+        }
+
+    }
+
+#if 0
+    for (int i = 0; i < mVc.comments; ++i) {
+        LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
+    }
+#endif
+}
+
+// The returned buffer should be free()d.
+static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
+    *outSize = 0;
+
+    if ((size % 4) != 0) {
+        return NULL;
+    }
+
+    size_t n = size;
+    size_t padding = 0;
+    if (n >= 1 && s[n - 1] == '=') {
+        padding = 1;
+
+        if (n >= 2 && s[n - 2] == '=') {
+            padding = 2;
+        }
+    }
+
+    size_t outLen = 3 * size / 4 - padding;
+
+    *outSize = outLen;
+
+    void *buffer = malloc(outLen);
+
+    uint8_t *out = (uint8_t *)buffer;
+    size_t j = 0;
+    uint32_t accum = 0;
+    for (size_t i = 0; i < n; ++i) {
+        char c = s[i];
+        unsigned value;
+        if (c >= 'A' && c <= 'Z') {
+            value = c - 'A';
+        } else if (c >= 'a' && c <= 'z') {
+            value = 26 + c - 'a';
+        } else if (c >= '0' && c <= '9') {
+            value = 52 + c - '0';
+        } else if (c == '+') {
+            value = 62;
+        } else if (c == '/') {
+            value = 63;
+        } else if (c != '=') {
+            return NULL;
+        } else {
+            if (i < n - padding) {
+                return NULL;
+            }
+
+            value = 0;
+        }
+
+        accum = (accum << 6) | value;
+
+        if (((i + 1) % 4) == 0) {
+            out[j++] = (accum >> 16);
+
+            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
+            if (j < outLen) { out[j++] = accum & 0xff; }
+
+            accum = 0;
+        }
+    }
+
+    return (uint8_t *)buffer;
+}
+
+void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
+    LOGV("extractAlbumArt from '%s'", (const char *)data);
+
+    size_t flacSize;
+    uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
+
+    if (flac == NULL) {
+        LOGE("malformed base64 encoded data.");
+        return;
+    }
+
+    LOGV("got flac of size %d", flacSize);
+
+    uint32_t picType;
+    uint32_t typeLen;
+    uint32_t descLen;
+    uint32_t dataLen;
+    char type[128];
+
+    if (flacSize < 8) {
+        goto exit;
+    }
+
+    picType = U32_AT(flac);
+
+    if (picType != 3) {
+        // This is not a front cover.
+        goto exit;
+    }
+
+    typeLen = U32_AT(&flac[4]);
+    if (typeLen + 1 > sizeof(type)) {
+        goto exit;
+    }
+
+    if (flacSize < 8 + typeLen) {
+        goto exit;
+    }
+
+    memcpy(type, &flac[8], typeLen);
+    type[typeLen] = '\0';
+
+    LOGV("picType = %d, type = '%s'", picType, type);
+
+    if (!strcmp(type, "-->")) {
+        // This is not inline cover art, but an external url instead.
+        goto exit;
+    }
+
+    descLen = U32_AT(&flac[8 + typeLen]);
+
+    if (flacSize < 32 + typeLen + descLen) {
+        goto exit;
+    }
+
+    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
+
+    if (flacSize < 32 + typeLen + descLen + dataLen) {
+        goto exit;
+    }
+
+    LOGV("got image data, %d trailing bytes",
+         flacSize - 32 - typeLen - descLen - dataLen);
+
+    mFileMeta->setData(
+            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
+
+    mFileMeta->setCString(kKeyAlbumArtMIME, type);
+
+exit:
+    free(flac);
+    flac = NULL;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 OggExtractor::OggExtractor(const sp<DataSource> &source)
@@ -570,15 +765,7 @@
 }
 
 sp<MetaData> OggExtractor::getMetaData() {
-    sp<MetaData> meta = new MetaData;
-
-    if (mInitCheck != OK) {
-        return meta;
-    }
-
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
-
-    return meta;
+    return mImpl->getFileMetaData();
 }
 
 bool SniffOgg(
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index ab17b04..2829638 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -26,10 +26,6 @@
 // Sonivox includes
 #include <libsonivox/eas.h>
 
-// Ogg Vorbis includes
-#include <Tremolo/ivorbiscodec.h>
-#include <Tremolo/ivorbisfile.h>
-
 namespace android {
 
 StagefrightMediaScanner::StagefrightMediaScanner()
@@ -103,48 +99,6 @@
     return OK;
 }
 
-static status_t HandleOGG(
-        const char *filename, MediaScannerClient *client) {
-    int duration;
-
-    FILE *file = fopen(filename,"r");
-    if (!file)
-        return UNKNOWN_ERROR;
-
-    OggVorbis_File vf;
-    if (ov_open(file, &vf, NULL, 0) < 0) {
-        return UNKNOWN_ERROR;
-    }
-
-    char **ptr=ov_comment(&vf,-1)->user_comments;
-    while(*ptr){
-        char *val = strstr(*ptr, "=");
-        if (val) {
-            int keylen = val++ - *ptr;
-            char key[keylen + 1];
-            strncpy(key, *ptr, keylen);
-            key[keylen] = 0;
-            if (!client->addStringTag(key, val)) goto failure;
-        }
-        ++ptr;
-    }
-
-    // Duration
-    duration = ov_time_total(&vf, -1);
-    if (duration > 0) {
-        char buffer[20];
-        sprintf(buffer, "%d", duration);
-        if (!client->addStringTag("duration", buffer)) goto failure;
-    }
-
-    ov_clear(&vf); // this also closes the FILE
-    return OK;
-
-failure:
-    ov_clear(&vf); // this also closes the FILE
-    return UNKNOWN_ERROR;
-}
-
 status_t StagefrightMediaScanner::processFile(
         const char *path, const char *mimeType,
         MediaScannerClient &client) {
@@ -176,10 +130,6 @@
         return HandleMIDI(path, &client);
     }
 
-    if (!strcasecmp(extension, ".ogg")) {
-        return HandleOGG(path, &client);
-    }
-
     if (mRetriever->setDataSource(path) == OK
             && mRetriever->setMode(
                 METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 197ccf8..339a7b5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -121,6 +121,29 @@
     }
 }
 
+struct BlockIterator {
+    BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
+
+    bool eos() const;
+
+    void advance();
+    void reset();
+    void seek(int64_t seekTimeUs);
+
+    const mkvparser::Block *block() const;
+    int64_t blockTimeUs() const;
+
+private:
+    mkvparser::Segment *mSegment;
+    unsigned long mTrackNum;
+
+    mkvparser::Cluster *mCluster;
+    const mkvparser::BlockEntry *mBlockEntry;
+
+    BlockIterator(const BlockIterator &);
+    BlockIterator &operator=(const BlockIterator &);
+};
+
 struct MatroskaSource : public MediaSource {
     MatroskaSource(
             const sp<MatroskaExtractor> &extractor, size_t index);
@@ -142,10 +165,8 @@
 
     sp<MatroskaExtractor> mExtractor;
     size_t mTrackIndex;
-    unsigned long mTrackNum;
     Type mType;
-    mkvparser::Cluster *mCluster;
-    const mkvparser::BlockEntry *mBlockEntry;
+    BlockIterator mBlockIter;
 
     status_t advance();
 
@@ -158,10 +179,8 @@
     : mExtractor(extractor),
       mTrackIndex(index),
       mType(OTHER),
-      mCluster(NULL),
-      mBlockEntry(NULL) {
-    mTrackNum = mExtractor->mTracks.itemAt(index).mTrackNum;
-
+      mBlockIter(mExtractor->mSegment,
+                 mExtractor->mTracks.itemAt(index).mTrackNum) {
     const char *mime;
     CHECK(mExtractor->mTracks.itemAt(index).mMeta->
             findCString(kKeyMIMEType, &mime));
@@ -174,8 +193,7 @@
 }
 
 status_t MatroskaSource::start(MetaData *params) {
-    mCluster = NULL;
-    mBlockEntry = NULL;
+    mBlockIter.reset();
 
     return OK;
 }
@@ -188,60 +206,95 @@
     return mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
 }
 
-status_t MatroskaSource::advance() {
-    for (;;) {
-        if (mBlockEntry == NULL || mBlockEntry->EOS()) {
-            if (mCluster == NULL) {
-                mCluster = mExtractor->mSegment->GetFirst();
-            } else {
-                mCluster = mExtractor->mSegment->GetNext(mCluster);
+////////////////////////////////////////////////////////////////////////////////
+
+BlockIterator::BlockIterator(
+        mkvparser::Segment *segment, unsigned long trackNum)
+    : mSegment(segment),
+      mTrackNum(trackNum),
+      mCluster(NULL),
+      mBlockEntry(NULL) {
+    reset();
+}
+
+bool BlockIterator::eos() const {
+    return mCluster == NULL || mCluster->EOS();
+}
+
+void BlockIterator::advance() {
+    while (!eos()) {
+        if (mBlockEntry != NULL) {
+            mBlockEntry = mCluster->GetNext(mBlockEntry);
+        } else if (mCluster != NULL) {
+            mCluster = mSegment->GetNext(mCluster);
+
+            if (eos()) {
+                break;
             }
-            if (mCluster == NULL || mCluster->EOS()) {
-                return ERROR_END_OF_STREAM;
-            }
+
             mBlockEntry = mCluster->GetFirst();
         }
 
-        if (mBlockEntry->GetBlock()->GetTrackNumber() != mTrackNum) {
-            mBlockEntry = mCluster->GetNext(mBlockEntry);
-            continue;
+        if (mBlockEntry != NULL
+                && mBlockEntry->GetBlock()->GetTrackNumber() == mTrackNum) {
+            break;
         }
+    }
+}
 
-        break;
+void BlockIterator::reset() {
+    mCluster = mSegment->GetFirst();
+    mBlockEntry = mCluster->GetFirst();
+
+    while (!eos() && block()->GetTrackNumber() != mTrackNum) {
+        advance();
+    }
+}
+
+void BlockIterator::seek(int64_t seekTimeUs) {
+    mCluster = mSegment->GetCluster(seekTimeUs * 1000ll);
+    mBlockEntry = mCluster != NULL ? mCluster->GetFirst() : NULL;
+
+    while (!eos() && block()->GetTrackNumber() != mTrackNum) {
+        advance();
     }
 
-    return OK;
+    while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
+        advance();
+    }
 }
 
+const mkvparser::Block *BlockIterator::block() const {
+    CHECK(!eos());
+
+    return mBlockEntry->GetBlock();
+}
+
+int64_t BlockIterator::blockTimeUs() const {
+    return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 status_t MatroskaSource::read(
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
     if (options && options->getSeekTo(&seekTimeUs)) {
-        mBlockEntry = NULL;
-        mCluster = mExtractor->mSegment->GetCluster(seekTimeUs * 1000ll);
-
-        status_t err;
-        while ((err = advance()) == OK && !mBlockEntry->GetBlock()->IsKey()) {
-            mBlockEntry = mCluster->GetNext(mBlockEntry);
-        }
-
-        if (err != OK) {
-            return ERROR_END_OF_STREAM;
-        }
+        mBlockIter.seek(seekTimeUs);
     }
 
-    if (advance() != OK) {
+    if (mBlockIter.eos()) {
         return ERROR_END_OF_STREAM;
     }
 
-    const mkvparser::Block *block = mBlockEntry->GetBlock();
+    const mkvparser::Block *block = mBlockIter.block();
     size_t size = block->GetSize();
-    long long timeNs = block->GetTime(mCluster);
+    int64_t timeUs = mBlockIter.blockTimeUs();
 
     MediaBuffer *buffer = new MediaBuffer(size + 2);
-    buffer->meta_data()->setInt64(kKeyTime, (timeNs + 500) / 1000);
+    buffer->meta_data()->setInt64(kKeyTime, timeUs);
 
     long res = block->Read(
             mExtractor->mReader, (unsigned char *)buffer->data() + 2);
@@ -280,7 +333,7 @@
             buffer->range_length());
 #endif
 
-    mBlockEntry = mCluster->GetNext(mBlockEntry);
+    mBlockIter.advance();
 
     return OK;
 }
@@ -290,7 +343,8 @@
 MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
     : mDataSource(source),
       mReader(new DataSourceReader(mDataSource)),
-      mSegment(NULL) {
+      mSegment(NULL),
+      mExtractedThumbnails(false) {
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
     if (ebmlHeader.Parse(mReader, pos) < 0) {
@@ -342,6 +396,11 @@
         return NULL;
     }
 
+    if ((flags & kIncludeExtensiveMetaData) && !mExtractedThumbnails) {
+        findThumbnails();
+        mExtractedThumbnails = true;
+    }
+
     return mTracks.itemAt(index).mMeta;
 }
 
@@ -479,6 +538,37 @@
     }
 }
 
+void MatroskaExtractor::findThumbnails() {
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        TrackInfo *info = &mTracks.editItemAt(i);
+
+        const char *mime;
+        CHECK(info->mMeta->findCString(kKeyMIMEType, &mime));
+
+        if (strncasecmp(mime, "video/", 6)) {
+            continue;
+        }
+
+        BlockIterator iter(mSegment, info->mTrackNum);
+        int32_t i = 0;
+        int64_t thumbnailTimeUs = 0;
+        size_t maxBlockSize = 0;
+        while (!iter.eos() && i < 20) {
+            if (iter.block()->IsKey()) {
+                ++i;
+
+                size_t blockSize = iter.block()->GetSize();
+                if (blockSize > maxBlockSize) {
+                    maxBlockSize = blockSize;
+                    thumbnailTimeUs = iter.blockTimeUs();
+                }
+            }
+            iter.advance();
+        }
+        info->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+    }
+}
+
 sp<MetaData> MatroskaExtractor::getMetaData() {
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MATROSKA);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 7bf41a9..7471848 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -59,8 +59,10 @@
     sp<DataSource> mDataSource;
     DataSourceReader *mReader;
     mkvparser::Segment *mSegment;
+    bool mExtractedThumbnails;
 
     void addTracks();
+    void findThumbnails();
 
     MatroskaExtractor(const MatroskaExtractor &);
     MatroskaExtractor &operator=(const MatroskaExtractor &);