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 &);