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/ABuffer.h>
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/DataSource.h>
27 #include <media/stagefright/MediaBuffer.h>
28 #include <media/stagefright/MediaBufferGroup.h>
29 #include <media/stagefright/MediaDefs.h>
30 #include <media/stagefright/MediaErrors.h>
31 #include <media/stagefright/MediaSource.h>
32 #include <media/stagefright/MetaData.h>
33 #include <media/stagefright/Utils.h>
34 #include <utils/String8.h>
35 
36 extern "C" {
37     #include <Tremolo/codec_internal.h>
38 
39     int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
40     int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
41     int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
42     long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
43 }
44 
45 namespace android {
46 
47 struct OggSource : public MediaSource {
48     OggSource(const sp<OggExtractor> &extractor);
49 
50     virtual sp<MetaData> getFormat();
51 
52     virtual status_t start(MetaData *params = NULL);
53     virtual status_t stop();
54 
55     virtual status_t read(
56             MediaBuffer **buffer, const ReadOptions *options = NULL);
57 
58 protected:
59     virtual ~OggSource();
60 
61 private:
62     sp<OggExtractor> mExtractor;
63     bool mStarted;
64 
65     OggSource(const OggSource &);
66     OggSource &operator=(const OggSource &);
67 };
68 
69 struct MyOggExtractor {
70     MyOggExtractor(
71             const sp<DataSource> &source,
72             const char *mimeType,
73             size_t numHeaders,
74             int64_t seekPreRollUs);
75     virtual ~MyOggExtractor();
76 
77     sp<MetaData> getFormat() const;
78 
79     // Returns an approximate bitrate in bits per second.
80     virtual uint64_t approxBitrate() const = 0;
81 
82     status_t seekToTime(int64_t timeUs);
83     status_t seekToOffset(off64_t offset);
84     virtual status_t readNextPacket(MediaBuffer **buffer) = 0;
85 
86     status_t init();
87 
getFileMetaDataandroid::MyOggExtractor88     sp<MetaData> getFileMetaData() { return mFileMeta; }
89 
90 protected:
91     struct Page {
92         uint64_t mGranulePosition;
93         int32_t mPrevPacketSize;
94         uint64_t mPrevPacketPos;
95         uint32_t mSerialNo;
96         uint32_t mPageNo;
97         uint8_t mFlags;
98         uint8_t mNumSegments;
99         uint8_t mLace[255];
100     };
101 
102     struct TOCEntry {
103         off64_t mPageOffset;
104         int64_t mTimeUs;
105     };
106 
107     sp<DataSource> mSource;
108     off64_t mOffset;
109     Page mCurrentPage;
110     uint64_t mCurGranulePosition;
111     uint64_t mPrevGranulePosition;
112     size_t mCurrentPageSize;
113     bool mFirstPacketInPage;
114     uint64_t mCurrentPageSamples;
115     size_t mNextLaceIndex;
116 
117     const char *mMimeType;
118     size_t mNumHeaders;
119     int64_t mSeekPreRollUs;
120 
121     off64_t mFirstDataOffset;
122 
123     vorbis_info mVi;
124     vorbis_comment mVc;
125 
126     sp<MetaData> mMeta;
127     sp<MetaData> mFileMeta;
128 
129     Vector<TOCEntry> mTableOfContents;
130 
131     ssize_t readPage(off64_t offset, Page *page);
132     status_t findNextPage(off64_t startOffset, off64_t *pageOffset);
133 
134     virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const = 0;
135 
136     // Extract codec format, metadata tags, and various codec specific data;
137     // the format and CSD's are required to setup the decoders for the enclosed media content.
138     //
139     // Valid values for `type` are:
140     // 1 - bitstream identification header
141     // 3 - comment header
142     // 5 - codec setup header (Vorbis only)
143     virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type) = 0;
144 
145     // Read the next ogg packet from the underlying data source; optionally
146     // calculate the timestamp for the output packet whilst pretending
147     // that we are parsing an Ogg Vorbis stream.
148     //
149     // *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated;
150     // clients are responsible for releasing the original buffer.
151     status_t _readNextPacket(MediaBuffer **buffer, bool calcVorbisTimestamp);
152 
153     int32_t getPacketBlockSize(MediaBuffer *buffer);
154 
155     void parseFileMetaData();
156 
157     status_t findPrevGranulePosition(off64_t pageOffset, uint64_t *granulePos);
158 
159     void buildTableOfContents();
160 
161     MyOggExtractor(const MyOggExtractor &);
162     MyOggExtractor &operator=(const MyOggExtractor &);
163 };
164 
165 struct MyVorbisExtractor : public MyOggExtractor {
MyVorbisExtractorandroid::MyVorbisExtractor166     MyVorbisExtractor(const sp<DataSource> &source)
167         : MyOggExtractor(source,
168                 MEDIA_MIMETYPE_AUDIO_VORBIS,
169                 /* numHeaders */ 3,
170                 /* seekPreRollUs */ 0) {
171     }
172 
173     virtual uint64_t approxBitrate() const;
174 
readNextPacketandroid::MyVorbisExtractor175     virtual status_t readNextPacket(MediaBuffer **buffer) {
176         return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true);
177     }
178 
179 protected:
getTimeUsOfGranuleandroid::MyVorbisExtractor180     virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const {
181         return granulePos * 1000000ll / mVi.rate;
182     }
183 
184     virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
185 };
186 
187 struct MyOpusExtractor : public MyOggExtractor {
188     static const int32_t kOpusSampleRate = 48000;
189     static const int64_t kOpusSeekPreRollUs = 80000; // 80 ms
190 
MyOpusExtractorandroid::MyOpusExtractor191     MyOpusExtractor(const sp<DataSource> &source)
192         : MyOggExtractor(source, MEDIA_MIMETYPE_AUDIO_OPUS, /*numHeaders*/ 2, kOpusSeekPreRollUs),
193           mChannelCount(0),
194           mCodecDelay(0),
195           mStartGranulePosition(-1) {
196     }
197 
approxBitrateandroid::MyOpusExtractor198     virtual uint64_t approxBitrate() const {
199         return 0;
200     }
201 
202     virtual status_t readNextPacket(MediaBuffer **buffer);
203 
204 protected:
205     virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const;
206     virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
207 
208 private:
209     status_t verifyOpusHeader(MediaBuffer *buffer);
210     status_t verifyOpusComments(MediaBuffer *buffer);
211     uint32_t getNumSamplesInPacket(MediaBuffer *buffer) const;
212 
213     uint8_t mChannelCount;
214     uint16_t mCodecDelay;
215     int64_t mStartGranulePosition;
216 };
217 
218 static void extractAlbumArt(
219         const sp<MetaData> &fileMeta, const void *data, size_t size);
220 
221 ////////////////////////////////////////////////////////////////////////////////
222 
OggSource(const sp<OggExtractor> & extractor)223 OggSource::OggSource(const sp<OggExtractor> &extractor)
224     : mExtractor(extractor),
225       mStarted(false) {
226 }
227 
~OggSource()228 OggSource::~OggSource() {
229     if (mStarted) {
230         stop();
231     }
232 }
233 
getFormat()234 sp<MetaData> OggSource::getFormat() {
235     return mExtractor->mImpl->getFormat();
236 }
237 
start(MetaData *)238 status_t OggSource::start(MetaData * /* params */) {
239     if (mStarted) {
240         return INVALID_OPERATION;
241     }
242 
243     mStarted = true;
244 
245     return OK;
246 }
247 
stop()248 status_t OggSource::stop() {
249     mStarted = false;
250 
251     return OK;
252 }
253 
read(MediaBuffer ** out,const ReadOptions * options)254 status_t OggSource::read(
255         MediaBuffer **out, const ReadOptions *options) {
256     *out = NULL;
257 
258     int64_t seekTimeUs;
259     ReadOptions::SeekMode mode;
260     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
261         status_t err = mExtractor->mImpl->seekToTime(seekTimeUs);
262         if (err != OK) {
263             return err;
264         }
265     }
266 
267     MediaBuffer *packet;
268     status_t err = mExtractor->mImpl->readNextPacket(&packet);
269 
270     if (err != OK) {
271         return err;
272     }
273 
274 #if 0
275     int64_t timeUs;
276     if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
277         ALOGI("found time = %lld us", timeUs);
278     } else {
279         ALOGI("NO time");
280     }
281 #endif
282 
283     packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
284 
285     *out = packet;
286 
287     return OK;
288 }
289 
290 ////////////////////////////////////////////////////////////////////////////////
291 
MyOggExtractor(const sp<DataSource> & source,const char * mimeType,size_t numHeaders,int64_t seekPreRollUs)292 MyOggExtractor::MyOggExtractor(
293         const sp<DataSource> &source,
294         const char *mimeType,
295         size_t numHeaders,
296         int64_t seekPreRollUs)
297     : mSource(source),
298       mOffset(0),
299       mCurGranulePosition(0),
300       mPrevGranulePosition(0),
301       mCurrentPageSize(0),
302       mFirstPacketInPage(true),
303       mCurrentPageSamples(0),
304       mNextLaceIndex(0),
305       mMimeType(mimeType),
306       mNumHeaders(numHeaders),
307       mSeekPreRollUs(seekPreRollUs),
308       mFirstDataOffset(-1) {
309     mCurrentPage.mNumSegments = 0;
310 
311     vorbis_info_init(&mVi);
312     vorbis_comment_init(&mVc);
313 }
314 
~MyOggExtractor()315 MyOggExtractor::~MyOggExtractor() {
316     vorbis_comment_clear(&mVc);
317     vorbis_info_clear(&mVi);
318 }
319 
getFormat() const320 sp<MetaData> MyOggExtractor::getFormat() const {
321     return mMeta;
322 }
323 
findNextPage(off64_t startOffset,off64_t * pageOffset)324 status_t MyOggExtractor::findNextPage(
325         off64_t startOffset, off64_t *pageOffset) {
326     *pageOffset = startOffset;
327 
328     for (;;) {
329         char signature[4];
330         ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
331 
332         if (n < 4) {
333             *pageOffset = 0;
334 
335             return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
336         }
337 
338         if (!memcmp(signature, "OggS", 4)) {
339             if (*pageOffset > startOffset) {
340                 ALOGV("skipped %lld bytes of junk to reach next frame",
341                      (long long)(*pageOffset - startOffset));
342             }
343 
344             return OK;
345         }
346 
347         ++*pageOffset;
348     }
349 }
350 
351 // Given the offset of the "current" page, find the page immediately preceding
352 // it (if any) and return its granule position.
353 // To do this we back up from the "current" page's offset until we find any
354 // page preceding it and then scan forward to just before the current page.
findPrevGranulePosition(off64_t pageOffset,uint64_t * granulePos)355 status_t MyOggExtractor::findPrevGranulePosition(
356         off64_t pageOffset, uint64_t *granulePos) {
357     *granulePos = 0;
358 
359     off64_t prevPageOffset = 0;
360     off64_t prevGuess = pageOffset;
361     for (;;) {
362         if (prevGuess >= 5000) {
363             prevGuess -= 5000;
364         } else {
365             prevGuess = 0;
366         }
367 
368         ALOGV("backing up %lld bytes", (long long)(pageOffset - prevGuess));
369 
370         status_t err = findNextPage(prevGuess, &prevPageOffset);
371         if (err == ERROR_END_OF_STREAM) {
372             // We are at the last page and didn't back off enough;
373             // back off 5000 bytes more and try again.
374             continue;
375         } else if (err != OK) {
376             return err;
377         }
378 
379         if (prevPageOffset < pageOffset || prevGuess == 0) {
380             break;
381         }
382     }
383 
384     if (prevPageOffset == pageOffset) {
385         // We did not find a page preceding this one.
386         return UNKNOWN_ERROR;
387     }
388 
389     ALOGV("prevPageOffset at %lld, pageOffset at %lld",
390             (long long)prevPageOffset, (long long)pageOffset);
391 
392     for (;;) {
393         Page prevPage;
394         ssize_t n = readPage(prevPageOffset, &prevPage);
395 
396         if (n <= 0) {
397             return (status_t)n;
398         }
399 
400         prevPageOffset += n;
401 
402         if (prevPageOffset == pageOffset) {
403             *granulePos = prevPage.mGranulePosition;
404             return OK;
405         }
406     }
407 }
408 
seekToTime(int64_t timeUs)409 status_t MyOggExtractor::seekToTime(int64_t timeUs) {
410     timeUs -= mSeekPreRollUs;
411     if (timeUs < 0) {
412         timeUs = 0;
413     }
414 
415     if (mTableOfContents.isEmpty()) {
416         // Perform approximate seeking based on avg. bitrate.
417         uint64_t bps = approxBitrate();
418         if (bps <= 0) {
419             return INVALID_OPERATION;
420         }
421 
422         off64_t pos = timeUs * bps / 8000000ll;
423 
424         ALOGV("seeking to offset %lld", (long long)pos);
425         return seekToOffset(pos);
426     }
427 
428     size_t left = 0;
429     size_t right_plus_one = mTableOfContents.size();
430     while (left < right_plus_one) {
431         size_t center = left + (right_plus_one - left) / 2;
432 
433         const TOCEntry &entry = mTableOfContents.itemAt(center);
434 
435         if (timeUs < entry.mTimeUs) {
436             right_plus_one = center;
437         } else if (timeUs > entry.mTimeUs) {
438             left = center + 1;
439         } else {
440             left = center;
441             break;
442         }
443     }
444 
445     if (left == mTableOfContents.size()) {
446         --left;
447     }
448 
449     const TOCEntry &entry = mTableOfContents.itemAt(left);
450 
451     ALOGV("seeking to entry %zu / %zu at offset %lld",
452          left, mTableOfContents.size(), (long long)entry.mPageOffset);
453 
454     return seekToOffset(entry.mPageOffset);
455 }
456 
seekToOffset(off64_t offset)457 status_t MyOggExtractor::seekToOffset(off64_t offset) {
458     if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
459         // Once we know where the actual audio data starts (past the headers)
460         // don't ever seek to anywhere before that.
461         offset = mFirstDataOffset;
462     }
463 
464     off64_t pageOffset;
465     status_t err = findNextPage(offset, &pageOffset);
466 
467     if (err != OK) {
468         return err;
469     }
470 
471     // We found the page we wanted to seek to, but we'll also need
472     // the page preceding it to determine how many valid samples are on
473     // this page.
474     findPrevGranulePosition(pageOffset, &mPrevGranulePosition);
475 
476     mOffset = pageOffset;
477 
478     mCurrentPageSize = 0;
479     mFirstPacketInPage = true;
480     mCurrentPageSamples = 0;
481     mCurrentPage.mNumSegments = 0;
482     mCurrentPage.mPrevPacketSize = -1;
483     mNextLaceIndex = 0;
484 
485     // XXX what if new page continues packet from last???
486 
487     return OK;
488 }
489 
readPage(off64_t offset,Page * page)490 ssize_t MyOggExtractor::readPage(off64_t offset, Page *page) {
491     uint8_t header[27];
492     ssize_t n;
493     if ((n = mSource->readAt(offset, header, sizeof(header)))
494             < (ssize_t)sizeof(header)) {
495         ALOGV("failed to read %zu bytes at offset %#016llx, got %zd bytes",
496                 sizeof(header), (long long)offset, n);
497 
498         if (n < 0) {
499             return n;
500         } else if (n == 0) {
501             return ERROR_END_OF_STREAM;
502         } else {
503             return ERROR_IO;
504         }
505     }
506 
507     if (memcmp(header, "OggS", 4)) {
508         return ERROR_MALFORMED;
509     }
510 
511     if (header[4] != 0) {
512         // Wrong version.
513 
514         return ERROR_UNSUPPORTED;
515     }
516 
517     page->mFlags = header[5];
518 
519     if (page->mFlags & ~7) {
520         // Only bits 0-2 are defined in version 0.
521         return ERROR_MALFORMED;
522     }
523 
524     page->mGranulePosition = U64LE_AT(&header[6]);
525 
526 #if 0
527     printf("granulePosition = %llu (0x%llx)\n",
528            page->mGranulePosition, page->mGranulePosition);
529 #endif
530 
531     page->mSerialNo = U32LE_AT(&header[14]);
532     page->mPageNo = U32LE_AT(&header[18]);
533 
534     page->mNumSegments = header[26];
535     if (mSource->readAt(
536                 offset + sizeof(header), page->mLace, page->mNumSegments)
537             < (ssize_t)page->mNumSegments) {
538         return ERROR_IO;
539     }
540 
541     size_t totalSize = 0;;
542     for (size_t i = 0; i < page->mNumSegments; ++i) {
543         totalSize += page->mLace[i];
544     }
545 
546 #if 0
547     String8 tmp;
548     for (size_t i = 0; i < page->mNumSegments; ++i) {
549         char x[32];
550         sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
551 
552         tmp.append(x);
553     }
554 
555     ALOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
556 #endif
557 
558     return sizeof(header) + page->mNumSegments + totalSize;
559 }
560 
readNextPacket(MediaBuffer ** out)561 status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
562     if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
563         // The first sample might not start at time 0; find out where by subtracting
564         // the number of samples on the first page from the granule position
565         // (position of last complete sample) of the first page. This happens
566         // the first time before we attempt to read a packet from the first page.
567         MediaBuffer *mBuf;
568         uint32_t numSamples = 0;
569         uint64_t curGranulePosition = 0;
570         while (true) {
571             status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false);
572             if (err != OK && err != ERROR_END_OF_STREAM) {
573                 return err;
574             }
575             // First two pages are header pages.
576             if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) {
577                 break;
578             }
579             curGranulePosition = mCurrentPage.mGranulePosition;
580             numSamples += getNumSamplesInPacket(mBuf);
581             mBuf->release();
582             mBuf = NULL;
583         }
584 
585         if (curGranulePosition > numSamples) {
586             mStartGranulePosition = curGranulePosition - numSamples;
587         } else {
588             mStartGranulePosition = 0;
589         }
590         seekToOffset(0);
591     }
592 
593     status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false);
594     if (err != OK) {
595         return err;
596     }
597 
598     int32_t currentPageSamples;
599     // Calculate timestamps by accumulating durations starting from the first sample of a page;
600     // We assume that we only seek to page boundaries.
601     if ((*out)->meta_data()->findInt32(kKeyValidSamples, &currentPageSamples)) {
602         // first packet in page
603         if (mOffset == mFirstDataOffset) {
604             currentPageSamples -= mStartGranulePosition;
605             (*out)->meta_data()->setInt32(kKeyValidSamples, currentPageSamples);
606         }
607         mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples;
608     }
609 
610     int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition);
611     (*out)->meta_data()->setInt64(kKeyTime, timeUs);
612 
613     uint32_t frames = getNumSamplesInPacket(*out);
614     mCurGranulePosition += frames;
615     return OK;
616 }
617 
getNumSamplesInPacket(MediaBuffer * buffer) const618 uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBuffer *buffer) const {
619     if (buffer == NULL || buffer->range_length() < 1) {
620         return 0;
621     }
622 
623     uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset();
624     uint8_t toc = data[0];
625     uint8_t config = (toc >> 3) & 0x1f;
626     uint32_t frameSizesUs[] = {
627         10000, 20000, 40000, 60000, // 0...3
628         10000, 20000, 40000, 60000, // 4...7
629         10000, 20000, 40000, 60000, // 8...11
630         10000, 20000,               // 12...13
631         10000, 20000,               // 14...15
632         2500, 5000, 10000, 20000,   // 16...19
633         2500, 5000, 10000, 20000,   // 20...23
634         2500, 5000, 10000, 20000,   // 24...27
635         2500, 5000, 10000, 20000    // 28...31
636     };
637     uint32_t frameSizeUs = frameSizesUs[config];
638 
639     uint32_t numFrames;
640     uint8_t c = toc & 3;
641     switch (c) {
642     case 0:
643         numFrames = 1;
644         break;
645     case 1:
646     case 2:
647         numFrames = 2;
648         break;
649     case 3:
650         if (buffer->range_length() < 3) {
651             numFrames = 0;
652         } else {
653             numFrames = data[2] & 0x3f;
654         }
655         break;
656     default:
657         TRESPASS();
658     }
659 
660     uint32_t numSamples = frameSizeUs * numFrames * kOpusSampleRate / 1000000;
661     return numSamples;
662 }
663 
_readNextPacket(MediaBuffer ** out,bool calcVorbisTimestamp)664 status_t MyOggExtractor::_readNextPacket(MediaBuffer **out, bool calcVorbisTimestamp) {
665     *out = NULL;
666 
667     MediaBuffer *buffer = NULL;
668     int64_t timeUs = -1;
669 
670     for (;;) {
671         size_t i;
672         size_t packetSize = 0;
673         bool gotFullPacket = false;
674         for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
675             uint8_t lace = mCurrentPage.mLace[i];
676 
677             packetSize += lace;
678 
679             if (lace < 255) {
680                 gotFullPacket = true;
681                 ++i;
682                 break;
683             }
684         }
685 
686         if (mNextLaceIndex < mCurrentPage.mNumSegments) {
687             off64_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
688             for (size_t j = 0; j < mNextLaceIndex; ++j) {
689                 dataOffset += mCurrentPage.mLace[j];
690             }
691 
692             size_t fullSize = packetSize;
693             if (buffer != NULL) {
694                 fullSize += buffer->range_length();
695             }
696             MediaBuffer *tmp = new MediaBuffer(fullSize);
697             if (buffer != NULL) {
698                 memcpy(tmp->data(), buffer->data(), buffer->range_length());
699                 tmp->set_range(0, buffer->range_length());
700                 buffer->release();
701             } else {
702                 tmp->set_range(0, 0);
703             }
704             buffer = tmp;
705 
706             ssize_t n = mSource->readAt(
707                     dataOffset,
708                     (uint8_t *)buffer->data() + buffer->range_length(),
709                     packetSize);
710 
711             if (n < (ssize_t)packetSize) {
712                 ALOGV("failed to read %zu bytes at %#016llx, got %zd bytes",
713                         packetSize, (long long)dataOffset, n);
714                 return ERROR_IO;
715             }
716 
717             buffer->set_range(0, fullSize);
718 
719             mNextLaceIndex = i;
720 
721             if (gotFullPacket) {
722                 // We've just read the entire packet.
723 
724                 if (mFirstPacketInPage) {
725                     buffer->meta_data()->setInt32(
726                             kKeyValidSamples, mCurrentPageSamples);
727                     mFirstPacketInPage = false;
728                 }
729 
730                 if (calcVorbisTimestamp) {
731                     int32_t curBlockSize = getPacketBlockSize(buffer);
732                     if (mCurrentPage.mPrevPacketSize < 0) {
733                         mCurrentPage.mPrevPacketSize = curBlockSize;
734                         mCurrentPage.mPrevPacketPos =
735                                 mCurrentPage.mGranulePosition - mCurrentPageSamples;
736                         timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate;
737                     } else {
738                         // The effective block size is the average of the two overlapped blocks
739                         int32_t actualBlockSize =
740                                 (curBlockSize + mCurrentPage.mPrevPacketSize) / 2;
741                         timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate;
742                         // The actual size output by the decoder will be half the effective
743                         // size, due to the overlap
744                         mCurrentPage.mPrevPacketPos += actualBlockSize / 2;
745                         mCurrentPage.mPrevPacketSize = curBlockSize;
746                     }
747                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
748                 }
749                 *out = buffer;
750 
751                 return OK;
752             }
753 
754             // fall through, the buffer now contains the start of the packet.
755         }
756 
757         CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
758 
759         mOffset += mCurrentPageSize;
760         ssize_t n = readPage(mOffset, &mCurrentPage);
761 
762         if (n <= 0) {
763             if (buffer) {
764                 buffer->release();
765                 buffer = NULL;
766             }
767 
768             ALOGV("readPage returned %zd", n);
769 
770             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
771         }
772 
773         mCurrentPageSamples =
774             mCurrentPage.mGranulePosition - mPrevGranulePosition;
775         mFirstPacketInPage = true;
776 
777         mPrevGranulePosition = mCurrentPage.mGranulePosition;
778 
779         mCurrentPageSize = n;
780         mNextLaceIndex = 0;
781 
782         if (buffer != NULL) {
783             if ((mCurrentPage.mFlags & 1) == 0) {
784                 // This page does not continue the packet, i.e. the packet
785                 // is already complete.
786 
787                 if (timeUs >= 0) {
788                     buffer->meta_data()->setInt64(kKeyTime, timeUs);
789                 }
790 
791                 buffer->meta_data()->setInt32(
792                         kKeyValidSamples, mCurrentPageSamples);
793                 mFirstPacketInPage = false;
794 
795                 *out = buffer;
796 
797                 return OK;
798             }
799         }
800     }
801 }
802 
init()803 status_t MyOggExtractor::init() {
804     mMeta = new MetaData;
805     mMeta->setCString(kKeyMIMEType, mMimeType);
806 
807     status_t err;
808     MediaBuffer *packet;
809     for (size_t i = 0; i < mNumHeaders; ++i) {
810         // ignore timestamp for configuration packets
811         if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) {
812             return err;
813         }
814         ALOGV("read packet of size %zu\n", packet->range_length());
815         err = verifyHeader(packet, /* type = */ i * 2 + 1);
816         packet->release();
817         packet = NULL;
818         if (err != OK) {
819             return err;
820         }
821     }
822 
823     mFirstDataOffset = mOffset + mCurrentPageSize;
824 
825     off64_t size;
826     uint64_t lastGranulePosition;
827     if (!(mSource->flags() & DataSource::kIsCachingDataSource)
828             && mSource->getSize(&size) == OK
829             && findPrevGranulePosition(size, &lastGranulePosition) == OK) {
830         // Let's assume it's cheap to seek to the end.
831         // The granule position of the final page in the stream will
832         // give us the exact duration of the content, something that
833         // we can only approximate using avg. bitrate if seeking to
834         // the end is too expensive or impossible (live streaming).
835 
836         int64_t durationUs = getTimeUsOfGranule(lastGranulePosition);
837 
838         mMeta->setInt64(kKeyDuration, durationUs);
839 
840         buildTableOfContents();
841     }
842 
843     return OK;
844 }
845 
buildTableOfContents()846 void MyOggExtractor::buildTableOfContents() {
847     off64_t offset = mFirstDataOffset;
848     Page page;
849     ssize_t pageSize;
850     while ((pageSize = readPage(offset, &page)) > 0) {
851         mTableOfContents.push();
852 
853         TOCEntry &entry =
854             mTableOfContents.editItemAt(mTableOfContents.size() - 1);
855 
856         entry.mPageOffset = offset;
857         entry.mTimeUs = getTimeUsOfGranule(page.mGranulePosition);
858 
859         offset += (size_t)pageSize;
860     }
861 
862     // Limit the maximum amount of RAM we spend on the table of contents,
863     // if necessary thin out the table evenly to trim it down to maximum
864     // size.
865 
866     static const size_t kMaxTOCSize = 8192;
867     static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry);
868 
869     size_t numerator = mTableOfContents.size();
870 
871     if (numerator > kMaxNumTOCEntries) {
872         size_t denom = numerator - kMaxNumTOCEntries;
873 
874         size_t accum = 0;
875         for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
876             accum += denom;
877             if (accum >= numerator) {
878                 mTableOfContents.removeAt(i);
879                 accum -= numerator;
880             }
881         }
882     }
883 }
884 
getPacketBlockSize(MediaBuffer * buffer)885 int32_t MyOggExtractor::getPacketBlockSize(MediaBuffer *buffer) {
886     const uint8_t *data =
887         (const uint8_t *)buffer->data() + buffer->range_offset();
888 
889     size_t size = buffer->range_length();
890 
891     ogg_buffer buf;
892     buf.data = (uint8_t *)data;
893     buf.size = size;
894     buf.refcount = 1;
895     buf.ptr.owner = NULL;
896 
897     ogg_reference ref;
898     ref.buffer = &buf;
899     ref.begin = 0;
900     ref.length = size;
901     ref.next = NULL;
902 
903     ogg_packet pack;
904     pack.packet = &ref;
905     pack.bytes = ref.length;
906     pack.b_o_s = 0;
907     pack.e_o_s = 0;
908     pack.granulepos = 0;
909     pack.packetno = 0;
910 
911     return vorbis_packet_blocksize(&mVi, &pack);
912 }
913 
getTimeUsOfGranule(uint64_t granulePos) const914 int64_t MyOpusExtractor::getTimeUsOfGranule(uint64_t granulePos) const {
915     uint64_t pcmSamplePosition = 0;
916     if (granulePos > mCodecDelay) {
917         pcmSamplePosition = granulePos - mCodecDelay;
918     }
919     return pcmSamplePosition * 1000000ll / kOpusSampleRate;
920 }
921 
verifyHeader(MediaBuffer * buffer,uint8_t type)922 status_t MyOpusExtractor::verifyHeader(MediaBuffer *buffer, uint8_t type) {
923     switch (type) {
924         // there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean
925         // header and comments such that we can share code with MyVorbisExtractor.
926         case 1:
927             return verifyOpusHeader(buffer);
928         case 3:
929             return verifyOpusComments(buffer);
930         default:
931             return INVALID_OPERATION;
932     }
933 }
934 
verifyOpusHeader(MediaBuffer * buffer)935 status_t MyOpusExtractor::verifyOpusHeader(MediaBuffer *buffer) {
936     const size_t kOpusHeaderSize = 19;
937     const uint8_t *data =
938         (const uint8_t *)buffer->data() + buffer->range_offset();
939 
940     size_t size = buffer->range_length();
941 
942     if (size < kOpusHeaderSize
943             || memcmp(data, "OpusHead", 8)
944             || /* version = */ data[8] != 1) {
945         return ERROR_MALFORMED;
946     }
947 
948     mChannelCount = data[9];
949     mCodecDelay = U16LE_AT(&data[10]);
950 
951     mMeta->setData(kKeyOpusHeader, 0, data, size);
952     mMeta->setInt32(kKeySampleRate, kOpusSampleRate);
953     mMeta->setInt32(kKeyChannelCount, mChannelCount);
954     mMeta->setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
955     mMeta->setInt64(kKeyOpusCodecDelay /* ns */,
956             mCodecDelay /* sample/s */ * 1000000000 / kOpusSampleRate);
957 
958     return OK;
959 }
960 
verifyOpusComments(MediaBuffer * buffer)961 status_t MyOpusExtractor::verifyOpusComments(MediaBuffer *buffer) {
962     // add artificial framing bit so we can reuse _vorbis_unpack_comment
963     int32_t commentSize = buffer->range_length() + 1;
964     sp<ABuffer> aBuf = new ABuffer(commentSize);
965     if (aBuf->capacity() <= buffer->range_length()) {
966         return ERROR_MALFORMED;
967     }
968 
969     uint8_t* commentData = aBuf->data();
970     memcpy(commentData,
971             (uint8_t *)buffer->data() + buffer->range_offset(),
972             buffer->range_length());
973 
974     ogg_buffer buf;
975     buf.data = commentData;
976     buf.size = commentSize;
977     buf.refcount = 1;
978     buf.ptr.owner = NULL;
979 
980     ogg_reference ref;
981     ref.buffer = &buf;
982     ref.begin = 0;
983     ref.length = commentSize;
984     ref.next = NULL;
985 
986     oggpack_buffer bits;
987     oggpack_readinit(&bits, &ref);
988 
989     // skip 'OpusTags'
990     const char *OpusTags = "OpusTags";
991     const int32_t headerLen = strlen(OpusTags);
992     int32_t framingBitOffset = headerLen;
993     for (int i = 0; i < headerLen; ++i) {
994         char chr = oggpack_read(&bits, 8);
995         if (chr != OpusTags[i]) {
996             return ERROR_MALFORMED;
997         }
998     }
999 
1000     int32_t vendorLen = oggpack_read(&bits, 32);
1001     framingBitOffset += 4;
1002     if (vendorLen < 0 || vendorLen > commentSize - 8) {
1003         return ERROR_MALFORMED;
1004     }
1005     // skip vendor string
1006     framingBitOffset += vendorLen;
1007     for (int i = 0; i < vendorLen; ++i) {
1008         oggpack_read(&bits, 8);
1009     }
1010 
1011     int32_t n = oggpack_read(&bits, 32);
1012     framingBitOffset += 4;
1013     if (n < 0 || n > ((commentSize - oggpack_bytes(&bits)) >> 2)) {
1014         return ERROR_MALFORMED;
1015     }
1016     for (int i = 0; i < n; ++i) {
1017         int32_t len = oggpack_read(&bits, 32);
1018         framingBitOffset += 4;
1019         if (len  < 0 || len  > (commentSize - oggpack_bytes(&bits))) {
1020             return ERROR_MALFORMED;
1021         }
1022         framingBitOffset += len;
1023         for (int j = 0; j < len; ++j) {
1024             oggpack_read(&bits, 8);
1025         }
1026     }
1027     if (framingBitOffset < 0 || framingBitOffset >= commentSize) {
1028         return ERROR_MALFORMED;
1029     }
1030     commentData[framingBitOffset] = 1;
1031 
1032     buf.data = commentData + headerLen;
1033     buf.size = commentSize - headerLen;
1034     buf.refcount = 1;
1035     buf.ptr.owner = NULL;
1036 
1037     ref.buffer = &buf;
1038     ref.begin = 0;
1039     ref.length = commentSize - headerLen;
1040     ref.next = NULL;
1041 
1042     oggpack_readinit(&bits, &ref);
1043     int err = _vorbis_unpack_comment(&mVc, &bits);
1044     if (0 != err) {
1045         return ERROR_MALFORMED;
1046     }
1047 
1048     parseFileMetaData();
1049     return OK;
1050 }
1051 
verifyHeader(MediaBuffer * buffer,uint8_t type)1052 status_t MyVorbisExtractor::verifyHeader(
1053         MediaBuffer *buffer, uint8_t type) {
1054     const uint8_t *data =
1055         (const uint8_t *)buffer->data() + buffer->range_offset();
1056 
1057     size_t size = buffer->range_length();
1058 
1059     if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
1060         return ERROR_MALFORMED;
1061     }
1062 
1063     ogg_buffer buf;
1064     buf.data = (uint8_t *)data;
1065     buf.size = size;
1066     buf.refcount = 1;
1067     buf.ptr.owner = NULL;
1068 
1069     ogg_reference ref;
1070     ref.buffer = &buf;
1071     ref.begin = 0;
1072     ref.length = size;
1073     ref.next = NULL;
1074 
1075     oggpack_buffer bits;
1076     oggpack_readinit(&bits, &ref);
1077 
1078     if (oggpack_read(&bits, 8) != type) {
1079         return ERROR_MALFORMED;
1080     }
1081     for (size_t i = 0; i < 6; ++i) {
1082         oggpack_read(&bits, 8);  // skip 'vorbis'
1083     }
1084 
1085     switch (type) {
1086         case 1:
1087         {
1088             if (0 != _vorbis_unpack_info(&mVi, &bits)) {
1089                 return ERROR_MALFORMED;
1090             }
1091 
1092             mMeta->setData(kKeyVorbisInfo, 0, data, size);
1093             mMeta->setInt32(kKeySampleRate, mVi.rate);
1094             mMeta->setInt32(kKeyChannelCount, mVi.channels);
1095 
1096             ALOGV("lower-bitrate = %ld", mVi.bitrate_lower);
1097             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
1098             ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
1099             ALOGV("window-bitrate = %ld", mVi.bitrate_window);
1100             ALOGV("blocksizes: %d/%d",
1101                     vorbis_info_blocksize(&mVi, 0),
1102                     vorbis_info_blocksize(&mVi, 1)
1103                     );
1104 
1105             off64_t size;
1106             if (mSource->getSize(&size) == OK) {
1107                 uint64_t bps = approxBitrate();
1108                 if (bps != 0) {
1109                     mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
1110                 }
1111             }
1112             break;
1113         }
1114 
1115         case 3:
1116         {
1117             if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
1118                 return ERROR_MALFORMED;
1119             }
1120 
1121             parseFileMetaData();
1122             break;
1123         }
1124 
1125         case 5:
1126         {
1127             if (0 != _vorbis_unpack_books(&mVi, &bits)) {
1128                 return ERROR_MALFORMED;
1129             }
1130 
1131             mMeta->setData(kKeyVorbisBooks, 0, data, size);
1132             break;
1133         }
1134     }
1135 
1136     return OK;
1137 }
1138 
approxBitrate() const1139 uint64_t MyVorbisExtractor::approxBitrate() const {
1140     if (mVi.bitrate_nominal != 0) {
1141         return mVi.bitrate_nominal;
1142     }
1143 
1144     return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
1145 }
1146 
parseFileMetaData()1147 void MyOggExtractor::parseFileMetaData() {
1148     mFileMeta = new MetaData;
1149     mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
1150 
1151     for (int i = 0; i < mVc.comments; ++i) {
1152         const char *comment = mVc.user_comments[i];
1153         size_t commentLength = mVc.comment_lengths[i];
1154         parseVorbisComment(mFileMeta, comment, commentLength);
1155         //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
1156     }
1157 }
1158 
parseVorbisComment(const sp<MetaData> & fileMeta,const char * comment,size_t commentLength)1159 void parseVorbisComment(
1160         const sp<MetaData> &fileMeta, const char *comment, size_t commentLength)
1161 {
1162     struct {
1163         const char *const mTag;
1164         uint32_t mKey;
1165     } kMap[] = {
1166         { "TITLE", kKeyTitle },
1167         { "ARTIST", kKeyArtist },
1168         { "ALBUMARTIST", kKeyAlbumArtist },
1169         { "ALBUM ARTIST", kKeyAlbumArtist },
1170         { "COMPILATION", kKeyCompilation },
1171         { "ALBUM", kKeyAlbum },
1172         { "COMPOSER", kKeyComposer },
1173         { "GENRE", kKeyGenre },
1174         { "AUTHOR", kKeyAuthor },
1175         { "TRACKNUMBER", kKeyCDTrackNumber },
1176         { "DISCNUMBER", kKeyDiscNumber },
1177         { "DATE", kKeyDate },
1178         { "YEAR", kKeyYear },
1179         { "LYRICIST", kKeyWriter },
1180         { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
1181         { "ANDROID_LOOP", kKeyAutoLoop },
1182     };
1183 
1184         for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
1185             size_t tagLen = strlen(kMap[j].mTag);
1186             if (!strncasecmp(kMap[j].mTag, comment, tagLen)
1187                     && comment[tagLen] == '=') {
1188                 if (kMap[j].mKey == kKeyAlbumArt) {
1189                     extractAlbumArt(
1190                             fileMeta,
1191                             &comment[tagLen + 1],
1192                             commentLength - tagLen - 1);
1193                 } else if (kMap[j].mKey == kKeyAutoLoop) {
1194                     if (!strcasecmp(&comment[tagLen + 1], "true")) {
1195                         fileMeta->setInt32(kKeyAutoLoop, true);
1196                     }
1197                 } else {
1198                     fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
1199                 }
1200             }
1201         }
1202 
1203 }
1204 
1205 // The returned buffer should be free()d.
DecodeBase64(const char * s,size_t size,size_t * outSize)1206 static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
1207     *outSize = 0;
1208 
1209     if ((size % 4) != 0) {
1210         return NULL;
1211     }
1212 
1213     size_t n = size;
1214     size_t padding = 0;
1215     if (n >= 1 && s[n - 1] == '=') {
1216         padding = 1;
1217 
1218         if (n >= 2 && s[n - 2] == '=') {
1219             padding = 2;
1220         }
1221     }
1222 
1223     size_t outLen = 3 * size / 4 - padding;
1224 
1225     *outSize = outLen;
1226 
1227     void *buffer = malloc(outLen);
1228 
1229     uint8_t *out = (uint8_t *)buffer;
1230     size_t j = 0;
1231     uint32_t accum = 0;
1232     for (size_t i = 0; i < n; ++i) {
1233         char c = s[i];
1234         unsigned value;
1235         if (c >= 'A' && c <= 'Z') {
1236             value = c - 'A';
1237         } else if (c >= 'a' && c <= 'z') {
1238             value = 26 + c - 'a';
1239         } else if (c >= '0' && c <= '9') {
1240             value = 52 + c - '0';
1241         } else if (c == '+') {
1242             value = 62;
1243         } else if (c == '/') {
1244             value = 63;
1245         } else if (c != '=') {
1246             return NULL;
1247         } else {
1248             if (i < n - padding) {
1249                 return NULL;
1250             }
1251 
1252             value = 0;
1253         }
1254 
1255         accum = (accum << 6) | value;
1256 
1257         if (((i + 1) % 4) == 0) {
1258             out[j++] = (accum >> 16);
1259 
1260             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
1261             if (j < outLen) { out[j++] = accum & 0xff; }
1262 
1263             accum = 0;
1264         }
1265     }
1266 
1267     return (uint8_t *)buffer;
1268 }
1269 
extractAlbumArt(const sp<MetaData> & fileMeta,const void * data,size_t size)1270 static void extractAlbumArt(
1271         const sp<MetaData> &fileMeta, const void *data, size_t size) {
1272     ALOGV("extractAlbumArt from '%s'", (const char *)data);
1273 
1274     size_t flacSize;
1275     uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
1276 
1277     if (flac == NULL) {
1278         ALOGE("malformed base64 encoded data.");
1279         return;
1280     }
1281 
1282     ALOGV("got flac of size %zu", flacSize);
1283 
1284     uint32_t picType;
1285     uint32_t typeLen;
1286     uint32_t descLen;
1287     uint32_t dataLen;
1288     char type[128];
1289 
1290     if (flacSize < 8) {
1291         goto exit;
1292     }
1293 
1294     picType = U32_AT(flac);
1295 
1296     if (picType != 3) {
1297         // This is not a front cover.
1298         goto exit;
1299     }
1300 
1301     typeLen = U32_AT(&flac[4]);
1302     if (typeLen > sizeof(type) - 1) {
1303         goto exit;
1304     }
1305 
1306     // we've already checked above that flacSize >= 8
1307     if (flacSize - 8 < typeLen) {
1308         goto exit;
1309     }
1310 
1311     memcpy(type, &flac[8], typeLen);
1312     type[typeLen] = '\0';
1313 
1314     ALOGV("picType = %d, type = '%s'", picType, type);
1315 
1316     if (!strcmp(type, "-->")) {
1317         // This is not inline cover art, but an external url instead.
1318         goto exit;
1319     }
1320 
1321     descLen = U32_AT(&flac[8 + typeLen]);
1322 
1323     if (flacSize < 32 ||
1324         flacSize - 32 < typeLen ||
1325         flacSize - 32 - typeLen < descLen) {
1326         goto exit;
1327     }
1328 
1329     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
1330 
1331 
1332     // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
1333     if (flacSize - 32 - typeLen - descLen < dataLen) {
1334         goto exit;
1335     }
1336 
1337     ALOGV("got image data, %zu trailing bytes",
1338          flacSize - 32 - typeLen - descLen - dataLen);
1339 
1340     fileMeta->setData(
1341             kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
1342 
1343     fileMeta->setCString(kKeyAlbumArtMIME, type);
1344 
1345 exit:
1346     free(flac);
1347     flac = NULL;
1348 }
1349 
1350 ////////////////////////////////////////////////////////////////////////////////
1351 
OggExtractor(const sp<DataSource> & source)1352 OggExtractor::OggExtractor(const sp<DataSource> &source)
1353     : mDataSource(source),
1354       mInitCheck(NO_INIT),
1355       mImpl(NULL) {
1356     for (int i = 0; i < 2; ++i) {
1357         if (mImpl != NULL) {
1358             delete mImpl;
1359         }
1360         if (i == 0) {
1361             mImpl = new MyVorbisExtractor(mDataSource);
1362         } else {
1363             mImpl = new MyOpusExtractor(mDataSource);
1364         }
1365         mInitCheck = mImpl->seekToOffset(0);
1366 
1367         if (mInitCheck == OK) {
1368             mInitCheck = mImpl->init();
1369             if (mInitCheck == OK) {
1370                 break;
1371             }
1372         }
1373     }
1374 }
1375 
~OggExtractor()1376 OggExtractor::~OggExtractor() {
1377     delete mImpl;
1378     mImpl = NULL;
1379 }
1380 
countTracks()1381 size_t OggExtractor::countTracks() {
1382     return mInitCheck != OK ? 0 : 1;
1383 }
1384 
getTrack(size_t index)1385 sp<MediaSource> OggExtractor::getTrack(size_t index) {
1386     if (index >= 1) {
1387         return NULL;
1388     }
1389 
1390     return new OggSource(this);
1391 }
1392 
getTrackMetaData(size_t index,uint32_t)1393 sp<MetaData> OggExtractor::getTrackMetaData(
1394         size_t index, uint32_t /* flags */) {
1395     if (index >= 1) {
1396         return NULL;
1397     }
1398 
1399     return mImpl->getFormat();
1400 }
1401 
getMetaData()1402 sp<MetaData> OggExtractor::getMetaData() {
1403     return mImpl->getFileMetaData();
1404 }
1405 
SniffOgg(const sp<DataSource> & source,String8 * mimeType,float * confidence,sp<AMessage> *)1406 bool SniffOgg(
1407         const sp<DataSource> &source, String8 *mimeType, float *confidence,
1408         sp<AMessage> *) {
1409     char tmp[4];
1410     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
1411         return false;
1412     }
1413 
1414     mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
1415     *confidence = 0.2f;
1416 
1417     return true;
1418 }
1419 
1420 }  // namespace android
1421