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