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