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