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