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/foundation/ADebug.h>
     25 #include <media/stagefright/DataSource.h>
     26 #include <media/stagefright/MediaBuffer.h>
     27 #include <media/stagefright/MediaBufferGroup.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 seekToTime(int64_t timeUs);
     77     status_t seekToOffset(off64_t offset);
     78     status_t readNextPacket(MediaBuffer **buffer);
     79 
     80     status_t init();
     81 
     82     sp<MetaData> getFileMetaData() { return mFileMeta; }
     83 
     84 private:
     85     struct Page {
     86         uint64_t mGranulePosition;
     87         uint32_t mSerialNo;
     88         uint32_t mPageNo;
     89         uint8_t mFlags;
     90         uint8_t mNumSegments;
     91         uint8_t mLace[255];
     92     };
     93 
     94     struct TOCEntry {
     95         off64_t mPageOffset;
     96         int64_t mTimeUs;
     97     };
     98 
     99     sp<DataSource> mSource;
    100     off64_t mOffset;
    101     Page mCurrentPage;
    102     uint64_t mPrevGranulePosition;
    103     size_t mCurrentPageSize;
    104     bool mFirstPacketInPage;
    105     uint64_t mCurrentPageSamples;
    106     size_t mNextLaceIndex;
    107 
    108     off64_t mFirstDataOffset;
    109 
    110     vorbis_info mVi;
    111     vorbis_comment mVc;
    112 
    113     sp<MetaData> mMeta;
    114     sp<MetaData> mFileMeta;
    115 
    116     Vector<TOCEntry> mTableOfContents;
    117 
    118     ssize_t readPage(off64_t offset, Page *page);
    119     status_t findNextPage(off64_t startOffset, off64_t *pageOffset);
    120 
    121     status_t verifyHeader(
    122             MediaBuffer *buffer, uint8_t type);
    123 
    124     void parseFileMetaData();
    125 
    126     status_t findPrevGranulePosition(off64_t pageOffset, uint64_t *granulePos);
    127 
    128     void buildTableOfContents();
    129 
    130     MyVorbisExtractor(const MyVorbisExtractor &);
    131     MyVorbisExtractor &operator=(const MyVorbisExtractor &);
    132 };
    133 
    134 static void extractAlbumArt(
    135         const sp<MetaData> &fileMeta, const void *data, size_t size);
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 
    139 OggSource::OggSource(const sp<OggExtractor> &extractor)
    140     : mExtractor(extractor),
    141       mStarted(false) {
    142 }
    143 
    144 OggSource::~OggSource() {
    145     if (mStarted) {
    146         stop();
    147     }
    148 }
    149 
    150 sp<MetaData> OggSource::getFormat() {
    151     return mExtractor->mImpl->getFormat();
    152 }
    153 
    154 status_t OggSource::start(MetaData *params) {
    155     if (mStarted) {
    156         return INVALID_OPERATION;
    157     }
    158 
    159     mStarted = true;
    160 
    161     return OK;
    162 }
    163 
    164 status_t OggSource::stop() {
    165     mStarted = false;
    166 
    167     return OK;
    168 }
    169 
    170 status_t OggSource::read(
    171         MediaBuffer **out, const ReadOptions *options) {
    172     *out = NULL;
    173 
    174     int64_t seekTimeUs;
    175     ReadOptions::SeekMode mode;
    176     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
    177         if (mExtractor->mImpl->seekToTime(seekTimeUs) != OK) {
    178             return ERROR_END_OF_STREAM;
    179         }
    180     }
    181 
    182     MediaBuffer *packet;
    183     status_t err = mExtractor->mImpl->readNextPacket(&packet);
    184 
    185     if (err != OK) {
    186         return err;
    187     }
    188 
    189 #if 0
    190     int64_t timeUs;
    191     if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
    192         ALOGI("found time = %lld us", timeUs);
    193     } else {
    194         ALOGI("NO time");
    195     }
    196 #endif
    197 
    198     packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
    199 
    200     *out = packet;
    201 
    202     return OK;
    203 }
    204 
    205 ////////////////////////////////////////////////////////////////////////////////
    206 
    207 MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
    208     : mSource(source),
    209       mOffset(0),
    210       mPrevGranulePosition(0),
    211       mCurrentPageSize(0),
    212       mFirstPacketInPage(true),
    213       mCurrentPageSamples(0),
    214       mNextLaceIndex(0),
    215       mFirstDataOffset(-1) {
    216     mCurrentPage.mNumSegments = 0;
    217 
    218     vorbis_info_init(&mVi);
    219     vorbis_comment_init(&mVc);
    220 }
    221 
    222 MyVorbisExtractor::~MyVorbisExtractor() {
    223     vorbis_comment_clear(&mVc);
    224     vorbis_info_clear(&mVi);
    225 }
    226 
    227 sp<MetaData> MyVorbisExtractor::getFormat() const {
    228     return mMeta;
    229 }
    230 
    231 status_t MyVorbisExtractor::findNextPage(
    232         off64_t startOffset, off64_t *pageOffset) {
    233     *pageOffset = startOffset;
    234 
    235     for (;;) {
    236         char signature[4];
    237         ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
    238 
    239         if (n < 4) {
    240             *pageOffset = 0;
    241 
    242             return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
    243         }
    244 
    245         if (!memcmp(signature, "OggS", 4)) {
    246             if (*pageOffset > startOffset) {
    247                 ALOGV("skipped %lld bytes of junk to reach next frame",
    248                      *pageOffset - startOffset);
    249             }
    250 
    251             return OK;
    252         }
    253 
    254         ++*pageOffset;
    255     }
    256 }
    257 
    258 // Given the offset of the "current" page, find the page immediately preceding
    259 // it (if any) and return its granule position.
    260 // To do this we back up from the "current" page's offset until we find any
    261 // page preceding it and then scan forward to just before the current page.
    262 status_t MyVorbisExtractor::findPrevGranulePosition(
    263         off64_t pageOffset, uint64_t *granulePos) {
    264     *granulePos = 0;
    265 
    266     off64_t prevPageOffset = 0;
    267     off64_t prevGuess = pageOffset;
    268     for (;;) {
    269         if (prevGuess >= 5000) {
    270             prevGuess -= 5000;
    271         } else {
    272             prevGuess = 0;
    273         }
    274 
    275         ALOGV("backing up %lld bytes", pageOffset - prevGuess);
    276 
    277         status_t err = findNextPage(prevGuess, &prevPageOffset);
    278         if (err != OK) {
    279             return err;
    280         }
    281 
    282         if (prevPageOffset < pageOffset || prevGuess == 0) {
    283             break;
    284         }
    285     }
    286 
    287     if (prevPageOffset == pageOffset) {
    288         // We did not find a page preceding this one.
    289         return UNKNOWN_ERROR;
    290     }
    291 
    292     ALOGV("prevPageOffset at %lld, pageOffset at %lld",
    293          prevPageOffset, pageOffset);
    294 
    295     for (;;) {
    296         Page prevPage;
    297         ssize_t n = readPage(prevPageOffset, &prevPage);
    298 
    299         if (n <= 0) {
    300             return (status_t)n;
    301         }
    302 
    303         prevPageOffset += n;
    304 
    305         if (prevPageOffset == pageOffset) {
    306             *granulePos = prevPage.mGranulePosition;
    307             return OK;
    308         }
    309     }
    310 }
    311 
    312 status_t MyVorbisExtractor::seekToTime(int64_t timeUs) {
    313     if (mTableOfContents.isEmpty()) {
    314         // Perform approximate seeking based on avg. bitrate.
    315 
    316         off64_t pos = timeUs * approxBitrate() / 8000000ll;
    317 
    318         ALOGV("seeking to offset %lld", pos);
    319         return seekToOffset(pos);
    320     }
    321 
    322     size_t left = 0;
    323     size_t right = mTableOfContents.size();
    324     while (left < right) {
    325         size_t center = left / 2 + right / 2 + (left & right & 1);
    326 
    327         const TOCEntry &entry = mTableOfContents.itemAt(center);
    328 
    329         if (timeUs < entry.mTimeUs) {
    330             right = center;
    331         } else if (timeUs > entry.mTimeUs) {
    332             left = center + 1;
    333         } else {
    334             left = right = center;
    335             break;
    336         }
    337     }
    338 
    339     const TOCEntry &entry = mTableOfContents.itemAt(left);
    340 
    341     ALOGV("seeking to entry %d / %d at offset %lld",
    342          left, mTableOfContents.size(), entry.mPageOffset);
    343 
    344     return seekToOffset(entry.mPageOffset);
    345 }
    346 
    347 status_t MyVorbisExtractor::seekToOffset(off64_t offset) {
    348     if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
    349         // Once we know where the actual audio data starts (past the headers)
    350         // don't ever seek to anywhere before that.
    351         offset = mFirstDataOffset;
    352     }
    353 
    354     off64_t pageOffset;
    355     status_t err = findNextPage(offset, &pageOffset);
    356 
    357     if (err != OK) {
    358         return err;
    359     }
    360 
    361     // We found the page we wanted to seek to, but we'll also need
    362     // the page preceding it to determine how many valid samples are on
    363     // this page.
    364     findPrevGranulePosition(pageOffset, &mPrevGranulePosition);
    365 
    366     mOffset = pageOffset;
    367 
    368     mCurrentPageSize = 0;
    369     mFirstPacketInPage = true;
    370     mCurrentPageSamples = 0;
    371     mCurrentPage.mNumSegments = 0;
    372     mNextLaceIndex = 0;
    373 
    374     // XXX what if new page continues packet from last???
    375 
    376     return OK;
    377 }
    378 
    379 ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) {
    380     uint8_t header[27];
    381     ssize_t n;
    382     if ((n = mSource->readAt(offset, header, sizeof(header)))
    383             < (ssize_t)sizeof(header)) {
    384         ALOGV("failed to read %d bytes at offset 0x%016llx, got %ld bytes",
    385              sizeof(header), offset, n);
    386 
    387         if (n < 0) {
    388             return n;
    389         } else if (n == 0) {
    390             return ERROR_END_OF_STREAM;
    391         } else {
    392             return ERROR_IO;
    393         }
    394     }
    395 
    396     if (memcmp(header, "OggS", 4)) {
    397         return ERROR_MALFORMED;
    398     }
    399 
    400     if (header[4] != 0) {
    401         // Wrong version.
    402 
    403         return ERROR_UNSUPPORTED;
    404     }
    405 
    406     page->mFlags = header[5];
    407 
    408     if (page->mFlags & ~7) {
    409         // Only bits 0-2 are defined in version 0.
    410         return ERROR_MALFORMED;
    411     }
    412 
    413     page->mGranulePosition = U64LE_AT(&header[6]);
    414 
    415 #if 0
    416     printf("granulePosition = %llu (0x%llx)\n",
    417            page->mGranulePosition, page->mGranulePosition);
    418 #endif
    419 
    420     page->mSerialNo = U32LE_AT(&header[14]);
    421     page->mPageNo = U32LE_AT(&header[18]);
    422 
    423     page->mNumSegments = header[26];
    424     if (mSource->readAt(
    425                 offset + sizeof(header), page->mLace, page->mNumSegments)
    426             < (ssize_t)page->mNumSegments) {
    427         return ERROR_IO;
    428     }
    429 
    430     size_t totalSize = 0;;
    431     for (size_t i = 0; i < page->mNumSegments; ++i) {
    432         totalSize += page->mLace[i];
    433     }
    434 
    435 #if 0
    436     String8 tmp;
    437     for (size_t i = 0; i < page->mNumSegments; ++i) {
    438         char x[32];
    439         sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
    440 
    441         tmp.append(x);
    442     }
    443 
    444     ALOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
    445 #endif
    446 
    447     return sizeof(header) + page->mNumSegments + totalSize;
    448 }
    449 
    450 status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
    451     *out = NULL;
    452 
    453     MediaBuffer *buffer = NULL;
    454     int64_t timeUs = -1;
    455 
    456     for (;;) {
    457         size_t i;
    458         size_t packetSize = 0;
    459         bool gotFullPacket = false;
    460         for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
    461             uint8_t lace = mCurrentPage.mLace[i];
    462 
    463             packetSize += lace;
    464 
    465             if (lace < 255) {
    466                 gotFullPacket = true;
    467                 ++i;
    468                 break;
    469             }
    470         }
    471 
    472         if (mNextLaceIndex < mCurrentPage.mNumSegments) {
    473             off64_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
    474             for (size_t j = 0; j < mNextLaceIndex; ++j) {
    475                 dataOffset += mCurrentPage.mLace[j];
    476             }
    477 
    478             size_t fullSize = packetSize;
    479             if (buffer != NULL) {
    480                 fullSize += buffer->range_length();
    481             }
    482             MediaBuffer *tmp = new MediaBuffer(fullSize);
    483             if (buffer != NULL) {
    484                 memcpy(tmp->data(), buffer->data(), buffer->range_length());
    485                 tmp->set_range(0, buffer->range_length());
    486                 buffer->release();
    487             } else {
    488                 // XXX Not only is this not technically the correct time for
    489                 // this packet, we also stamp every packet in this page
    490                 // with the same time. This needs fixing later.
    491 
    492                 if (mVi.rate) {
    493                     // Rate may not have been initialized yet if we're currently
    494                     // reading the configuration packets...
    495                     // Fortunately, the timestamp doesn't matter for those.
    496                     timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
    497                 }
    498                 tmp->set_range(0, 0);
    499             }
    500             buffer = tmp;
    501 
    502             ssize_t n = mSource->readAt(
    503                     dataOffset,
    504                     (uint8_t *)buffer->data() + buffer->range_length(),
    505                     packetSize);
    506 
    507             if (n < (ssize_t)packetSize) {
    508                 ALOGV("failed to read %d bytes at 0x%016llx, got %ld bytes",
    509                      packetSize, dataOffset, n);
    510                 return ERROR_IO;
    511             }
    512 
    513             buffer->set_range(0, fullSize);
    514 
    515             mNextLaceIndex = i;
    516 
    517             if (gotFullPacket) {
    518                 // We've just read the entire packet.
    519 
    520                 if (timeUs >= 0) {
    521                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    522                 }
    523 
    524                 if (mFirstPacketInPage) {
    525                     buffer->meta_data()->setInt32(
    526                             kKeyValidSamples, mCurrentPageSamples);
    527                     mFirstPacketInPage = false;
    528                 }
    529 
    530                 *out = buffer;
    531 
    532                 return OK;
    533             }
    534 
    535             // fall through, the buffer now contains the start of the packet.
    536         }
    537 
    538         CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
    539 
    540         mOffset += mCurrentPageSize;
    541         ssize_t n = readPage(mOffset, &mCurrentPage);
    542 
    543         if (n <= 0) {
    544             if (buffer) {
    545                 buffer->release();
    546                 buffer = NULL;
    547             }
    548 
    549             ALOGV("readPage returned %ld", n);
    550 
    551             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
    552         }
    553 
    554         mCurrentPageSamples =
    555             mCurrentPage.mGranulePosition - mPrevGranulePosition;
    556         mFirstPacketInPage = true;
    557 
    558         mPrevGranulePosition = mCurrentPage.mGranulePosition;
    559 
    560         mCurrentPageSize = n;
    561         mNextLaceIndex = 0;
    562 
    563         if (buffer != NULL) {
    564             if ((mCurrentPage.mFlags & 1) == 0) {
    565                 // This page does not continue the packet, i.e. the packet
    566                 // is already complete.
    567 
    568                 if (timeUs >= 0) {
    569                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    570                 }
    571 
    572                 buffer->meta_data()->setInt32(
    573                         kKeyValidSamples, mCurrentPageSamples);
    574                 mFirstPacketInPage = false;
    575 
    576                 *out = buffer;
    577 
    578                 return OK;
    579             }
    580         }
    581     }
    582 }
    583 
    584 status_t MyVorbisExtractor::init() {
    585     mMeta = new MetaData;
    586     mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
    587 
    588     MediaBuffer *packet;
    589     status_t err;
    590     if ((err = readNextPacket(&packet)) != OK) {
    591         return err;
    592     }
    593     ALOGV("read packet of size %d\n", packet->range_length());
    594     err = verifyHeader(packet, 1);
    595     packet->release();
    596     packet = NULL;
    597     if (err != OK) {
    598         return err;
    599     }
    600 
    601     if ((err = readNextPacket(&packet)) != OK) {
    602         return err;
    603     }
    604     ALOGV("read packet of size %d\n", packet->range_length());
    605     err = verifyHeader(packet, 3);
    606     packet->release();
    607     packet = NULL;
    608     if (err != OK) {
    609         return err;
    610     }
    611 
    612     if ((err = readNextPacket(&packet)) != OK) {
    613         return err;
    614     }
    615     ALOGV("read packet of size %d\n", packet->range_length());
    616     err = verifyHeader(packet, 5);
    617     packet->release();
    618     packet = NULL;
    619     if (err != OK) {
    620         return err;
    621     }
    622 
    623     mFirstDataOffset = mOffset + mCurrentPageSize;
    624 
    625     off64_t size;
    626     uint64_t lastGranulePosition;
    627     if (!(mSource->flags() & DataSource::kIsCachingDataSource)
    628             && mSource->getSize(&size) == OK
    629             && findPrevGranulePosition(size, &lastGranulePosition) == OK) {
    630         // Let's assume it's cheap to seek to the end.
    631         // The granule position of the final page in the stream will
    632         // give us the exact duration of the content, something that
    633         // we can only approximate using avg. bitrate if seeking to
    634         // the end is too expensive or impossible (live streaming).
    635 
    636         int64_t durationUs = lastGranulePosition * 1000000ll / mVi.rate;
    637 
    638         mMeta->setInt64(kKeyDuration, durationUs);
    639 
    640         buildTableOfContents();
    641     }
    642 
    643     return OK;
    644 }
    645 
    646 void MyVorbisExtractor::buildTableOfContents() {
    647     off64_t offset = mFirstDataOffset;
    648     Page page;
    649     ssize_t pageSize;
    650     while ((pageSize = readPage(offset, &page)) > 0) {
    651         mTableOfContents.push();
    652 
    653         TOCEntry &entry =
    654             mTableOfContents.editItemAt(mTableOfContents.size() - 1);
    655 
    656         entry.mPageOffset = offset;
    657         entry.mTimeUs = page.mGranulePosition * 1000000ll / mVi.rate;
    658 
    659         offset += (size_t)pageSize;
    660     }
    661 
    662     // Limit the maximum amount of RAM we spend on the table of contents,
    663     // if necessary thin out the table evenly to trim it down to maximum
    664     // size.
    665 
    666     static const size_t kMaxTOCSize = 8192;
    667     static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry);
    668 
    669     size_t numerator = mTableOfContents.size();
    670 
    671     if (numerator > kMaxNumTOCEntries) {
    672         size_t denom = numerator - kMaxNumTOCEntries;
    673 
    674         size_t accum = 0;
    675         for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
    676             accum += denom;
    677             if (accum >= numerator) {
    678                 mTableOfContents.removeAt(i);
    679                 accum -= numerator;
    680             }
    681         }
    682     }
    683 }
    684 
    685 status_t MyVorbisExtractor::verifyHeader(
    686         MediaBuffer *buffer, uint8_t type) {
    687     const uint8_t *data =
    688         (const uint8_t *)buffer->data() + buffer->range_offset();
    689 
    690     size_t size = buffer->range_length();
    691 
    692     if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
    693         return ERROR_MALFORMED;
    694     }
    695 
    696     ogg_buffer buf;
    697     buf.data = (uint8_t *)data;
    698     buf.size = size;
    699     buf.refcount = 1;
    700     buf.ptr.owner = NULL;
    701 
    702     ogg_reference ref;
    703     ref.buffer = &buf;
    704     ref.begin = 0;
    705     ref.length = size;
    706     ref.next = NULL;
    707 
    708     oggpack_buffer bits;
    709     oggpack_readinit(&bits, &ref);
    710 
    711     CHECK_EQ(oggpack_read(&bits, 8), type);
    712     for (size_t i = 0; i < 6; ++i) {
    713         oggpack_read(&bits, 8);  // skip 'vorbis'
    714     }
    715 
    716     switch (type) {
    717         case 1:
    718         {
    719             CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
    720 
    721             mMeta->setData(kKeyVorbisInfo, 0, data, size);
    722             mMeta->setInt32(kKeySampleRate, mVi.rate);
    723             mMeta->setInt32(kKeyChannelCount, mVi.channels);
    724 
    725             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
    726             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
    727             ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
    728             ALOGV("window-bitrate = %ld", mVi.bitrate_window);
    729 
    730             off64_t size;
    731             if (mSource->getSize(&size) == OK) {
    732                 uint64_t bps = approxBitrate();
    733                 if (bps != 0) {
    734                     mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
    735                 }
    736             }
    737             break;
    738         }
    739 
    740         case 3:
    741         {
    742             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
    743                 return ERROR_MALFORMED;
    744             }
    745 
    746             parseFileMetaData();
    747             break;
    748         }
    749 
    750         case 5:
    751         {
    752             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
    753                 return ERROR_MALFORMED;
    754             }
    755 
    756             mMeta->setData(kKeyVorbisBooks, 0, data, size);
    757             break;
    758         }
    759     }
    760 
    761     return OK;
    762 }
    763 
    764 uint64_t MyVorbisExtractor::approxBitrate() {
    765     if (mVi.bitrate_nominal != 0) {
    766         return mVi.bitrate_nominal;
    767     }
    768 
    769     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
    770 }
    771 
    772 void MyVorbisExtractor::parseFileMetaData() {
    773     mFileMeta = new MetaData;
    774     mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
    775 
    776     for (int i = 0; i < mVc.comments; ++i) {
    777         const char *comment = mVc.user_comments[i];
    778         size_t commentLength = mVc.comment_lengths[i];
    779         parseVorbisComment(mFileMeta, comment, commentLength);
    780         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
    781     }
    782 }
    783 
    784 void parseVorbisComment(
    785         const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
    786 {
    787     struct {
    788         const char *const mTag;
    789         uint32_t mKey;
    790     } kMap[] = {
    791         { "TITLE", kKeyTitle },
    792         { "ARTIST", kKeyArtist },
    793         { "ALBUMARTIST", kKeyAlbumArtist },
    794         { "ALBUM ARTIST", kKeyAlbumArtist },
    795         { "COMPILATION", kKeyCompilation },
    796         { "ALBUM", kKeyAlbum },
    797         { "COMPOSER", kKeyComposer },
    798         { "GENRE", kKeyGenre },
    799         { "AUTHOR", kKeyAuthor },
    800         { "TRACKNUMBER", kKeyCDTrackNumber },
    801         { "DISCNUMBER", kKeyDiscNumber },
    802         { "DATE", kKeyDate },
    803         { "LYRICIST", kKeyWriter },
    804         { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
    805         { "ANDROID_LOOP", kKeyAutoLoop },
    806     };
    807 
    808         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
    809             size_t tagLen = strlen(kMap[j].mTag);
    810             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
    811                     && comment[tagLen] == '=') {
    812                 if (kMap[j].mKey == kKeyAlbumArt) {
    813                     extractAlbumArt(
    814                             fileMeta,
    815                             &comment[tagLen + 1],
    816                             commentLength - tagLen - 1);
    817                 } else if (kMap[j].mKey == kKeyAutoLoop) {
    818                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
    819                         fileMeta->setInt32(kKeyAutoLoop, true);
    820                     }
    821                 } else {
    822                     fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
    823                 }
    824             }
    825         }
    826 
    827 }
    828 
    829 // The returned buffer should be free()d.
    830 static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
    831     *outSize = 0;
    832 
    833     if ((size % 4) != 0) {
    834         return NULL;
    835     }
    836 
    837     size_t n = size;
    838     size_t padding = 0;
    839     if (n >= 1 && s[n - 1] == '=') {
    840         padding = 1;
    841 
    842         if (n >= 2 && s[n - 2] == '=') {
    843             padding = 2;
    844         }
    845     }
    846 
    847     size_t outLen = 3 * size / 4 - padding;
    848 
    849     *outSize = outLen;
    850 
    851     void *buffer = malloc(outLen);
    852 
    853     uint8_t *out = (uint8_t *)buffer;
    854     size_t j = 0;
    855     uint32_t accum = 0;
    856     for (size_t i = 0; i < n; ++i) {
    857         char c = s[i];
    858         unsigned value;
    859         if (c >= 'A' && c <= 'Z') {
    860             value = c - 'A';
    861         } else if (c >= 'a' && c <= 'z') {
    862             value = 26 + c - 'a';
    863         } else if (c >= '0' && c <= '9') {
    864             value = 52 + c - '0';
    865         } else if (c == '+') {
    866             value = 62;
    867         } else if (c == '/') {
    868             value = 63;
    869         } else if (c != '=') {
    870             return NULL;
    871         } else {
    872             if (i < n - padding) {
    873                 return NULL;
    874             }
    875 
    876             value = 0;
    877         }
    878 
    879         accum = (accum << 6) | value;
    880 
    881         if (((i + 1) % 4) == 0) {
    882             out[j++] = (accum >> 16);
    883 
    884             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    885             if (j < outLen) { out[j++] = accum & 0xff; }
    886 
    887             accum = 0;
    888         }
    889     }
    890 
    891     return (uint8_t *)buffer;
    892 }
    893 
    894 static void extractAlbumArt(
    895         const sp<MetaData> &fileMeta, const void *data, size_t size) {
    896     ALOGV("extractAlbumArt from '%s'", (const char *)data);
    897 
    898     size_t flacSize;
    899     uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
    900 
    901     if (flac == NULL) {
    902         ALOGE("malformed base64 encoded data.");
    903         return;
    904     }
    905 
    906     ALOGV("got flac of size %d", flacSize);
    907 
    908     uint32_t picType;
    909     uint32_t typeLen;
    910     uint32_t descLen;
    911     uint32_t dataLen;
    912     char type[128];
    913 
    914     if (flacSize < 8) {
    915         goto exit;
    916     }
    917 
    918     picType = U32_AT(flac);
    919 
    920     if (picType != 3) {
    921         // This is not a front cover.
    922         goto exit;
    923     }
    924 
    925     typeLen = U32_AT(&flac[4]);
    926     if (typeLen + 1 > sizeof(type)) {
    927         goto exit;
    928     }
    929 
    930     if (flacSize < 8 + typeLen) {
    931         goto exit;
    932     }
    933 
    934     memcpy(type, &flac[8], typeLen);
    935     type[typeLen] = '\0';
    936 
    937     ALOGV("picType = %d, type = '%s'", picType, type);
    938 
    939     if (!strcmp(type, "-->")) {
    940         // This is not inline cover art, but an external url instead.
    941         goto exit;
    942     }
    943 
    944     descLen = U32_AT(&flac[8 + typeLen]);
    945 
    946     if (flacSize < 32 + typeLen + descLen) {
    947         goto exit;
    948     }
    949 
    950     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
    951 
    952     if (flacSize < 32 + typeLen + descLen + dataLen) {
    953         goto exit;
    954     }
    955 
    956     ALOGV("got image data, %d trailing bytes",
    957          flacSize - 32 - typeLen - descLen - dataLen);
    958 
    959     fileMeta->setData(
    960             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
    961 
    962     fileMeta->setCString(kKeyAlbumArtMIME, type);
    963 
    964 exit:
    965     free(flac);
    966     flac = NULL;
    967 }
    968 
    969 ////////////////////////////////////////////////////////////////////////////////
    970 
    971 OggExtractor::OggExtractor(const sp<DataSource> &source)
    972     : mDataSource(source),
    973       mInitCheck(NO_INIT),
    974       mImpl(NULL) {
    975     mImpl = new MyVorbisExtractor(mDataSource);
    976     mInitCheck = mImpl->seekToOffset(0);
    977 
    978     if (mInitCheck == OK) {
    979         mInitCheck = mImpl->init();
    980     }
    981 }
    982 
    983 OggExtractor::~OggExtractor() {
    984     delete mImpl;
    985     mImpl = NULL;
    986 }
    987 
    988 size_t OggExtractor::countTracks() {
    989     return mInitCheck != OK ? 0 : 1;
    990 }
    991 
    992 sp<MediaSource> OggExtractor::getTrack(size_t index) {
    993     if (index >= 1) {
    994         return NULL;
    995     }
    996 
    997     return new OggSource(this);
    998 }
    999 
   1000 sp<MetaData> OggExtractor::getTrackMetaData(
   1001         size_t index, uint32_t flags) {
   1002     if (index >= 1) {
   1003         return NULL;
   1004     }
   1005 
   1006     return mImpl->getFormat();
   1007 }
   1008 
   1009 sp<MetaData> OggExtractor::getMetaData() {
   1010     return mImpl->getFileMetaData();
   1011 }
   1012 
   1013 bool SniffOgg(
   1014         const sp<DataSource> &source, String8 *mimeType, float *confidence,
   1015         sp<AMessage> *) {
   1016     char tmp[4];
   1017     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
   1018         return false;
   1019     }
   1020 
   1021     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
   1022     *confidence = 0.2f;
   1023 
   1024     return true;
   1025 }
   1026 
   1027 }  // namespace android
   1028