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