Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "OggExtractor"
     19 #include <utils/Log.h>
     20 
     21 #include "include/OggExtractor.h"
     22 
     23 #include <cutils/properties.h>
     24 #include <media/stagefright/DataSource.h>
     25 #include <media/stagefright/MediaBuffer.h>
     26 #include <media/stagefright/MediaBufferGroup.h>
     27 #include <media/stagefright/MediaDebug.h>
     28 #include <media/stagefright/MediaDefs.h>
     29 #include <media/stagefright/MediaErrors.h>
     30 #include <media/stagefright/MediaSource.h>
     31 #include <media/stagefright/MetaData.h>
     32 #include <media/stagefright/Utils.h>
     33 #include <utils/String8.h>
     34 
     35 extern "C" {
     36     #include <Tremolo/codec_internal.h>
     37 
     38     int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
     39     int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
     40     int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
     41 }
     42 
     43 namespace android {
     44 
     45 struct OggSource : public MediaSource {
     46     OggSource(const sp<OggExtractor> &extractor);
     47 
     48     virtual sp<MetaData> getFormat();
     49 
     50     virtual status_t start(MetaData *params = NULL);
     51     virtual status_t stop();
     52 
     53     virtual status_t read(
     54             MediaBuffer **buffer, const ReadOptions *options = NULL);
     55 
     56 protected:
     57     virtual ~OggSource();
     58 
     59 private:
     60     sp<OggExtractor> mExtractor;
     61     bool mStarted;
     62 
     63     OggSource(const OggSource &);
     64     OggSource &operator=(const OggSource &);
     65 };
     66 
     67 struct MyVorbisExtractor {
     68     MyVorbisExtractor(const sp<DataSource> &source);
     69     virtual ~MyVorbisExtractor();
     70 
     71     sp<MetaData> getFormat() const;
     72 
     73     // Returns an approximate bitrate in bits per second.
     74     uint64_t approxBitrate();
     75 
     76     status_t seekToOffset(off_t offset);
     77     status_t readNextPacket(MediaBuffer **buffer);
     78 
     79     status_t init();
     80 
     81     sp<MetaData> getFileMetaData() { return mFileMeta; }
     82 
     83 private:
     84     struct Page {
     85         uint64_t mGranulePosition;
     86         uint32_t mSerialNo;
     87         uint32_t mPageNo;
     88         uint8_t mFlags;
     89         uint8_t mNumSegments;
     90         uint8_t mLace[255];
     91     };
     92 
     93     sp<DataSource> mSource;
     94     off_t mOffset;
     95     Page mCurrentPage;
     96     uint64_t mPrevGranulePosition;
     97     size_t mCurrentPageSize;
     98     bool mFirstPacketInPage;
     99     uint64_t mCurrentPageSamples;
    100     size_t mNextLaceIndex;
    101 
    102     off_t mFirstDataOffset;
    103 
    104     vorbis_info mVi;
    105     vorbis_comment mVc;
    106 
    107     sp<MetaData> mMeta;
    108     sp<MetaData> mFileMeta;
    109 
    110     ssize_t readPage(off_t offset, Page *page);
    111     status_t findNextPage(off_t startOffset, off_t *pageOffset);
    112 
    113     status_t verifyHeader(
    114             MediaBuffer *buffer, uint8_t type);
    115 
    116     void parseFileMetaData();
    117     void extractAlbumArt(const void *data, size_t size);
    118 
    119     uint64_t findPrevGranulePosition(off_t pageOffset);
    120 
    121     MyVorbisExtractor(const MyVorbisExtractor &);
    122     MyVorbisExtractor &operator=(const MyVorbisExtractor &);
    123 };
    124 
    125 ////////////////////////////////////////////////////////////////////////////////
    126 
    127 OggSource::OggSource(const sp<OggExtractor> &extractor)
    128     : mExtractor(extractor),
    129       mStarted(false) {
    130 }
    131 
    132 OggSource::~OggSource() {
    133     if (mStarted) {
    134         stop();
    135     }
    136 }
    137 
    138 sp<MetaData> OggSource::getFormat() {
    139     return mExtractor->mImpl->getFormat();
    140 }
    141 
    142 status_t OggSource::start(MetaData *params) {
    143     if (mStarted) {
    144         return INVALID_OPERATION;
    145     }
    146 
    147     mStarted = true;
    148 
    149     return OK;
    150 }
    151 
    152 status_t OggSource::stop() {
    153     mStarted = false;
    154 
    155     return OK;
    156 }
    157 
    158 status_t OggSource::read(
    159         MediaBuffer **out, const ReadOptions *options) {
    160     *out = NULL;
    161 
    162     int64_t seekTimeUs;
    163     ReadOptions::SeekMode mode;
    164     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
    165         off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
    166         LOGV("seeking to offset %ld", pos);
    167 
    168         if (mExtractor->mImpl->seekToOffset(pos) != OK) {
    169             return ERROR_END_OF_STREAM;
    170         }
    171     }
    172 
    173     MediaBuffer *packet;
    174     status_t err = mExtractor->mImpl->readNextPacket(&packet);
    175 
    176     if (err != OK) {
    177         return err;
    178     }
    179 
    180 #if 0
    181     int64_t timeUs;
    182     if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
    183         LOGI("found time = %lld us", timeUs);
    184     } else {
    185         LOGI("NO time");
    186     }
    187 #endif
    188 
    189     packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
    190 
    191     *out = packet;
    192 
    193     return OK;
    194 }
    195 
    196 ////////////////////////////////////////////////////////////////////////////////
    197 
    198 MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
    199     : mSource(source),
    200       mOffset(0),
    201       mPrevGranulePosition(0),
    202       mCurrentPageSize(0),
    203       mFirstPacketInPage(true),
    204       mCurrentPageSamples(0),
    205       mNextLaceIndex(0),
    206       mFirstDataOffset(-1) {
    207     mCurrentPage.mNumSegments = 0;
    208 
    209     vorbis_info_init(&mVi);
    210     vorbis_comment_init(&mVc);
    211 }
    212 
    213 MyVorbisExtractor::~MyVorbisExtractor() {
    214     vorbis_comment_clear(&mVc);
    215     vorbis_info_clear(&mVi);
    216 }
    217 
    218 sp<MetaData> MyVorbisExtractor::getFormat() const {
    219     return mMeta;
    220 }
    221 
    222 status_t MyVorbisExtractor::findNextPage(
    223         off_t startOffset, off_t *pageOffset) {
    224     *pageOffset = startOffset;
    225 
    226     for (;;) {
    227         char signature[4];
    228         ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
    229 
    230         if (n < 4) {
    231             *pageOffset = 0;
    232 
    233             return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
    234         }
    235 
    236         if (!memcmp(signature, "OggS", 4)) {
    237             if (*pageOffset > startOffset) {
    238                 LOGV("skipped %ld bytes of junk to reach next frame",
    239                      *pageOffset - startOffset);
    240             }
    241 
    242             return OK;
    243         }
    244 
    245         ++*pageOffset;
    246     }
    247 }
    248 
    249 // Given the offset of the "current" page, find the page immediately preceding
    250 // it (if any) and return its granule position.
    251 // To do this we back up from the "current" page's offset until we find any
    252 // page preceding it and then scan forward to just before the current page.
    253 uint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) {
    254     off_t prevPageOffset = 0;
    255     off_t prevGuess = pageOffset;
    256     for (;;) {
    257         if (prevGuess >= 5000) {
    258             prevGuess -= 5000;
    259         } else {
    260             prevGuess = 0;
    261         }
    262 
    263         LOGV("backing up %ld bytes", pageOffset - prevGuess);
    264 
    265         CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK);
    266 
    267         if (prevPageOffset < pageOffset || prevGuess == 0) {
    268             break;
    269         }
    270     }
    271 
    272     if (prevPageOffset == pageOffset) {
    273         // We did not find a page preceding this one.
    274         return 0;
    275     }
    276 
    277     LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset);
    278 
    279     for (;;) {
    280         Page prevPage;
    281         ssize_t n = readPage(prevPageOffset, &prevPage);
    282 
    283         if (n <= 0) {
    284             return 0;
    285         }
    286 
    287         prevPageOffset += n;
    288 
    289         if (prevPageOffset == pageOffset) {
    290             return prevPage.mGranulePosition;
    291         }
    292     }
    293 }
    294 
    295 status_t MyVorbisExtractor::seekToOffset(off_t offset) {
    296     if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
    297         // Once we know where the actual audio data starts (past the headers)
    298         // don't ever seek to anywhere before that.
    299         offset = mFirstDataOffset;
    300     }
    301 
    302     off_t pageOffset;
    303     status_t err = findNextPage(offset, &pageOffset);
    304 
    305     if (err != OK) {
    306         return err;
    307     }
    308 
    309     // We found the page we wanted to seek to, but we'll also need
    310     // the page preceding it to determine how many valid samples are on
    311     // this page.
    312     mPrevGranulePosition = findPrevGranulePosition(pageOffset);
    313 
    314     mOffset = pageOffset;
    315 
    316     mCurrentPageSize = 0;
    317     mFirstPacketInPage = true;
    318     mCurrentPageSamples = 0;
    319     mCurrentPage.mNumSegments = 0;
    320     mNextLaceIndex = 0;
    321 
    322     // XXX what if new page continues packet from last???
    323 
    324     return OK;
    325 }
    326 
    327 ssize_t MyVorbisExtractor::readPage(off_t offset, Page *page) {
    328     uint8_t header[27];
    329     if (mSource->readAt(offset, header, sizeof(header))
    330             < (ssize_t)sizeof(header)) {
    331         LOGV("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
    332 
    333         return ERROR_IO;
    334     }
    335 
    336     if (memcmp(header, "OggS", 4)) {
    337         return ERROR_MALFORMED;
    338     }
    339 
    340     if (header[4] != 0) {
    341         // Wrong version.
    342 
    343         return ERROR_UNSUPPORTED;
    344     }
    345 
    346     page->mFlags = header[5];
    347 
    348     if (page->mFlags & ~7) {
    349         // Only bits 0-2 are defined in version 0.
    350         return ERROR_MALFORMED;
    351     }
    352 
    353     page->mGranulePosition = U64LE_AT(&header[6]);
    354 
    355 #if 0
    356     printf("granulePosition = %llu (0x%llx)\n",
    357            page->mGranulePosition, page->mGranulePosition);
    358 #endif
    359 
    360     page->mSerialNo = U32LE_AT(&header[14]);
    361     page->mPageNo = U32LE_AT(&header[18]);
    362 
    363     page->mNumSegments = header[26];
    364     if (mSource->readAt(
    365                 offset + sizeof(header), page->mLace, page->mNumSegments)
    366             < (ssize_t)page->mNumSegments) {
    367         return ERROR_IO;
    368     }
    369 
    370     size_t totalSize = 0;;
    371     for (size_t i = 0; i < page->mNumSegments; ++i) {
    372         totalSize += page->mLace[i];
    373     }
    374 
    375 #if 0
    376     String8 tmp;
    377     for (size_t i = 0; i < page->mNumSegments; ++i) {
    378         char x[32];
    379         sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
    380 
    381         tmp.append(x);
    382     }
    383 
    384     LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
    385 #endif
    386 
    387     return sizeof(header) + page->mNumSegments + totalSize;
    388 }
    389 
    390 status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
    391     *out = NULL;
    392 
    393     MediaBuffer *buffer = NULL;
    394     int64_t timeUs = -1;
    395 
    396     for (;;) {
    397         size_t i;
    398         size_t packetSize = 0;
    399         bool gotFullPacket = false;
    400         for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
    401             uint8_t lace = mCurrentPage.mLace[i];
    402 
    403             packetSize += lace;
    404 
    405             if (lace < 255) {
    406                 gotFullPacket = true;
    407                 ++i;
    408                 break;
    409             }
    410         }
    411 
    412         if (mNextLaceIndex < mCurrentPage.mNumSegments) {
    413             off_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
    414             for (size_t j = 0; j < mNextLaceIndex; ++j) {
    415                 dataOffset += mCurrentPage.mLace[j];
    416             }
    417 
    418             size_t fullSize = packetSize;
    419             if (buffer != NULL) {
    420                 fullSize += buffer->range_length();
    421             }
    422             MediaBuffer *tmp = new MediaBuffer(fullSize);
    423             if (buffer != NULL) {
    424                 memcpy(tmp->data(), buffer->data(), buffer->range_length());
    425                 tmp->set_range(0, buffer->range_length());
    426                 buffer->release();
    427             } else {
    428                 // XXX Not only is this not technically the correct time for
    429                 // this packet, we also stamp every packet in this page
    430                 // with the same time. This needs fixing later.
    431 
    432                 if (mVi.rate) {
    433                     // Rate may not have been initialized yet if we're currently
    434                     // reading the configuration packets...
    435                     // Fortunately, the timestamp doesn't matter for those.
    436                     timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
    437                 }
    438                 tmp->set_range(0, 0);
    439             }
    440             buffer = tmp;
    441 
    442             ssize_t n = mSource->readAt(
    443                     dataOffset,
    444                     (uint8_t *)buffer->data() + buffer->range_length(),
    445                     packetSize);
    446 
    447             if (n < (ssize_t)packetSize) {
    448                 LOGV("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
    449                 return ERROR_IO;
    450             }
    451 
    452             buffer->set_range(0, fullSize);
    453 
    454             mNextLaceIndex = i;
    455 
    456             if (gotFullPacket) {
    457                 // We've just read the entire packet.
    458 
    459                 if (timeUs >= 0) {
    460                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    461                 }
    462 
    463                 if (mFirstPacketInPage) {
    464                     buffer->meta_data()->setInt32(
    465                             kKeyValidSamples, mCurrentPageSamples);
    466                     mFirstPacketInPage = false;
    467                 }
    468 
    469                 *out = buffer;
    470 
    471                 return OK;
    472             }
    473 
    474             // fall through, the buffer now contains the start of the packet.
    475         }
    476 
    477         CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
    478 
    479         mOffset += mCurrentPageSize;
    480         ssize_t n = readPage(mOffset, &mCurrentPage);
    481 
    482         if (n <= 0) {
    483             if (buffer) {
    484                 buffer->release();
    485                 buffer = NULL;
    486             }
    487 
    488             LOGV("readPage returned %ld", n);
    489 
    490             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
    491         }
    492 
    493         mCurrentPageSamples =
    494             mCurrentPage.mGranulePosition - mPrevGranulePosition;
    495         mFirstPacketInPage = true;
    496 
    497         mPrevGranulePosition = mCurrentPage.mGranulePosition;
    498 
    499         mCurrentPageSize = n;
    500         mNextLaceIndex = 0;
    501 
    502         if (buffer != NULL) {
    503             if ((mCurrentPage.mFlags & 1) == 0) {
    504                 // This page does not continue the packet, i.e. the packet
    505                 // is already complete.
    506 
    507                 if (timeUs >= 0) {
    508                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    509                 }
    510 
    511                 buffer->meta_data()->setInt32(
    512                         kKeyValidSamples, mCurrentPageSamples);
    513                 mFirstPacketInPage = false;
    514 
    515                 *out = buffer;
    516 
    517                 return OK;
    518             }
    519         }
    520     }
    521 }
    522 
    523 status_t MyVorbisExtractor::init() {
    524     mMeta = new MetaData;
    525     mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
    526 
    527     MediaBuffer *packet;
    528     status_t err;
    529     if ((err = readNextPacket(&packet)) != OK) {
    530         return err;
    531     }
    532     LOGV("read packet of size %d\n", packet->range_length());
    533     err = verifyHeader(packet, 1);
    534     packet->release();
    535     packet = NULL;
    536     if (err != OK) {
    537         return err;
    538     }
    539 
    540     if ((err = readNextPacket(&packet)) != OK) {
    541         return err;
    542     }
    543     LOGV("read packet of size %d\n", packet->range_length());
    544     err = verifyHeader(packet, 3);
    545     packet->release();
    546     packet = NULL;
    547     if (err != OK) {
    548         return err;
    549     }
    550 
    551     if ((err = readNextPacket(&packet)) != OK) {
    552         return err;
    553     }
    554     LOGV("read packet of size %d\n", packet->range_length());
    555     err = verifyHeader(packet, 5);
    556     packet->release();
    557     packet = NULL;
    558     if (err != OK) {
    559         return err;
    560     }
    561 
    562     mFirstDataOffset = mOffset + mCurrentPageSize;
    563 
    564     return OK;
    565 }
    566 
    567 status_t MyVorbisExtractor::verifyHeader(
    568         MediaBuffer *buffer, uint8_t type) {
    569     const uint8_t *data =
    570         (const uint8_t *)buffer->data() + buffer->range_offset();
    571 
    572     size_t size = buffer->range_length();
    573 
    574     if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
    575         return ERROR_MALFORMED;
    576     }
    577 
    578     ogg_buffer buf;
    579     buf.data = (uint8_t *)data;
    580     buf.size = size;
    581     buf.refcount = 1;
    582     buf.ptr.owner = NULL;
    583 
    584     ogg_reference ref;
    585     ref.buffer = &buf;
    586     ref.begin = 0;
    587     ref.length = size;
    588     ref.next = NULL;
    589 
    590     oggpack_buffer bits;
    591     oggpack_readinit(&bits, &ref);
    592 
    593     CHECK_EQ(oggpack_read(&bits, 8), type);
    594     for (size_t i = 0; i < 6; ++i) {
    595         oggpack_read(&bits, 8);  // skip 'vorbis'
    596     }
    597 
    598     switch (type) {
    599         case 1:
    600         {
    601             CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
    602 
    603             mMeta->setData(kKeyVorbisInfo, 0, data, size);
    604             mMeta->setInt32(kKeySampleRate, mVi.rate);
    605             mMeta->setInt32(kKeyChannelCount, mVi.channels);
    606 
    607             LOGV("lower-bitrate = %ld", mVi.bitrate_lower);
    608             LOGV("upper-bitrate = %ld", mVi.bitrate_upper);
    609             LOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
    610             LOGV("window-bitrate = %ld", mVi.bitrate_window);
    611 
    612             off_t size;
    613             if (mSource->getSize(&size) == OK) {
    614                 uint64_t bps = approxBitrate();
    615 
    616                 mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
    617             }
    618             break;
    619         }
    620 
    621         case 3:
    622         {
    623             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
    624                 return ERROR_MALFORMED;
    625             }
    626 
    627             parseFileMetaData();
    628             break;
    629         }
    630 
    631         case 5:
    632         {
    633             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
    634                 return ERROR_MALFORMED;
    635             }
    636 
    637             mMeta->setData(kKeyVorbisBooks, 0, data, size);
    638             break;
    639         }
    640     }
    641 
    642     return OK;
    643 }
    644 
    645 uint64_t MyVorbisExtractor::approxBitrate() {
    646     if (mVi.bitrate_nominal != 0) {
    647         return mVi.bitrate_nominal;
    648     }
    649 
    650     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
    651 }
    652 
    653 void MyVorbisExtractor::parseFileMetaData() {
    654     mFileMeta = new MetaData;
    655     mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
    656 
    657     struct {
    658         const char *const mTag;
    659         uint32_t mKey;
    660     } kMap[] = {
    661         { "TITLE", kKeyTitle },
    662         { "ARTIST", kKeyArtist },
    663         { "ALBUM", kKeyAlbum },
    664         { "COMPOSER", kKeyComposer },
    665         { "GENRE", kKeyGenre },
    666         { "AUTHOR", kKeyAuthor },
    667         { "TRACKNUMBER", kKeyCDTrackNumber },
    668         { "DISCNUMBER", kKeyDiscNumber },
    669         { "DATE", kKeyDate },
    670         { "LYRICIST", kKeyWriter },
    671         { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
    672         { "ANDROID_LOOP", kKeyAutoLoop },
    673     };
    674 
    675     for (int i = 0; i < mVc.comments; ++i) {
    676         const char *comment = mVc.user_comments[i];
    677 
    678         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
    679             size_t tagLen = strlen(kMap[j].mTag);
    680             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
    681                     && comment[tagLen] == '=') {
    682                 if (kMap[j].mKey == kKeyAlbumArt) {
    683                     extractAlbumArt(
    684                             &comment[tagLen + 1],
    685                             mVc.comment_lengths[i] - tagLen - 1);
    686                 } else if (kMap[j].mKey == kKeyAutoLoop) {
    687                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
    688                         mFileMeta->setInt32(kKeyAutoLoop, true);
    689                     }
    690                 } else {
    691                     mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
    692                 }
    693             }
    694         }
    695     }
    696 
    697 #if 0
    698     for (int i = 0; i < mVc.comments; ++i) {
    699         LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
    700     }
    701 #endif
    702 }
    703 
    704 // The returned buffer should be free()d.
    705 static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
    706     *outSize = 0;
    707 
    708     if ((size % 4) != 0) {
    709         return NULL;
    710     }
    711 
    712     size_t n = size;
    713     size_t padding = 0;
    714     if (n >= 1 && s[n - 1] == '=') {
    715         padding = 1;
    716 
    717         if (n >= 2 && s[n - 2] == '=') {
    718             padding = 2;
    719         }
    720     }
    721 
    722     size_t outLen = 3 * size / 4 - padding;
    723 
    724     *outSize = outLen;
    725 
    726     void *buffer = malloc(outLen);
    727 
    728     uint8_t *out = (uint8_t *)buffer;
    729     size_t j = 0;
    730     uint32_t accum = 0;
    731     for (size_t i = 0; i < n; ++i) {
    732         char c = s[i];
    733         unsigned value;
    734         if (c >= 'A' && c <= 'Z') {
    735             value = c - 'A';
    736         } else if (c >= 'a' && c <= 'z') {
    737             value = 26 + c - 'a';
    738         } else if (c >= '0' && c <= '9') {
    739             value = 52 + c - '0';
    740         } else if (c == '+') {
    741             value = 62;
    742         } else if (c == '/') {
    743             value = 63;
    744         } else if (c != '=') {
    745             return NULL;
    746         } else {
    747             if (i < n - padding) {
    748                 return NULL;
    749             }
    750 
    751             value = 0;
    752         }
    753 
    754         accum = (accum << 6) | value;
    755 
    756         if (((i + 1) % 4) == 0) {
    757             out[j++] = (accum >> 16);
    758 
    759             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    760             if (j < outLen) { out[j++] = accum & 0xff; }
    761 
    762             accum = 0;
    763         }
    764     }
    765 
    766     return (uint8_t *)buffer;
    767 }
    768 
    769 void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
    770     LOGV("extractAlbumArt from '%s'", (const char *)data);
    771 
    772     size_t flacSize;
    773     uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
    774 
    775     if (flac == NULL) {
    776         LOGE("malformed base64 encoded data.");
    777         return;
    778     }
    779 
    780     LOGV("got flac of size %d", flacSize);
    781 
    782     uint32_t picType;
    783     uint32_t typeLen;
    784     uint32_t descLen;
    785     uint32_t dataLen;
    786     char type[128];
    787 
    788     if (flacSize < 8) {
    789         goto exit;
    790     }
    791 
    792     picType = U32_AT(flac);
    793 
    794     if (picType != 3) {
    795         // This is not a front cover.
    796         goto exit;
    797     }
    798 
    799     typeLen = U32_AT(&flac[4]);
    800     if (typeLen + 1 > sizeof(type)) {
    801         goto exit;
    802     }
    803 
    804     if (flacSize < 8 + typeLen) {
    805         goto exit;
    806     }
    807 
    808     memcpy(type, &flac[8], typeLen);
    809     type[typeLen] = '\0';
    810 
    811     LOGV("picType = %d, type = '%s'", picType, type);
    812 
    813     if (!strcmp(type, "-->")) {
    814         // This is not inline cover art, but an external url instead.
    815         goto exit;
    816     }
    817 
    818     descLen = U32_AT(&flac[8 + typeLen]);
    819 
    820     if (flacSize < 32 + typeLen + descLen) {
    821         goto exit;
    822     }
    823 
    824     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
    825 
    826     if (flacSize < 32 + typeLen + descLen + dataLen) {
    827         goto exit;
    828     }
    829 
    830     LOGV("got image data, %d trailing bytes",
    831          flacSize - 32 - typeLen - descLen - dataLen);
    832 
    833     mFileMeta->setData(
    834             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
    835 
    836     mFileMeta->setCString(kKeyAlbumArtMIME, type);
    837 
    838 exit:
    839     free(flac);
    840     flac = NULL;
    841 }
    842 
    843 ////////////////////////////////////////////////////////////////////////////////
    844 
    845 OggExtractor::OggExtractor(const sp<DataSource> &source)
    846     : mDataSource(source),
    847       mInitCheck(NO_INIT),
    848       mImpl(NULL) {
    849     mImpl = new MyVorbisExtractor(mDataSource);
    850     mInitCheck = mImpl->seekToOffset(0);
    851 
    852     if (mInitCheck == OK) {
    853         mInitCheck = mImpl->init();
    854     }
    855 }
    856 
    857 OggExtractor::~OggExtractor() {
    858     delete mImpl;
    859     mImpl = NULL;
    860 }
    861 
    862 size_t OggExtractor::countTracks() {
    863     return mInitCheck != OK ? 0 : 1;
    864 }
    865 
    866 sp<MediaSource> OggExtractor::getTrack(size_t index) {
    867     if (index >= 1) {
    868         return NULL;
    869     }
    870 
    871     return new OggSource(this);
    872 }
    873 
    874 sp<MetaData> OggExtractor::getTrackMetaData(
    875         size_t index, uint32_t flags) {
    876     if (index >= 1) {
    877         return NULL;
    878     }
    879 
    880     return mImpl->getFormat();
    881 }
    882 
    883 sp<MetaData> OggExtractor::getMetaData() {
    884     return mImpl->getFileMetaData();
    885 }
    886 
    887 bool SniffOgg(
    888         const sp<DataSource> &source, String8 *mimeType, float *confidence,
    889         sp<AMessage> *) {
    890     char tmp[4];
    891     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
    892         return false;
    893     }
    894 
    895     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
    896     *confidence = 0.2f;
    897 
    898     return true;
    899 }
    900 
    901 }  // namespace android
    902