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, ¤tPageSamples)) {
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