1ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber/* 2ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * Copyright (C) 2010 The Android Open Source Project 3ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * 4ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * you may not use this file except in compliance with the License. 6ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * You may obtain a copy of the License at 7ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * 8ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * 10ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * Unless required by applicable law or agreed to in writing, software 11ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * See the License for the specific language governing permissions and 14ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber * limitations under the License. 15ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber */ 16ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 17ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber//#define LOG_NDEBUG 0 18ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#define LOG_TAG "OggExtractor" 19ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <utils/Log.h> 20ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2175226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen#include "OggExtractor.h" 22ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 23ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <cutils/properties.h> 242a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen#include <media/DataSourceBase.h> 25a1a005fc01118685c92e723c8dcf7afeffc9d59cMarco Nelissen#include <media/ExtractorUtils.h> 263d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen#include <media/MediaTrack.h> 273d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen#include <media/VorbisComment.h> 288c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih#include <media/stagefright/foundation/ABuffer.h> 29f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong#include <media/stagefright/foundation/ADebug.h> 3059acbe2b82b2678d5614c7bfdd8684521bed23fcWonsik Kim#include <media/stagefright/foundation/base64.h> 31607612858f3afad1ade51a098aafa2a41523b5f7Dongwon Kang#include <media/stagefright/foundation/ByteUtils.h> 321889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang#include <media/stagefright/MediaBufferBase.h> 33ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <media/stagefright/MediaBufferGroup.h> 34ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <media/stagefright/MediaDefs.h> 35ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <media/stagefright/MediaErrors.h> 363d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen#include <media/stagefright/MetaDataBase.h> 37ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#include <utils/String8.h> 38ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 39ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huberextern "C" { 40ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber #include <Tremolo/codec_internal.h> 41ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 42ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb); 43ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb); 44ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb); 457a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); 46ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 47ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 48ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Hubernamespace android { 49ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 503d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstruct OggSource : public MediaTrack { 517d880c31d2079299000b036c6ae742dc695a5b19Marco Nelissen explicit OggSource(OggExtractor *extractor); 52ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 533d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen virtual status_t getFormat(MetaDataBase &); 54ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 553d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen virtual status_t start(MetaDataBase *params = NULL); 56ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber virtual status_t stop(); 57ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 58ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber virtual status_t read( 591889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase **buffer, const ReadOptions *options = NULL); 60ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 61ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huberprotected: 62ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber virtual ~OggSource(); 63ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 64ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huberprivate: 657d880c31d2079299000b036c6ae742dc695a5b19Marco Nelissen OggExtractor *mExtractor; 66ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber bool mStarted; 67ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 68ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber OggSource(const OggSource &); 69ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber OggSource &operator=(const OggSource &); 70ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber}; 71ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 728c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstruct MyOggExtractor { 738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih MyOggExtractor( 742a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *source, 758c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const char *mimeType, 768c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih size_t numHeaders, 778c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int64_t seekPreRollUs); 788c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual ~MyOggExtractor(); 79ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 803d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen status_t getFormat(MetaDataBase &) const; 81ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 82ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // Returns an approximate bitrate in bits per second. 838c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual uint64_t approxBitrate() const = 0; 84ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 853fd91baee812919f53a85c5c05f32606313f8334Andreas Huber status_t seekToTime(int64_t timeUs); 86c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong status_t seekToOffset(off64_t offset); 871889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t readNextPacket(MediaBufferBase **buffer) = 0; 88ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 895a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber status_t init(); 90ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 913d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen status_t getFileMetaData(MetaDataBase &meta) { 923d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen meta = mFileMeta; 933d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return OK; 943d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen } 954595be952e3b1d6776a023e3f447c057797f1505Andreas Huber 968c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihprotected: 97ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber struct Page { 98ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint64_t mGranulePosition; 997a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen int32_t mPrevPacketSize; 1007a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen uint64_t mPrevPacketPos; 101ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint32_t mSerialNo; 102ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint32_t mPageNo; 103ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint8_t mFlags; 104ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint8_t mNumSegments; 105ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint8_t mLace[255]; 106ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber }; 107ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1083fd91baee812919f53a85c5c05f32606313f8334Andreas Huber struct TOCEntry { 1093fd91baee812919f53a85c5c05f32606313f8334Andreas Huber off64_t mPageOffset; 1103fd91baee812919f53a85c5c05f32606313f8334Andreas Huber int64_t mTimeUs; 1113fd91baee812919f53a85c5c05f32606313f8334Andreas Huber }; 1123fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 1132a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *mSource; 114c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t mOffset; 115ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber Page mCurrentPage; 1168c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint64_t mCurGranulePosition; 117db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber uint64_t mPrevGranulePosition; 118ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t mCurrentPageSize; 119db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber bool mFirstPacketInPage; 120db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber uint64_t mCurrentPageSamples; 121ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t mNextLaceIndex; 122ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1238c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const char *mMimeType; 1248c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih size_t mNumHeaders; 1258c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int64_t mSeekPreRollUs; 1268c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 127c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t mFirstDataOffset; 12896f52cde23982f668592418a9548045237d5e327Andreas Huber 129ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber vorbis_info mVi; 130ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber vorbis_comment mVc; 131ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1323d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen MetaDataBase mMeta; 1333d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen MetaDataBase mFileMeta; 134ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1353fd91baee812919f53a85c5c05f32606313f8334Andreas Huber Vector<TOCEntry> mTableOfContents; 1363fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 137c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong ssize_t readPage(off64_t offset, Page *page); 138c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong status_t findNextPage(off64_t startOffset, off64_t *pageOffset); 139ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1408c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const = 0; 1418c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1428c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // Extract codec format, metadata tags, and various codec specific data; 1438c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // the format and CSD's are required to setup the decoders for the enclosed media content. 1448c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // 1458c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // Valid values for `type` are: 1468c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // 1 - bitstream identification header 1478c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // 3 - comment header 1488c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // 5 - codec setup header (Vorbis only) 1491889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0; 1508c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1518c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // Read the next ogg packet from the underlying data source; optionally 1528c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // calculate the timestamp for the output packet whilst pretending 1538c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // that we are parsing an Ogg Vorbis stream. 1548c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // 1558c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated; 1568c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // clients are responsible for releasing the original buffer. 1571889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp); 158ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1591889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang int32_t getPacketBlockSize(MediaBufferBase *buffer); 1607a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 1614595be952e3b1d6776a023e3f447c057797f1505Andreas Huber void parseFileMetaData(); 1624595be952e3b1d6776a023e3f447c057797f1505Andreas Huber 1633fd91baee812919f53a85c5c05f32606313f8334Andreas Huber status_t findPrevGranulePosition(off64_t pageOffset, uint64_t *granulePos); 1643fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 1653fd91baee812919f53a85c5c05f32606313f8334Andreas Huber void buildTableOfContents(); 166db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 1678c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih MyOggExtractor(const MyOggExtractor &); 1688c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih MyOggExtractor &operator=(const MyOggExtractor &); 1698c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih}; 1708c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1718c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstruct MyVorbisExtractor : public MyOggExtractor { 1722a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen explicit MyVorbisExtractor(DataSourceBase *source) 1738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih : MyOggExtractor(source, 1748c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih MEDIA_MIMETYPE_AUDIO_VORBIS, 1758c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih /* numHeaders */ 3, 1768c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih /* seekPreRollUs */ 0) { 1778c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 1788c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1798c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual uint64_t approxBitrate() const; 1808c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1811889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t readNextPacket(MediaBufferBase **buffer) { 1828c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true); 1838c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 1848c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1858c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihprotected: 1868c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const { 187894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker if (granulePos > INT64_MAX / 1000000ll) { 188894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker return INT64_MAX; 189894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker } 1908c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return granulePos * 1000000ll / mVi.rate; 1918c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 1928c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1931889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type); 1948c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih}; 1958c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 1968c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstruct MyOpusExtractor : public MyOggExtractor { 1978c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih static const int32_t kOpusSampleRate = 48000; 1988c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih static const int64_t kOpusSeekPreRollUs = 80000; // 80 ms 1998c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2002a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen explicit MyOpusExtractor(DataSourceBase *source) 2018c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih : MyOggExtractor(source, MEDIA_MIMETYPE_AUDIO_OPUS, /*numHeaders*/ 2, kOpusSeekPreRollUs), 2028c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mChannelCount(0), 203819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mCodecDelay(0), 204819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mStartGranulePosition(-1) { 2058c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 2068c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2078c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual uint64_t approxBitrate() const { 2088c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return 0; 2098c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 2108c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2111889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t readNextPacket(MediaBufferBase **buffer); 2128c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2138c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihprotected: 2148c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const; 2151889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type); 2168c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2178c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihprivate: 2181889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang status_t verifyOpusHeader(MediaBufferBase *buffer); 2191889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang status_t verifyOpusComments(MediaBufferBase *buffer); 2201889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang uint32_t getNumSamplesInPacket(MediaBufferBase *buffer) const; 2218c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2228c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint8_t mChannelCount; 2238c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint16_t mCodecDelay; 224819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih int64_t mStartGranulePosition; 225ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber}; 226ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 227ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber//////////////////////////////////////////////////////////////////////////////// 228ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2297d880c31d2079299000b036c6ae742dc695a5b19Marco NelissenOggSource::OggSource(OggExtractor *extractor) 230ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber : mExtractor(extractor), 231ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mStarted(false) { 232ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 233ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 234ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas HuberOggSource::~OggSource() { 235ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mStarted) { 236ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber stop(); 237ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 238ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 239ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2403d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstatus_t OggSource::getFormat(MetaDataBase &meta) { 2413d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return mExtractor->mImpl->getFormat(meta); 242ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 243ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2443d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstatus_t OggSource::start(MetaDataBase * /* params */) { 245ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mStarted) { 246ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return INVALID_OPERATION; 247ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 248ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 249ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mStarted = true; 250ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 251ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 252ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 253ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 254ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huberstatus_t OggSource::stop() { 255ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mStarted = false; 256ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 257ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 258ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 259ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 260ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huberstatus_t OggSource::read( 2611889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase **out, const ReadOptions *options) { 262ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *out = NULL; 263ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 264ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int64_t seekTimeUs; 265abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber ReadOptions::SeekMode mode; 266abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber if (options && options->getSeekTo(&seekTimeUs, &mode)) { 2678c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih status_t err = mExtractor->mImpl->seekToTime(seekTimeUs); 2688c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (err != OK) { 2698c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return err; 270ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 271ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 272ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2731889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *packet; 2748c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih status_t err = mExtractor->mImpl->readNextPacket(&packet); 275ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 276ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (err != OK) { 277ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return err; 278ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 279ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 280ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#if 0 281ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int64_t timeUs; 2823d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen if (packet->meta_data().findInt64(kKeyTime, &timeUs)) { 283df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block ALOGI("found time = %lld us", timeUs); 284ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } else { 285df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block ALOGI("NO time"); 286ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 287ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#endif 288ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2893d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen packet->meta_data().setInt32(kKeyIsSyncFrame, 1); 2908bf59e735760af0b6a85747fd90bf8cf1e5388d7Andreas Huber 291ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *out = packet; 292ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 293ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 294ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 295ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 296ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber//////////////////////////////////////////////////////////////////////////////// 297ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 2988c10a80cf1af68f15eb39552ca116ec6f04fc173Robert ShihMyOggExtractor::MyOggExtractor( 2992a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *source, 3008c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const char *mimeType, 3018c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih size_t numHeaders, 3028c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int64_t seekPreRollUs) 303ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber : mSource(source), 304ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mOffset(0), 3058c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mCurGranulePosition(0), 306db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mPrevGranulePosition(0), 307ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mCurrentPageSize(0), 308db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mFirstPacketInPage(true), 309db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mCurrentPageSamples(0), 31096f52cde23982f668592418a9548045237d5e327Andreas Huber mNextLaceIndex(0), 3118c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mMimeType(mimeType), 3128c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mNumHeaders(numHeaders), 3138c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mSeekPreRollUs(seekPreRollUs), 31496f52cde23982f668592418a9548045237d5e327Andreas Huber mFirstDataOffset(-1) { 315ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mCurrentPage.mNumSegments = 0; 3164595be952e3b1d6776a023e3f447c057797f1505Andreas Huber 3174595be952e3b1d6776a023e3f447c057797f1505Andreas Huber vorbis_info_init(&mVi); 3184595be952e3b1d6776a023e3f447c057797f1505Andreas Huber vorbis_comment_init(&mVc); 319ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 320ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 3218c10a80cf1af68f15eb39552ca116ec6f04fc173Robert ShihMyOggExtractor::~MyOggExtractor() { 3224595be952e3b1d6776a023e3f447c057797f1505Andreas Huber vorbis_comment_clear(&mVc); 3234595be952e3b1d6776a023e3f447c057797f1505Andreas Huber vorbis_info_clear(&mVi); 324ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 325ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 3263d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstatus_t MyOggExtractor::getFormat(MetaDataBase &meta) const { 3273d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen meta = mMeta; 3283d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return OK; 329ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 330ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 3318c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstatus_t MyOggExtractor::findNextPage( 332c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t startOffset, off64_t *pageOffset) { 333ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *pageOffset = startOffset; 334ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 335ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (;;) { 336ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber char signature[4]; 337ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ssize_t n = mSource->readAt(*pageOffset, &signature, 4); 338ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 339ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (n < 4) { 340ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *pageOffset = 0; 341ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 342ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM; 343ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 344ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 345ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (!memcmp(signature, "OggS", 4)) { 346ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (*pageOffset > startOffset) { 3473856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("skipped %lld bytes of junk to reach next frame", 348ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar (long long)(*pageOffset - startOffset)); 349ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 350ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 351ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 352ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 353ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 354ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ++*pageOffset; 355ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 356ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 357ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 358db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber// Given the offset of the "current" page, find the page immediately preceding 359db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber// it (if any) and return its granule position. 360db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber// To do this we back up from the "current" page's offset until we find any 361db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber// page preceding it and then scan forward to just before the current page. 3628c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstatus_t MyOggExtractor::findPrevGranulePosition( 3633fd91baee812919f53a85c5c05f32606313f8334Andreas Huber off64_t pageOffset, uint64_t *granulePos) { 3643fd91baee812919f53a85c5c05f32606313f8334Andreas Huber *granulePos = 0; 3653fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 366c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t prevPageOffset = 0; 367c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t prevGuess = pageOffset; 368db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber for (;;) { 369db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (prevGuess >= 5000) { 370db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber prevGuess -= 5000; 371db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } else { 372db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber prevGuess = 0; 373db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 374db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 375ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar ALOGV("backing up %lld bytes", (long long)(pageOffset - prevGuess)); 376db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 3773fd91baee812919f53a85c5c05f32606313f8334Andreas Huber status_t err = findNextPage(prevGuess, &prevPageOffset); 3788c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (err == ERROR_END_OF_STREAM) { 3798c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // We are at the last page and didn't back off enough; 3808c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // back off 5000 bytes more and try again. 3818c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih continue; 3828c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } else if (err != OK) { 3833fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return err; 3843fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 385db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 386db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (prevPageOffset < pageOffset || prevGuess == 0) { 387db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber break; 388db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 389db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 390db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 391db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (prevPageOffset == pageOffset) { 392db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber // We did not find a page preceding this one. 3933fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return UNKNOWN_ERROR; 394db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 395db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 3963856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("prevPageOffset at %lld, pageOffset at %lld", 397ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar (long long)prevPageOffset, (long long)pageOffset); 398db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 399db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber for (;;) { 400db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber Page prevPage; 401db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber ssize_t n = readPage(prevPageOffset, &prevPage); 402db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 403db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (n <= 0) { 4043fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return (status_t)n; 405db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 406db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 407db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber prevPageOffset += n; 408db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 409db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (prevPageOffset == pageOffset) { 4103fd91baee812919f53a85c5c05f32606313f8334Andreas Huber *granulePos = prevPage.mGranulePosition; 4113fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return OK; 412db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 413db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 414db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber} 415db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 4168c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstatus_t MyOggExtractor::seekToTime(int64_t timeUs) { 4178c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih timeUs -= mSeekPreRollUs; 4188c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (timeUs < 0) { 4198c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih timeUs = 0; 4208c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 4218c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 4223fd91baee812919f53a85c5c05f32606313f8334Andreas Huber if (mTableOfContents.isEmpty()) { 4233fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // Perform approximate seeking based on avg. bitrate. 4248c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint64_t bps = approxBitrate(); 4258c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (bps <= 0) { 4268c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return INVALID_OPERATION; 4278c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 4283fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4298c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih off64_t pos = timeUs * bps / 8000000ll; 4303fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 431ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar ALOGV("seeking to offset %lld", (long long)pos); 4323fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return seekToOffset(pos); 4333fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 4343fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4353fd91baee812919f53a85c5c05f32606313f8334Andreas Huber size_t left = 0; 436225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar size_t right_plus_one = mTableOfContents.size(); 437225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar while (left < right_plus_one) { 438225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar size_t center = left + (right_plus_one - left) / 2; 4393fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4403fd91baee812919f53a85c5c05f32606313f8334Andreas Huber const TOCEntry &entry = mTableOfContents.itemAt(center); 4413fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4423fd91baee812919f53a85c5c05f32606313f8334Andreas Huber if (timeUs < entry.mTimeUs) { 443225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar right_plus_one = center; 4443fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } else if (timeUs > entry.mTimeUs) { 4453fd91baee812919f53a85c5c05f32606313f8334Andreas Huber left = center + 1; 4463fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } else { 447225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar left = center; 4483fd91baee812919f53a85c5c05f32606313f8334Andreas Huber break; 4493fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 4503fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 4513fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 452225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar if (left == mTableOfContents.size()) { 453225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar --left; 454225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar } 455225d5b20409fd400bfa4ed5e9bc1d5babb498471Lajos Molnar 4563fd91baee812919f53a85c5c05f32606313f8334Andreas Huber const TOCEntry &entry = mTableOfContents.itemAt(left); 4573fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 458a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("seeking to entry %zu / %zu at offset %lld", 459ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar left, mTableOfContents.size(), (long long)entry.mPageOffset); 4603fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4613fd91baee812919f53a85c5c05f32606313f8334Andreas Huber return seekToOffset(entry.mPageOffset); 4623fd91baee812919f53a85c5c05f32606313f8334Andreas Huber} 4633fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 4648c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstatus_t MyOggExtractor::seekToOffset(off64_t offset) { 46596f52cde23982f668592418a9548045237d5e327Andreas Huber if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) { 46696f52cde23982f668592418a9548045237d5e327Andreas Huber // Once we know where the actual audio data starts (past the headers) 46796f52cde23982f668592418a9548045237d5e327Andreas Huber // don't ever seek to anywhere before that. 46896f52cde23982f668592418a9548045237d5e327Andreas Huber offset = mFirstDataOffset; 46996f52cde23982f668592418a9548045237d5e327Andreas Huber } 47096f52cde23982f668592418a9548045237d5e327Andreas Huber 471c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t pageOffset; 472ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber status_t err = findNextPage(offset, &pageOffset); 473ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 474ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (err != OK) { 475ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return err; 476ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 477ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 478db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber // We found the page we wanted to seek to, but we'll also need 479db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber // the page preceding it to determine how many valid samples are on 480db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber // this page. 4813fd91baee812919f53a85c5c05f32606313f8334Andreas Huber findPrevGranulePosition(pageOffset, &mPrevGranulePosition); 482db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 483ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mOffset = pageOffset; 484ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 485ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mCurrentPageSize = 0; 486db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mFirstPacketInPage = true; 487db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mCurrentPageSamples = 0; 488ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mCurrentPage.mNumSegments = 0; 4897a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mPrevPacketSize = -1; 490ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mNextLaceIndex = 0; 491ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 492ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // XXX what if new page continues packet from last??? 493ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 494ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 495ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 496ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 4978c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihssize_t MyOggExtractor::readPage(off64_t offset, Page *page) { 498ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint8_t header[27]; 499df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber ssize_t n; 500df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber if ((n = mSource->readAt(offset, header, sizeof(header))) 501ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber < (ssize_t)sizeof(header)) { 502ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar ALOGV("failed to read %zu bytes at offset %#016llx, got %zd bytes", 503ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar sizeof(header), (long long)offset, n); 504ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 505df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber if (n < 0) { 506df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber return n; 507df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber } else if (n == 0) { 508df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber return ERROR_END_OF_STREAM; 509df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber } else { 510df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber return ERROR_IO; 511df659ac173b247b4ad440fb2979ff51ff45e0aa4Andreas Huber } 512ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 513ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 514ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (memcmp(header, "OggS", 4)) { 515ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return ERROR_MALFORMED; 516ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 517ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 518ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (header[4] != 0) { 519ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // Wrong version. 520ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 521ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return ERROR_UNSUPPORTED; 522ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 523ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 524ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mFlags = header[5]; 525ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 526ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (page->mFlags & ~7) { 527ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // Only bits 0-2 are defined in version 0. 528ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return ERROR_MALFORMED; 529ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 530ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 531ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mGranulePosition = U64LE_AT(&header[6]); 532ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 533ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#if 0 534ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber printf("granulePosition = %llu (0x%llx)\n", 535ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mGranulePosition, page->mGranulePosition); 536ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber#endif 537ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 538ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mSerialNo = U32LE_AT(&header[14]); 539ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mPageNo = U32LE_AT(&header[18]); 540ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 541ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber page->mNumSegments = header[26]; 542ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mSource->readAt( 543ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber offset + sizeof(header), page->mLace, page->mNumSegments) 544ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber < (ssize_t)page->mNumSegments) { 545ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return ERROR_IO; 546ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 547ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 548ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t totalSize = 0;; 549ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (size_t i = 0; i < page->mNumSegments; ++i) { 550ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber totalSize += page->mLace[i]; 551ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 552ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 5535a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber#if 0 554ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber String8 tmp; 555ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (size_t i = 0; i < page->mNumSegments; ++i) { 556ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber char x[32]; 557ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]); 558ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 559ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber tmp.append(x); 560ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 561ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 5623856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string()); 5635a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber#endif 564ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 565ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return sizeof(header) + page->mNumSegments + totalSize; 566ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 567ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 5681889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangstatus_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) { 569819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) { 570819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih // The first sample might not start at time 0; find out where by subtracting 571819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih // the number of samples on the first page from the granule position 572819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih // (position of last complete sample) of the first page. This happens 573819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih // the first time before we attempt to read a packet from the first page. 5741889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *mBuf; 575819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih uint32_t numSamples = 0; 576819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih uint64_t curGranulePosition = 0; 577819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih while (true) { 578819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih status_t err = _readNextPacket(&mBuf, /* calcVorbisTimestamp = */false); 579819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih if (err != OK && err != ERROR_END_OF_STREAM) { 580819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih return err; 581819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 582819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih // First two pages are header pages. 583819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih if (err == ERROR_END_OF_STREAM || mCurrentPage.mPageNo > 2) { 58463079e7c8e12cda4eb124fbe565213d30b9ea34cDongwon Kang if (mBuf != NULL) { 58563079e7c8e12cda4eb124fbe565213d30b9ea34cDongwon Kang mBuf->release(); 58663079e7c8e12cda4eb124fbe565213d30b9ea34cDongwon Kang mBuf = NULL; 58763079e7c8e12cda4eb124fbe565213d30b9ea34cDongwon Kang } 588819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih break; 589819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 590819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih curGranulePosition = mCurrentPage.mGranulePosition; 591819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih numSamples += getNumSamplesInPacket(mBuf); 592819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mBuf->release(); 593819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mBuf = NULL; 594819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 595819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih 596819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih if (curGranulePosition > numSamples) { 597819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mStartGranulePosition = curGranulePosition - numSamples; 598819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } else { 599819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih mStartGranulePosition = 0; 600819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 601819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih seekToOffset(0); 602819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 603819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih 6048c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih status_t err = _readNextPacket(out, /* calcVorbisTimestamp = */false); 6058c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (err != OK) { 6068c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return err; 6078c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 6088c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6098c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t currentPageSamples; 6108c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // Calculate timestamps by accumulating durations starting from the first sample of a page; 6118c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // We assume that we only seek to page boundaries. 6123d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen if ((*out)->meta_data().findInt32(kKeyValidSamples, ¤tPageSamples)) { 6138c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // first packet in page 614819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih if (mOffset == mFirstDataOffset) { 615819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih currentPageSamples -= mStartGranulePosition; 6163d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen (*out)->meta_data().setInt32(kKeyValidSamples, currentPageSamples); 617819bcef03907c8df8fc0fa78c0d43db98279ffa9Robert Shih } 6188c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mCurGranulePosition = mCurrentPage.mGranulePosition - currentPageSamples; 6198c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 6208c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6218c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int64_t timeUs = getTimeUsOfGranule(mCurGranulePosition); 6223d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen (*out)->meta_data().setInt64(kKeyTime, timeUs); 6238c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6248c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint32_t frames = getNumSamplesInPacket(*out); 6258c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mCurGranulePosition += frames; 6268c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return OK; 6278c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 6288c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6291889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kanguint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const { 6308c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (buffer == NULL || buffer->range_length() < 1) { 6318c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return 0; 6328c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 6338c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6348c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset(); 6358c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint8_t toc = data[0]; 6368c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint8_t config = (toc >> 3) & 0x1f; 6378c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint32_t frameSizesUs[] = { 6388c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10000, 20000, 40000, 60000, // 0...3 6398c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10000, 20000, 40000, 60000, // 4...7 6408c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10000, 20000, 40000, 60000, // 8...11 6418c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10000, 20000, // 12...13 6428c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10000, 20000, // 14...15 6438c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2500, 5000, 10000, 20000, // 16...19 6448c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2500, 5000, 10000, 20000, // 20...23 6458c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2500, 5000, 10000, 20000, // 24...27 6468c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 2500, 5000, 10000, 20000 // 28...31 6478c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih }; 6488c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint32_t frameSizeUs = frameSizesUs[config]; 6498c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6508c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint32_t numFrames; 6518c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint8_t c = toc & 3; 6528c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih switch (c) { 6538c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 0: 6548c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih numFrames = 1; 6558c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih break; 6568c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 1: 6578c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 2: 6588c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih numFrames = 2; 6598c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih break; 6608c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 3: 6618c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (buffer->range_length() < 3) { 6628c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih numFrames = 0; 6638c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } else { 6648c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih numFrames = data[2] & 0x3f; 6658c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 6668c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih break; 6678c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih default: 6688c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih TRESPASS(); 6698c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 6708c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6718c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint32_t numSamples = frameSizeUs * numFrames * kOpusSampleRate / 1000000; 6728c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return numSamples; 6738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 6748c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 6751889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangstatus_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) { 676ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *out = NULL; 677ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 6781889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *buffer = NULL; 679ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber int64_t timeUs = -1; 680ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 681ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (;;) { 682ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t i; 683ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t packetSize = 0; 684ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber bool gotFullPacket = false; 685ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) { 686ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint8_t lace = mCurrentPage.mLace[i]; 687ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 688ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber packetSize += lace; 689ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 690ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (lace < 255) { 691ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber gotFullPacket = true; 692ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ++i; 693ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber break; 694ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 695ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 696ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 697ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mNextLaceIndex < mCurrentPage.mNumSegments) { 698c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments; 699ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (size_t j = 0; j < mNextLaceIndex; ++j) { 700ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber dataOffset += mCurrentPage.mLace[j]; 701ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 702ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 703ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t fullSize = packetSize; 704ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (buffer != NULL) { 705ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber fullSize += buffer->range_length(); 706ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 707bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen if (fullSize > 16 * 1024 * 1024) { // arbitrary limit of 16 MB packet size 708bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen if (buffer != NULL) { 709bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen buffer->release(); 710bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen } 711bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen ALOGE("b/36592202"); 712bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen return ERROR_MALFORMED; 713bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen } 7141889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *tmp = MediaBufferBase::Create(fullSize); 715bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen if (tmp == NULL) { 716bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen if (buffer != NULL) { 717bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen buffer->release(); 718bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen } 719bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen ALOGE("b/36592202"); 720bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen return ERROR_MALFORMED; 721bf928560aca13c5a615cb3ffc3b6aad16cdf3824Marco Nelissen } 722ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (buffer != NULL) { 723ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber memcpy(tmp->data(), buffer->data(), buffer->range_length()); 724ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber tmp->set_range(0, buffer->range_length()); 725ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buffer->release(); 726ecaccb9f82dd07b29aa32ce36e8d15862dfdf547Andreas Huber } else { 727ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber tmp->set_range(0, 0); 728ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 729ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buffer = tmp; 730ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 731ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ssize_t n = mSource->readAt( 732ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber dataOffset, 733ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber (uint8_t *)buffer->data() + buffer->range_length(), 734ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber packetSize); 735ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 736ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (n < (ssize_t)packetSize) { 737a6f2946f15be11db7c2b013fbe69126a799cbf97Wei Jia buffer->release(); 738ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar ALOGV("failed to read %zu bytes at %#016llx, got %zd bytes", 739ee4e1b1a63758941460ae79a064249d3a5189443Lajos Molnar packetSize, (long long)dataOffset, n); 740ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return ERROR_IO; 741ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 742ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 743ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buffer->set_range(0, fullSize); 744ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 745ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mNextLaceIndex = i; 746ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 747ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (gotFullPacket) { 748ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // We've just read the entire packet. 749ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 750db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber if (mFirstPacketInPage) { 7513d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen buffer->meta_data().setInt32( 752db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber kKeyValidSamples, mCurrentPageSamples); 753db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mFirstPacketInPage = false; 754db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber } 755db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 7568c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (calcVorbisTimestamp) { 7578c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t curBlockSize = getPacketBlockSize(buffer); 7587a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen if (mCurrentPage.mPrevPacketSize < 0) { 7597a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mPrevPacketSize = curBlockSize; 7607a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mPrevPacketPos = 7617a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mGranulePosition - mCurrentPageSamples; 7627a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 7637a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen } else { 7647a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen // The effective block size is the average of the two overlapped blocks 7657a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen int32_t actualBlockSize = 7667a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen (curBlockSize + mCurrentPage.mPrevPacketSize) / 2; 7677a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 7687a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen // The actual size output by the decoder will be half the effective 7697a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen // size, due to the overlap 7707a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mPrevPacketPos += actualBlockSize / 2; 7717a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen mCurrentPage.mPrevPacketSize = curBlockSize; 7727a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen } 7733d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen buffer->meta_data().setInt64(kKeyTime, timeUs); 7747a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen } 775ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *out = buffer; 776ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 777ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 778ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 779ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 780ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // fall through, the buffer now contains the start of the packet. 781ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 782ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 783ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments); 784ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 785ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mOffset += mCurrentPageSize; 786ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ssize_t n = readPage(mOffset, &mCurrentPage); 787ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 788ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (n <= 0) { 789ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (buffer) { 790ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buffer->release(); 791ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buffer = NULL; 792ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 793ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 794a5750e0dad9e90f2195ce36f2c4457fa04b2b83eMark Salyzyn ALOGV("readPage returned %zd", n); 795ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 796ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; 797ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 798ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 7992369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker // Prevent a harmless unsigned integer overflow by clamping to 0 8002369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker if (mCurrentPage.mGranulePosition >= mPrevGranulePosition) { 8012369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker mCurrentPageSamples = 8022369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker mCurrentPage.mGranulePosition - mPrevGranulePosition; 8032369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker } else { 8042369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker mCurrentPageSamples = 0; 8052369bda581ddd379296b57098e119afb0cfa0952Chad Brubaker } 806db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mFirstPacketInPage = true; 807db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 808db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mPrevGranulePosition = mCurrentPage.mGranulePosition; 809db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 810ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mCurrentPageSize = n; 811ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mNextLaceIndex = 0; 812ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 813ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (buffer != NULL) { 814ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if ((mCurrentPage.mFlags & 1) == 0) { 815ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // This page does not continue the packet, i.e. the packet 816ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber // is already complete. 817ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 818ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (timeUs >= 0) { 8193d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen buffer->meta_data().setInt64(kKeyTime, timeUs); 820ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 821ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 8223d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen buffer->meta_data().setInt32( 823db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber kKeyValidSamples, mCurrentPageSamples); 824db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber mFirstPacketInPage = false; 825db6222212528637d8f2afa7f49fc3c8c915bafbeAndreas Huber 826ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *out = buffer; 827ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 828ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return OK; 829ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 830ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 831ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 832ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 833ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 8348c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihstatus_t MyOggExtractor::init() { 8353d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setCString(kKeyMIMEType, mMimeType); 836ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 8375a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber status_t err; 8381889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *packet; 8398c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (size_t i = 0; i < mNumHeaders; ++i) { 8408c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // ignore timestamp for configuration packets 8418c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) { 8428c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return err; 8438c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 8448c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ALOGV("read packet of size %zu\n", packet->range_length()); 8458c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih err = verifyHeader(packet, /* type = */ i * 2 + 1); 8468c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih packet->release(); 8478c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih packet = NULL; 8488c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (err != OK) { 8498c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return err; 8508c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 8515a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber } 85296f52cde23982f668592418a9548045237d5e327Andreas Huber 85396f52cde23982f668592418a9548045237d5e327Andreas Huber mFirstDataOffset = mOffset + mCurrentPageSize; 8545a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber 8553fd91baee812919f53a85c5c05f32606313f8334Andreas Huber off64_t size; 8563fd91baee812919f53a85c5c05f32606313f8334Andreas Huber uint64_t lastGranulePosition; 8572a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen if (!(mSource->flags() & DataSourceBase::kIsCachingDataSource) 8583fd91baee812919f53a85c5c05f32606313f8334Andreas Huber && mSource->getSize(&size) == OK 8593fd91baee812919f53a85c5c05f32606313f8334Andreas Huber && findPrevGranulePosition(size, &lastGranulePosition) == OK) { 8603fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // Let's assume it's cheap to seek to the end. 8613fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // The granule position of the final page in the stream will 8623fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // give us the exact duration of the content, something that 8633fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // we can only approximate using avg. bitrate if seeking to 8643fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // the end is too expensive or impossible (live streaming). 8653fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8668c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int64_t durationUs = getTimeUsOfGranule(lastGranulePosition); 8673fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8683d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt64(kKeyDuration, durationUs); 8693fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8703fd91baee812919f53a85c5c05f32606313f8334Andreas Huber buildTableOfContents(); 8713fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 8723fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8735a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber return OK; 874ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 875ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 8768c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihvoid MyOggExtractor::buildTableOfContents() { 8773fd91baee812919f53a85c5c05f32606313f8334Andreas Huber off64_t offset = mFirstDataOffset; 8783fd91baee812919f53a85c5c05f32606313f8334Andreas Huber Page page; 8793fd91baee812919f53a85c5c05f32606313f8334Andreas Huber ssize_t pageSize; 8803fd91baee812919f53a85c5c05f32606313f8334Andreas Huber while ((pageSize = readPage(offset, &page)) > 0) { 8813fd91baee812919f53a85c5c05f32606313f8334Andreas Huber mTableOfContents.push(); 8823fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8833fd91baee812919f53a85c5c05f32606313f8334Andreas Huber TOCEntry &entry = 8843fd91baee812919f53a85c5c05f32606313f8334Andreas Huber mTableOfContents.editItemAt(mTableOfContents.size() - 1); 8853fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8863fd91baee812919f53a85c5c05f32606313f8334Andreas Huber entry.mPageOffset = offset; 8878c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih entry.mTimeUs = getTimeUsOfGranule(page.mGranulePosition); 8883fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8893fd91baee812919f53a85c5c05f32606313f8334Andreas Huber offset += (size_t)pageSize; 8903fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 8913fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8923fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // Limit the maximum amount of RAM we spend on the table of contents, 8933fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // if necessary thin out the table evenly to trim it down to maximum 8943fd91baee812919f53a85c5c05f32606313f8334Andreas Huber // size. 8953fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8963fd91baee812919f53a85c5c05f32606313f8334Andreas Huber static const size_t kMaxTOCSize = 8192; 8973fd91baee812919f53a85c5c05f32606313f8334Andreas Huber static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry); 8983fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 8993fd91baee812919f53a85c5c05f32606313f8334Andreas Huber size_t numerator = mTableOfContents.size(); 9003fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 9013fd91baee812919f53a85c5c05f32606313f8334Andreas Huber if (numerator > kMaxNumTOCEntries) { 9023fd91baee812919f53a85c5c05f32606313f8334Andreas Huber size_t denom = numerator - kMaxNumTOCEntries; 9033fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 9043fd91baee812919f53a85c5c05f32606313f8334Andreas Huber size_t accum = 0; 9053fd91baee812919f53a85c5c05f32606313f8334Andreas Huber for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) { 9063fd91baee812919f53a85c5c05f32606313f8334Andreas Huber accum += denom; 9073fd91baee812919f53a85c5c05f32606313f8334Andreas Huber if (accum >= numerator) { 9083fd91baee812919f53a85c5c05f32606313f8334Andreas Huber mTableOfContents.removeAt(i); 9093fd91baee812919f53a85c5c05f32606313f8334Andreas Huber accum -= numerator; 9103fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 9113fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 9123fd91baee812919f53a85c5c05f32606313f8334Andreas Huber } 9133fd91baee812919f53a85c5c05f32606313f8334Andreas Huber} 9143fd91baee812919f53a85c5c05f32606313f8334Andreas Huber 9151889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangint32_t MyOggExtractor::getPacketBlockSize(MediaBufferBase *buffer) { 9167a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen const uint8_t *data = 9177a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen (const uint8_t *)buffer->data() + buffer->range_offset(); 9187a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9197a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen size_t size = buffer->range_length(); 9207a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9217a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ogg_buffer buf; 9227a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen buf.data = (uint8_t *)data; 9237a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen buf.size = size; 9247a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen buf.refcount = 1; 9257a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen buf.ptr.owner = NULL; 9267a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9277a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ogg_reference ref; 9287a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ref.buffer = &buf; 9297a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ref.begin = 0; 9307a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ref.length = size; 9317a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ref.next = NULL; 9327a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9337a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ogg_packet pack; 9347a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.packet = &ref; 9357a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.bytes = ref.length; 9367a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.b_o_s = 0; 9377a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.e_o_s = 0; 9387a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.granulepos = 0; 9397a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen pack.packetno = 0; 9407a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9417a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen return vorbis_packet_blocksize(&mVi, &pack); 9427a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen} 9437a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen 9448c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihint64_t MyOpusExtractor::getTimeUsOfGranule(uint64_t granulePos) const { 9458c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih uint64_t pcmSamplePosition = 0; 9468c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (granulePos > mCodecDelay) { 9478c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih pcmSamplePosition = granulePos - mCodecDelay; 9488c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 949894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker if (pcmSamplePosition > INT64_MAX / 1000000ll) { 950894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker return INT64_MAX; 951894aa94e101f9ff9a074f2bcc4d1fb989cf9ea04Chad Brubaker } 9528c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return pcmSamplePosition * 1000000ll / kOpusSampleRate; 9538c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 9548c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9551889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangstatus_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) { 9568c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih switch (type) { 9578c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean 9588c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // header and comments such that we can share code with MyVorbisExtractor. 9598c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 1: 9608c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return verifyOpusHeader(buffer); 9618c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih case 3: 9628c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return verifyOpusComments(buffer); 9638c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih default: 9648c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return INVALID_OPERATION; 9658c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 9668c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 9678c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9681889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangstatus_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) { 9698c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const size_t kOpusHeaderSize = 19; 9708c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const uint8_t *data = 9718c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih (const uint8_t *)buffer->data() + buffer->range_offset(); 9728c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih size_t size = buffer->range_length(); 9748c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9758c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (size < kOpusHeaderSize 9768c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih || memcmp(data, "OpusHead", 8) 9778c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih || /* version = */ data[8] != 1) { 9788c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 9798c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 9808c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9818c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mChannelCount = data[9]; 9828c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mCodecDelay = U16LE_AT(&data[10]); 9838c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9843d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setData(kKeyOpusHeader, 0, data, size); 9853d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt32(kKeySampleRate, kOpusSampleRate); 9863d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt32(kKeyChannelCount, mChannelCount); 9873d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/); 9883d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt64(kKeyOpusCodecDelay /* ns */, 9892d93abfb06455176b7f2fcde0d9fd4dfe7a0973cChad Brubaker mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate); 9908c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9918c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return OK; 9928c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 9938c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 9941889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kangstatus_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) { 9958c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // add artificial framing bit so we can reuse _vorbis_unpack_comment 9968c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t commentSize = buffer->range_length() + 1; 997a1a005fc01118685c92e723c8dcf7afeffc9d59cMarco Nelissen auto tmp = heapbuffer<uint8_t>(commentSize); 998a1a005fc01118685c92e723c8dcf7afeffc9d59cMarco Nelissen uint8_t *commentData = tmp.get(); 9993d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen if (commentData == nullptr) { 10008c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10018c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10028c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10038c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih memcpy(commentData, 10048c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih (uint8_t *)buffer->data() + buffer->range_offset(), 10058c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buffer->range_length()); 10068c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10078c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ogg_buffer buf; 10088c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.data = commentData; 10098c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.size = commentSize; 10108c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.refcount = 1; 10118c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.ptr.owner = NULL; 10128c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10138c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ogg_reference ref; 10148c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.buffer = &buf; 10158c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.begin = 0; 10168c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.length = commentSize; 10178c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.next = NULL; 10188c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10198c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih oggpack_buffer bits; 10208c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih oggpack_readinit(&bits, &ref); 10218c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10228c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // skip 'OpusTags' 10238c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const char *OpusTags = "OpusTags"; 10248c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih const int32_t headerLen = strlen(OpusTags); 10258c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t framingBitOffset = headerLen; 10268c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (int i = 0; i < headerLen; ++i) { 10278c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih char chr = oggpack_read(&bits, 8); 10288c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (chr != OpusTags[i]) { 10298c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10308c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10318c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10328c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10338c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t vendorLen = oggpack_read(&bits, 32); 10348c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih framingBitOffset += 4; 10358c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (vendorLen < 0 || vendorLen > commentSize - 8) { 10368c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10378c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10388c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih // skip vendor string 10398c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih framingBitOffset += vendorLen; 10408c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (int i = 0; i < vendorLen; ++i) { 10418c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih oggpack_read(&bits, 8); 10428c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10438c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10448c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t n = oggpack_read(&bits, 32); 10458c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih framingBitOffset += 4; 10468c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (n < 0 || n > ((commentSize - oggpack_bytes(&bits)) >> 2)) { 10478c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10488c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10498c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (int i = 0; i < n; ++i) { 10508c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int32_t len = oggpack_read(&bits, 32); 10518c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih framingBitOffset += 4; 10528c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (len < 0 || len > (commentSize - oggpack_bytes(&bits))) { 10538c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10548c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10558c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih framingBitOffset += len; 10568c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (int j = 0; j < len; ++j) { 10578c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih oggpack_read(&bits, 8); 10588c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10598c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10608c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (framingBitOffset < 0 || framingBitOffset >= commentSize) { 10618c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10628c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10638c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih commentData[framingBitOffset] = 1; 10648c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10658c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.data = commentData + headerLen; 10668c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.size = commentSize - headerLen; 10678c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.refcount = 1; 10688c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih buf.ptr.owner = NULL; 10698c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10708c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.buffer = &buf; 10718c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.begin = 0; 10728c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.length = commentSize - headerLen; 10738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih ref.next = NULL; 10748c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10758c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih oggpack_readinit(&bits, &ref); 10768c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih int err = _vorbis_unpack_comment(&mVc, &bits); 10778c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (0 != err) { 10788c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return ERROR_MALFORMED; 10798c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 10808c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10818c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih parseFileMetaData(); 10828c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih return OK; 10838c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih} 10848c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih 10855a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huberstatus_t MyVorbisExtractor::verifyHeader( 10861889c3edad32995c0cf26ae2248fe7c957b7ec84Dongwon Kang MediaBufferBase *buffer, uint8_t type) { 1087ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber const uint8_t *data = 1088ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber (const uint8_t *)buffer->data() + buffer->range_offset(); 1089ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1090ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber size_t size = buffer->range_length(); 1091ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 10925a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) { 10935a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber return ERROR_MALFORMED; 10945a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber } 1095ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1096ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ogg_buffer buf; 1097ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buf.data = (uint8_t *)data; 1098ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buf.size = size; 1099ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buf.refcount = 1; 1100ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber buf.ptr.owner = NULL; 1101ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1102ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ogg_reference ref; 1103ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ref.buffer = &buf; 1104ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ref.begin = 0; 1105ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ref.length = size; 1106ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber ref.next = NULL; 1107ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1108ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber oggpack_buffer bits; 1109ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber oggpack_readinit(&bits, &ref); 1110ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1111fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen if (oggpack_read(&bits, 8) != type) { 1112fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen return ERROR_MALFORMED; 1113fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen } 1114ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber for (size_t i = 0; i < 6; ++i) { 1115ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber oggpack_read(&bits, 8); // skip 'vorbis' 1116ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1117ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1118ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber switch (type) { 1119ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber case 1: 1120ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber { 1121fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen if (0 != _vorbis_unpack_info(&mVi, &bits)) { 1122fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen return ERROR_MALFORMED; 1123fe7186bb1567b5725eb8ce61e3267a1733e90c53Marco Nelissen } 1124ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11253d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setData(kKeyVorbisInfo, 0, data, size); 11263d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt32(kKeySampleRate, mVi.rate); 11273d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt32(kKeyChannelCount, mVi.channels); 11283d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt32(kKeyBitRate, mVi.bitrate_nominal); 1129ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11303856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("lower-bitrate = %ld", mVi.bitrate_lower); 11313856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("upper-bitrate = %ld", mVi.bitrate_upper); 11323856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal); 11333856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("window-bitrate = %ld", mVi.bitrate_window); 11347a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ALOGV("blocksizes: %d/%d", 11357a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen vorbis_info_blocksize(&mVi, 0), 11367a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen vorbis_info_blocksize(&mVi, 1) 11377a493d8578bb00cf10190053a4caf1d07f4e24f7Marco Nelissen ); 1138ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1139c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong off64_t size; 1140ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mSource->getSize(&size) == OK) { 1141ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber uint64_t bps = approxBitrate(); 1142f9fb13966a8e6ba039e88a46d096cd1cce2eb283Dongwon Kang if (bps != 0) { 11433d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setInt64(kKeyDuration, size * 8000000ll / bps); 1144f9fb13966a8e6ba039e88a46d096cd1cce2eb283Dongwon Kang } 1145ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1146ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber break; 1147ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1148ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1149ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber case 3: 1150ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber { 11515a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber if (0 != _vorbis_unpack_comment(&mVc, &bits)) { 11525a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber return ERROR_MALFORMED; 11535a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber } 11544595be952e3b1d6776a023e3f447c057797f1505Andreas Huber 11554595be952e3b1d6776a023e3f447c057797f1505Andreas Huber parseFileMetaData(); 1156ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber break; 1157ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1158ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1159ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber case 5: 1160ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber { 11615a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber if (0 != _vorbis_unpack_books(&mVi, &bits)) { 11625a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber return ERROR_MALFORMED; 11635a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber } 1164ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11653d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mMeta.setData(kKeyVorbisBooks, 0, data, size); 1166ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber break; 1167ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1168ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 11695a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber 11705a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber return OK; 1171ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1172ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11738c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shihuint64_t MyVorbisExtractor::approxBitrate() const { 1174ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (mVi.bitrate_nominal != 0) { 1175ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return mVi.bitrate_nominal; 1176ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1177ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1178ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return (mVi.bitrate_lower + mVi.bitrate_upper) / 2; 1179ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1180ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11814595be952e3b1d6776a023e3f447c057797f1505Andreas Huber 118275226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissenvoid MyOggExtractor::parseFileMetaData() { 11833d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen mFileMeta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG); 118475226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 118575226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen for (int i = 0; i < mVc.comments; ++i) { 118675226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen const char *comment = mVc.user_comments[i]; 118775226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen size_t commentLength = mVc.comment_lengths[i]; 11883d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen parseVorbisComment(&mFileMeta, comment, commentLength); 118975226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]); 119075226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen } 119175226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen} 119275226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 119375226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 1194ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber//////////////////////////////////////////////////////////////////////////////// 1195ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 11962a243f08193fe9ff1afe018e9953f01c44ced9deMarco NelissenOggExtractor::OggExtractor(DataSourceBase *source) 1197ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber : mDataSource(source), 1198ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mInitCheck(NO_INIT), 1199ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mImpl(NULL) { 12008c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih for (int i = 0; i < 2; ++i) { 12018c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (mImpl != NULL) { 12028c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih delete mImpl; 12038c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 12048c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (i == 0) { 12058c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mImpl = new MyVorbisExtractor(mDataSource); 12068c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } else { 12078c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mImpl = new MyOpusExtractor(mDataSource); 12088c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 12098c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mInitCheck = mImpl->seekToOffset(0); 1210ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 12118c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (mInitCheck == OK) { 12128c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih mInitCheck = mImpl->init(); 12138c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih if (mInitCheck == OK) { 12148c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih break; 12158c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 12168c10a80cf1af68f15eb39552ca116ec6f04fc173Robert Shih } 12175a4001ddb2536d65d966970fc0579bf6bd11b5a0Andreas Huber } 1218ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1219ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1220ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas HuberOggExtractor::~OggExtractor() { 1221ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber delete mImpl; 1222ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber mImpl = NULL; 1223ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1224ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1225ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Hubersize_t OggExtractor::countTracks() { 1226ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return mInitCheck != OK ? 0 : 1; 1227ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1228ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 12293d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco NelissenMediaTrack *OggExtractor::getTrack(size_t index) { 1230ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (index >= 1) { 1231ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return NULL; 1232ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1233ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1234ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber return new OggSource(this); 1235ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1236ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 12373d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstatus_t OggExtractor::getTrackMetaData( 12383d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen MetaDataBase &meta, 123984333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber size_t index, uint32_t /* flags */) { 1240ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (index >= 1) { 12413d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return UNKNOWN_ERROR; 1242ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1243ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 12443d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return mImpl->getFormat(meta); 1245ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1246ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 12473d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissenstatus_t OggExtractor::getMetaData(MetaDataBase &meta) { 12483d21ae3fad5a894cf15f2e7e7a1d54d0f3d19db0Marco Nelissen return mImpl->getFileMetaData(meta); 1249ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1250ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 125175226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissenstatic MediaExtractor* CreateExtractor( 12522a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *source, 125317e172b4c3c87ecaa7c87eecc42b4dc47e3e9734Dongwon Kang void *) { 125475226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen return new OggExtractor(source); 125575226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen} 125675226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 125775226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissenstatic MediaExtractor::CreatorFunc Sniff( 12582a243f08193fe9ff1afe018e9953f01c44ced9deMarco Nelissen DataSourceBase *source, 125975226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen float *confidence, 126017e172b4c3c87ecaa7c87eecc42b4dc47e3e9734Dongwon Kang void **, 126117e172b4c3c87ecaa7c87eecc42b4dc47e3e9734Dongwon Kang MediaExtractor::FreeMetaFunc *) { 1262ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber char tmp[4]; 1263ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) { 126475226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen return NULL; 1265ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber } 1266ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 1267ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber *confidence = 0.2f; 1268ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 126975226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen return CreateExtractor; 127075226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen} 127175226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 127275226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissenextern "C" { 127375226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen// This is the only symbol that needs to be exported 127475226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen__attribute__ ((visibility ("default"))) 127575226177f20a176d50e3e53bbb34067cb49112c3Marco NelissenMediaExtractor::ExtractorDef GETEXTRACTORDEF() { 127675226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen return { 127775226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen MediaExtractor::EXTRACTORDEF_VERSION, 127875226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"), 127975226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 1, // version 128075226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen "Ogg Extractor", 128175226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen Sniff 128275226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen }; 1283ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} 1284ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber 128575226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen} // extern "C" 128675226177f20a176d50e3e53bbb34067cb49112c3Marco Nelissen 1287ee7ff20e69498ebd53dd9717a0f984188341a75eAndreas Huber} // namespace android 1288