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