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_plus_one = mTableOfContents.size();
    324     while (left < right_plus_one) {
    325         size_t center = left + (right_plus_one - left) / 2;
    326 
    327         const TOCEntry &entry = mTableOfContents.itemAt(center);
    328 
    329         if (timeUs < entry.mTimeUs) {
    330             right_plus_one = center;
    331         } else if (timeUs > entry.mTimeUs) {
    332             left = center + 1;
    333         } else {
    334             left = center;
    335             break;
    336         }
    337     }
    338 
    339     if (left == mTableOfContents.size()) {
    340         --left;
    341     }
    342 
    343     const TOCEntry &entry = mTableOfContents.itemAt(left);
    344 
    345     ALOGV("seeking to entry %zu / %zu at offset %lld",
    346          left, mTableOfContents.size(), entry.mPageOffset);
    347 
    348     return seekToOffset(entry.mPageOffset);
    349 }
    350 
    351 status_t MyVorbisExtractor::seekToOffset(off64_t offset) {
    352     if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
    353         // Once we know where the actual audio data starts (past the headers)
    354         // don't ever seek to anywhere before that.
    355         offset = mFirstDataOffset;
    356     }
    357 
    358     off64_t pageOffset;
    359     status_t err = findNextPage(offset, &pageOffset);
    360 
    361     if (err != OK) {
    362         return err;
    363     }
    364 
    365     // We found the page we wanted to seek to, but we'll also need
    366     // the page preceding it to determine how many valid samples are on
    367     // this page.
    368     findPrevGranulePosition(pageOffset, &mPrevGranulePosition);
    369 
    370     mOffset = pageOffset;
    371 
    372     mCurrentPageSize = 0;
    373     mFirstPacketInPage = true;
    374     mCurrentPageSamples = 0;
    375     mCurrentPage.mNumSegments = 0;
    376     mNextLaceIndex = 0;
    377 
    378     // XXX what if new page continues packet from last???
    379 
    380     return OK;
    381 }
    382 
    383 ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) {
    384     uint8_t header[27];
    385     ssize_t n;
    386     if ((n = mSource->readAt(offset, header, sizeof(header)))
    387             < (ssize_t)sizeof(header)) {
    388         ALOGV("failed to read %zu bytes at offset 0x%016llx, got %zd bytes",
    389              sizeof(header), offset, n);
    390 
    391         if (n < 0) {
    392             return n;
    393         } else if (n == 0) {
    394             return ERROR_END_OF_STREAM;
    395         } else {
    396             return ERROR_IO;
    397         }
    398     }
    399 
    400     if (memcmp(header, "OggS", 4)) {
    401         return ERROR_MALFORMED;
    402     }
    403 
    404     if (header[4] != 0) {
    405         // Wrong version.
    406 
    407         return ERROR_UNSUPPORTED;
    408     }
    409 
    410     page->mFlags = header[5];
    411 
    412     if (page->mFlags & ~7) {
    413         // Only bits 0-2 are defined in version 0.
    414         return ERROR_MALFORMED;
    415     }
    416 
    417     page->mGranulePosition = U64LE_AT(&header[6]);
    418 
    419 #if 0
    420     printf("granulePosition = %llu (0x%llx)\n",
    421            page->mGranulePosition, page->mGranulePosition);
    422 #endif
    423 
    424     page->mSerialNo = U32LE_AT(&header[14]);
    425     page->mPageNo = U32LE_AT(&header[18]);
    426 
    427     page->mNumSegments = header[26];
    428     if (mSource->readAt(
    429                 offset + sizeof(header), page->mLace, page->mNumSegments)
    430             < (ssize_t)page->mNumSegments) {
    431         return ERROR_IO;
    432     }
    433 
    434     size_t totalSize = 0;;
    435     for (size_t i = 0; i < page->mNumSegments; ++i) {
    436         totalSize += page->mLace[i];
    437     }
    438 
    439 #if 0
    440     String8 tmp;
    441     for (size_t i = 0; i < page->mNumSegments; ++i) {
    442         char x[32];
    443         sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
    444 
    445         tmp.append(x);
    446     }
    447 
    448     ALOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
    449 #endif
    450 
    451     return sizeof(header) + page->mNumSegments + totalSize;
    452 }
    453 
    454 status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
    455     *out = NULL;
    456 
    457     MediaBuffer *buffer = NULL;
    458     int64_t timeUs = -1;
    459 
    460     for (;;) {
    461         size_t i;
    462         size_t packetSize = 0;
    463         bool gotFullPacket = false;
    464         for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
    465             uint8_t lace = mCurrentPage.mLace[i];
    466 
    467             packetSize += lace;
    468 
    469             if (lace < 255) {
    470                 gotFullPacket = true;
    471                 ++i;
    472                 break;
    473             }
    474         }
    475 
    476         if (mNextLaceIndex < mCurrentPage.mNumSegments) {
    477             off64_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
    478             for (size_t j = 0; j < mNextLaceIndex; ++j) {
    479                 dataOffset += mCurrentPage.mLace[j];
    480             }
    481 
    482             size_t fullSize = packetSize;
    483             if (buffer != NULL) {
    484                 fullSize += buffer->range_length();
    485             }
    486             MediaBuffer *tmp = new MediaBuffer(fullSize);
    487             if (buffer != NULL) {
    488                 memcpy(tmp->data(), buffer->data(), buffer->range_length());
    489                 tmp->set_range(0, buffer->range_length());
    490                 buffer->release();
    491             } else {
    492                 // XXX Not only is this not technically the correct time for
    493                 // this packet, we also stamp every packet in this page
    494                 // with the same time. This needs fixing later.
    495 
    496                 if (mVi.rate) {
    497                     // Rate may not have been initialized yet if we're currently
    498                     // reading the configuration packets...
    499                     // Fortunately, the timestamp doesn't matter for those.
    500                     timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
    501                 }
    502                 tmp->set_range(0, 0);
    503             }
    504             buffer = tmp;
    505 
    506             ssize_t n = mSource->readAt(
    507                     dataOffset,
    508                     (uint8_t *)buffer->data() + buffer->range_length(),
    509                     packetSize);
    510 
    511             if (n < (ssize_t)packetSize) {
    512                 ALOGV("failed to read %zu bytes at 0x%016llx, got %zd bytes",
    513                      packetSize, dataOffset, n);
    514                 return ERROR_IO;
    515             }
    516 
    517             buffer->set_range(0, fullSize);
    518 
    519             mNextLaceIndex = i;
    520 
    521             if (gotFullPacket) {
    522                 // We've just read the entire packet.
    523 
    524                 if (timeUs >= 0) {
    525                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    526                 }
    527 
    528                 if (mFirstPacketInPage) {
    529                     buffer->meta_data()->setInt32(
    530                             kKeyValidSamples, mCurrentPageSamples);
    531                     mFirstPacketInPage = false;
    532                 }
    533 
    534                 *out = buffer;
    535 
    536                 return OK;
    537             }
    538 
    539             // fall through, the buffer now contains the start of the packet.
    540         }
    541 
    542         CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
    543 
    544         mOffset += mCurrentPageSize;
    545         ssize_t n = readPage(mOffset, &mCurrentPage);
    546 
    547         if (n <= 0) {
    548             if (buffer) {
    549                 buffer->release();
    550                 buffer = NULL;
    551             }
    552 
    553             ALOGV("readPage returned %zd", n);
    554 
    555             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
    556         }
    557 
    558         mCurrentPageSamples =
    559             mCurrentPage.mGranulePosition - mPrevGranulePosition;
    560         mFirstPacketInPage = true;
    561 
    562         mPrevGranulePosition = mCurrentPage.mGranulePosition;
    563 
    564         mCurrentPageSize = n;
    565         mNextLaceIndex = 0;
    566 
    567         if (buffer != NULL) {
    568             if ((mCurrentPage.mFlags & 1) == 0) {
    569                 // This page does not continue the packet, i.e. the packet
    570                 // is already complete.
    571 
    572                 if (timeUs >= 0) {
    573                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
    574                 }
    575 
    576                 buffer->meta_data()->setInt32(
    577                         kKeyValidSamples, mCurrentPageSamples);
    578                 mFirstPacketInPage = false;
    579 
    580                 *out = buffer;
    581 
    582                 return OK;
    583             }
    584         }
    585     }
    586 }
    587 
    588 status_t MyVorbisExtractor::init() {
    589     mMeta = new MetaData;
    590     mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
    591 
    592     MediaBuffer *packet;
    593     status_t err;
    594     if ((err = readNextPacket(&packet)) != OK) {
    595         return err;
    596     }
    597     ALOGV("read packet of size %zu\n", packet->range_length());
    598     err = verifyHeader(packet, 1);
    599     packet->release();
    600     packet = NULL;
    601     if (err != OK) {
    602         return err;
    603     }
    604 
    605     if ((err = readNextPacket(&packet)) != OK) {
    606         return err;
    607     }
    608     ALOGV("read packet of size %zu\n", packet->range_length());
    609     err = verifyHeader(packet, 3);
    610     packet->release();
    611     packet = NULL;
    612     if (err != OK) {
    613         return err;
    614     }
    615 
    616     if ((err = readNextPacket(&packet)) != OK) {
    617         return err;
    618     }
    619     ALOGV("read packet of size %zu\n", packet->range_length());
    620     err = verifyHeader(packet, 5);
    621     packet->release();
    622     packet = NULL;
    623     if (err != OK) {
    624         return err;
    625     }
    626 
    627     mFirstDataOffset = mOffset + mCurrentPageSize;
    628 
    629     off64_t size;
    630     uint64_t lastGranulePosition;
    631     if (!(mSource->flags() & DataSource::kIsCachingDataSource)
    632             && mSource->getSize(&size) == OK
    633             && findPrevGranulePosition(size, &lastGranulePosition) == OK) {
    634         // Let's assume it's cheap to seek to the end.
    635         // The granule position of the final page in the stream will
    636         // give us the exact duration of the content, something that
    637         // we can only approximate using avg. bitrate if seeking to
    638         // the end is too expensive or impossible (live streaming).
    639 
    640         int64_t durationUs = lastGranulePosition * 1000000ll / mVi.rate;
    641 
    642         mMeta->setInt64(kKeyDuration, durationUs);
    643 
    644         buildTableOfContents();
    645     }
    646 
    647     return OK;
    648 }
    649 
    650 void MyVorbisExtractor::buildTableOfContents() {
    651     off64_t offset = mFirstDataOffset;
    652     Page page;
    653     ssize_t pageSize;
    654     while ((pageSize = readPage(offset, &page)) > 0) {
    655         mTableOfContents.push();
    656 
    657         TOCEntry &entry =
    658             mTableOfContents.editItemAt(mTableOfContents.size() - 1);
    659 
    660         entry.mPageOffset = offset;
    661         entry.mTimeUs = page.mGranulePosition * 1000000ll / mVi.rate;
    662 
    663         offset += (size_t)pageSize;
    664     }
    665 
    666     // Limit the maximum amount of RAM we spend on the table of contents,
    667     // if necessary thin out the table evenly to trim it down to maximum
    668     // size.
    669 
    670     static const size_t kMaxTOCSize = 8192;
    671     static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry);
    672 
    673     size_t numerator = mTableOfContents.size();
    674 
    675     if (numerator > kMaxNumTOCEntries) {
    676         size_t denom = numerator - kMaxNumTOCEntries;
    677 
    678         size_t accum = 0;
    679         for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
    680             accum += denom;
    681             if (accum >= numerator) {
    682                 mTableOfContents.removeAt(i);
    683                 accum -= numerator;
    684             }
    685         }
    686     }
    687 }
    688 
    689 status_t MyVorbisExtractor::verifyHeader(
    690         MediaBuffer *buffer, uint8_t type) {
    691     const uint8_t *data =
    692         (const uint8_t *)buffer->data() + buffer->range_offset();
    693 
    694     size_t size = buffer->range_length();
    695 
    696     if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
    697         return ERROR_MALFORMED;
    698     }
    699 
    700     ogg_buffer buf;
    701     buf.data = (uint8_t *)data;
    702     buf.size = size;
    703     buf.refcount = 1;
    704     buf.ptr.owner = NULL;
    705 
    706     ogg_reference ref;
    707     ref.buffer = &buf;
    708     ref.begin = 0;
    709     ref.length = size;
    710     ref.next = NULL;
    711 
    712     oggpack_buffer bits;
    713     oggpack_readinit(&bits, &ref);
    714 
    715     CHECK_EQ(oggpack_read(&bits, 8), type);
    716     for (size_t i = 0; i < 6; ++i) {
    717         oggpack_read(&bits, 8);  // skip 'vorbis'
    718     }
    719 
    720     switch (type) {
    721         case 1:
    722         {
    723             CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
    724 
    725             mMeta->setData(kKeyVorbisInfo, 0, data, size);
    726             mMeta->setInt32(kKeySampleRate, mVi.rate);
    727             mMeta->setInt32(kKeyChannelCount, mVi.channels);
    728 
    729             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
    730             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
    731             ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
    732             ALOGV("window-bitrate = %ld", mVi.bitrate_window);
    733 
    734             off64_t size;
    735             if (mSource->getSize(&size) == OK) {
    736                 uint64_t bps = approxBitrate();
    737                 if (bps != 0) {
    738                     mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
    739                 }
    740             }
    741             break;
    742         }
    743 
    744         case 3:
    745         {
    746             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
    747                 return ERROR_MALFORMED;
    748             }
    749 
    750             parseFileMetaData();
    751             break;
    752         }
    753 
    754         case 5:
    755         {
    756             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
    757                 return ERROR_MALFORMED;
    758             }
    759 
    760             mMeta->setData(kKeyVorbisBooks, 0, data, size);
    761             break;
    762         }
    763     }
    764 
    765     return OK;
    766 }
    767 
    768 uint64_t MyVorbisExtractor::approxBitrate() {
    769     if (mVi.bitrate_nominal != 0) {
    770         return mVi.bitrate_nominal;
    771     }
    772 
    773     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
    774 }
    775 
    776 void MyVorbisExtractor::parseFileMetaData() {
    777     mFileMeta = new MetaData;
    778     mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
    779 
    780     for (int i = 0; i < mVc.comments; ++i) {
    781         const char *comment = mVc.user_comments[i];
    782         size_t commentLength = mVc.comment_lengths[i];
    783         parseVorbisComment(mFileMeta, comment, commentLength);
    784         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
    785     }
    786 }
    787 
    788 void parseVorbisComment(
    789         const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
    790 {
    791     struct {
    792         const char *const mTag;
    793         uint32_t mKey;
    794     } kMap[] = {
    795         { "TITLE", kKeyTitle },
    796         { "ARTIST", kKeyArtist },
    797         { "ALBUMARTIST", kKeyAlbumArtist },
    798         { "ALBUM ARTIST", kKeyAlbumArtist },
    799         { "COMPILATION", kKeyCompilation },
    800         { "ALBUM", kKeyAlbum },
    801         { "COMPOSER", kKeyComposer },
    802         { "GENRE", kKeyGenre },
    803         { "AUTHOR", kKeyAuthor },
    804         { "TRACKNUMBER", kKeyCDTrackNumber },
    805         { "DISCNUMBER", kKeyDiscNumber },
    806         { "DATE", kKeyDate },
    807         { "LYRICIST", kKeyWriter },
    808         { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
    809         { "ANDROID_LOOP", kKeyAutoLoop },
    810     };
    811 
    812         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
    813             size_t tagLen = strlen(kMap[j].mTag);
    814             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
    815                     && comment[tagLen] == '=') {
    816                 if (kMap[j].mKey == kKeyAlbumArt) {
    817                     extractAlbumArt(
    818                             fileMeta,
    819                             &comment[tagLen + 1],
    820                             commentLength - tagLen - 1);
    821                 } else if (kMap[j].mKey == kKeyAutoLoop) {
    822                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
    823                         fileMeta->setInt32(kKeyAutoLoop, true);
    824                     }
    825                 } else {
    826                     fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
    827                 }
    828             }
    829         }
    830 
    831 }
    832 
    833 // The returned buffer should be free()d.
    834 static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
    835     *outSize = 0;
    836 
    837     if ((size % 4) != 0) {
    838         return NULL;
    839     }
    840 
    841     size_t n = size;
    842     size_t padding = 0;
    843     if (n >= 1 && s[n - 1] == '=') {
    844         padding = 1;
    845 
    846         if (n >= 2 && s[n - 2] == '=') {
    847             padding = 2;
    848         }
    849     }
    850 
    851     size_t outLen = 3 * size / 4 - padding;
    852 
    853     *outSize = outLen;
    854 
    855     void *buffer = malloc(outLen);
    856 
    857     uint8_t *out = (uint8_t *)buffer;
    858     size_t j = 0;
    859     uint32_t accum = 0;
    860     for (size_t i = 0; i < n; ++i) {
    861         char c = s[i];
    862         unsigned value;
    863         if (c >= 'A' && c <= 'Z') {
    864             value = c - 'A';
    865         } else if (c >= 'a' && c <= 'z') {
    866             value = 26 + c - 'a';
    867         } else if (c >= '0' && c <= '9') {
    868             value = 52 + c - '0';
    869         } else if (c == '+') {
    870             value = 62;
    871         } else if (c == '/') {
    872             value = 63;
    873         } else if (c != '=') {
    874             return NULL;
    875         } else {
    876             if (i < n - padding) {
    877                 return NULL;
    878             }
    879 
    880             value = 0;
    881         }
    882 
    883         accum = (accum << 6) | value;
    884 
    885         if (((i + 1) % 4) == 0) {
    886             out[j++] = (accum >> 16);
    887 
    888             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
    889             if (j < outLen) { out[j++] = accum & 0xff; }
    890 
    891             accum = 0;
    892         }
    893     }
    894 
    895     return (uint8_t *)buffer;
    896 }
    897 
    898 static void extractAlbumArt(
    899         const sp<MetaData> &fileMeta, const void *data, size_t size) {
    900     ALOGV("extractAlbumArt from '%s'", (const char *)data);
    901 
    902     size_t flacSize;
    903     uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
    904 
    905     if (flac == NULL) {
    906         ALOGE("malformed base64 encoded data.");
    907         return;
    908     }
    909 
    910     ALOGV("got flac of size %zu", flacSize);
    911 
    912     uint32_t picType;
    913     uint32_t typeLen;
    914     uint32_t descLen;
    915     uint32_t dataLen;
    916     char type[128];
    917 
    918     if (flacSize < 8) {
    919         goto exit;
    920     }
    921 
    922     picType = U32_AT(flac);
    923 
    924     if (picType != 3) {
    925         // This is not a front cover.
    926         goto exit;
    927     }
    928 
    929     typeLen = U32_AT(&flac[4]);
    930     if (typeLen + 1 > sizeof(type)) {
    931         goto exit;
    932     }
    933 
    934     if (flacSize < 8 + typeLen) {
    935         goto exit;
    936     }
    937 
    938     memcpy(type, &flac[8], typeLen);
    939     type[typeLen] = '\0';
    940 
    941     ALOGV("picType = %d, type = '%s'", picType, type);
    942 
    943     if (!strcmp(type, "-->")) {
    944         // This is not inline cover art, but an external url instead.
    945         goto exit;
    946     }
    947 
    948     descLen = U32_AT(&flac[8 + typeLen]);
    949 
    950     if (flacSize < 32 + typeLen + descLen) {
    951         goto exit;
    952     }
    953 
    954     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
    955 
    956     if (flacSize < 32 + typeLen + descLen + dataLen) {
    957         goto exit;
    958     }
    959 
    960     ALOGV("got image data, %zu trailing bytes",
    961          flacSize - 32 - typeLen - descLen - dataLen);
    962 
    963     fileMeta->setData(
    964             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
    965 
    966     fileMeta->setCString(kKeyAlbumArtMIME, type);
    967 
    968 exit:
    969     free(flac);
    970     flac = NULL;
    971 }
    972 
    973 ////////////////////////////////////////////////////////////////////////////////
    974 
    975 OggExtractor::OggExtractor(const sp<DataSource> &source)
    976     : mDataSource(source),
    977       mInitCheck(NO_INIT),
    978       mImpl(NULL) {
    979     mImpl = new MyVorbisExtractor(mDataSource);
    980     mInitCheck = mImpl->seekToOffset(0);
    981 
    982     if (mInitCheck == OK) {
    983         mInitCheck = mImpl->init();
    984     }
    985 }
    986 
    987 OggExtractor::~OggExtractor() {
    988     delete mImpl;
    989     mImpl = NULL;
    990 }
    991 
    992 size_t OggExtractor::countTracks() {
    993     return mInitCheck != OK ? 0 : 1;
    994 }
    995 
    996 sp<MediaSource> OggExtractor::getTrack(size_t index) {
    997     if (index >= 1) {
    998         return NULL;
    999     }
   1000 
   1001     return new OggSource(this);
   1002 }
   1003 
   1004 sp<MetaData> OggExtractor::getTrackMetaData(
   1005         size_t index, uint32_t /* flags */) {
   1006     if (index >= 1) {
   1007         return NULL;
   1008     }
   1009 
   1010     return mImpl->getFormat();
   1011 }
   1012 
   1013 sp<MetaData> OggExtractor::getMetaData() {
   1014     return mImpl->getFileMetaData();
   1015 }
   1016 
   1017 bool SniffOgg(
   1018         const sp<DataSource> &source, String8 *mimeType, float *confidence,
   1019         sp<AMessage> *) {
   1020     char tmp[4];
   1021     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
   1022         return false;
   1023     }
   1024 
   1025     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
   1026     *confidence = 0.2f;
   1027 
   1028     return true;
   1029 }
   1030 
   1031 }  // namespace android
   1032