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, &currentPageSamples)) {
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