1388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber/*
2388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * Copyright (C) 2010 The Android Open Source Project
3388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber *
4388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * you may not use this file except in compliance with the License.
6388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * You may obtain a copy of the License at
7388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber *
8388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber *
10388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * Unless required by applicable law or agreed to in writing, software
11388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * See the License for the specific language governing permissions and
14388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber * limitations under the License.
15388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber */
16388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
17388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber//#define LOG_NDEBUG 0
18388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#define LOG_TAG "OggExtractor"
19388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <utils/Log.h>
20388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
21388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include "include/OggExtractor.h"
22388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
23388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <cutils/properties.h>
24388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/DataSource.h>
25388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaBuffer.h>
26388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaBufferGroup.h>
27388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaDebug.h>
28388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaDefs.h>
29388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaErrors.h>
30388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MediaSource.h>
31388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/MetaData.h>
32388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <media/stagefright/Utils.h>
33388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#include <utils/String8.h>
34388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
35388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberextern "C" {
36388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    #include <Tremolo/codec_internal.h>
37388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
38388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
39388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
40388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
41388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
42388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
43388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubernamespace android {
44388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
45388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstruct OggSource : public MediaSource {
46388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    OggSource(const sp<OggExtractor> &extractor);
47388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
48388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual sp<MetaData> getFormat();
49388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
50388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual status_t start(MetaData *params = NULL);
51388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual status_t stop();
52388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
53388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual status_t read(
54388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            MediaBuffer **buffer, const ReadOptions *options = NULL);
55388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
56388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberprotected:
57388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual ~OggSource();
58388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
59388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberprivate:
60388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    sp<OggExtractor> mExtractor;
61388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    bool mStarted;
62388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
63388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    OggSource(const OggSource &);
64388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    OggSource &operator=(const OggSource &);
65388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber};
66388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
67388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstruct MyVorbisExtractor {
68388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MyVorbisExtractor(const sp<DataSource> &source);
69388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    virtual ~MyVorbisExtractor();
70388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
71388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    sp<MetaData> getFormat() const;
72388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
73388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    // Returns an approximate bitrate in bits per second.
74388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    uint64_t approxBitrate();
75388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
76388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    status_t seekToOffset(off_t offset);
77388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    status_t readNextPacket(MediaBuffer **buffer);
78388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
79eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    status_t init();
80388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
81c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    sp<MetaData> getFileMetaData() { return mFileMeta; }
82c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
83388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberprivate:
84388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    struct Page {
85388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint64_t mGranulePosition;
86388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint32_t mSerialNo;
87388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint32_t mPageNo;
88388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint8_t mFlags;
89388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint8_t mNumSegments;
90388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        uint8_t mLace[255];
91388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    };
92388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
93388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    sp<DataSource> mSource;
94388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    off_t mOffset;
95388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    Page mCurrentPage;
9638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    uint64_t mPrevGranulePosition;
97388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    size_t mCurrentPageSize;
9838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    bool mFirstPacketInPage;
9938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    uint64_t mCurrentPageSamples;
100388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    size_t mNextLaceIndex;
101388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
10234c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber    off_t mFirstDataOffset;
10334c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber
104388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    vorbis_info mVi;
105388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    vorbis_comment mVc;
106388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
107388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    sp<MetaData> mMeta;
108c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    sp<MetaData> mFileMeta;
109388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
110388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ssize_t readPage(off_t offset, Page *page);
111388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    status_t findNextPage(off_t startOffset, off_t *pageOffset);
112388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
113eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    status_t verifyHeader(
114388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            MediaBuffer *buffer, uint8_t type);
115388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
116c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    void parseFileMetaData();
117c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    void extractAlbumArt(const void *data, size_t size);
118c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
11938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    uint64_t findPrevGranulePosition(off_t pageOffset);
12038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
121388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MyVorbisExtractor(const MyVorbisExtractor &);
122388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MyVorbisExtractor &operator=(const MyVorbisExtractor &);
123388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber};
124388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
125388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber////////////////////////////////////////////////////////////////////////////////
126388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
127388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberOggSource::OggSource(const sp<OggExtractor> &extractor)
128388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    : mExtractor(extractor),
129388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber      mStarted(false) {
130388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
131388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
132388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberOggSource::~OggSource() {
133388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (mStarted) {
134388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        stop();
135388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
136388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
137388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
138388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersp<MetaData> OggSource::getFormat() {
139388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return mExtractor->mImpl->getFormat();
140388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
141388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
142388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t OggSource::start(MetaData *params) {
143388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (mStarted) {
144388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return INVALID_OPERATION;
145388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
146388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
147388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mStarted = true;
148388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
149388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return OK;
150388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
151388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
152388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t OggSource::stop() {
153388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mStarted = false;
154388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
155388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return OK;
156388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
157388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
158388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t OggSource::read(
159388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        MediaBuffer **out, const ReadOptions *options) {
160388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    *out = NULL;
161388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
162388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int64_t seekTimeUs;
1636624c9fd0bc5e3858a22a04c05b5059445c1c367Andreas Huber    ReadOptions::SeekMode mode;
1646624c9fd0bc5e3858a22a04c05b5059445c1c367Andreas Huber    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
165388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
1663386c38d59fa837f4876a24af821fb9b35314712Andreas Huber        LOGV("seeking to offset %ld", pos);
167388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
168388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (mExtractor->mImpl->seekToOffset(pos) != OK) {
169388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            return ERROR_END_OF_STREAM;
170388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
171388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
172388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
173388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MediaBuffer *packet;
174388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    status_t err = mExtractor->mImpl->readNextPacket(&packet);
175388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
176388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (err != OK) {
177388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return err;
178388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
179388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
180388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#if 0
181388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int64_t timeUs;
182388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
183388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        LOGI("found time = %lld us", timeUs);
184388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    } else {
185388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        LOGI("NO time");
186388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
187388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#endif
188388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
189ad98d383a04fce08a147b200e23b12f12b2681a3Andreas Huber    packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
190ad98d383a04fce08a147b200e23b12f12b2681a3Andreas Huber
191388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    *out = packet;
192388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
193388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return OK;
194388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
195388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
196388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber////////////////////////////////////////////////////////////////////////////////
197388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
198388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberMyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
199388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    : mSource(source),
200388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber      mOffset(0),
20138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber      mPrevGranulePosition(0),
202388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber      mCurrentPageSize(0),
20338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber      mFirstPacketInPage(true),
20438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber      mCurrentPageSamples(0),
20534c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber      mNextLaceIndex(0),
20634c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber      mFirstDataOffset(-1) {
207388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mCurrentPage.mNumSegments = 0;
208c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
209c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    vorbis_info_init(&mVi);
210c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    vorbis_comment_init(&mVc);
211388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
212388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
213388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberMyVorbisExtractor::~MyVorbisExtractor() {
214c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    vorbis_comment_clear(&mVc);
215c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    vorbis_info_clear(&mVi);
216388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
217388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
218388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersp<MetaData> MyVorbisExtractor::getFormat() const {
219388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return mMeta;
220388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
221388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
222388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t MyVorbisExtractor::findNextPage(
223388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        off_t startOffset, off_t *pageOffset) {
224388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    *pageOffset = startOffset;
225388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
226388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    for (;;) {
227388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        char signature[4];
228388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
229388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
230388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (n < 4) {
231388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            *pageOffset = 0;
232388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
233388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
234388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
235388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
236388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (!memcmp(signature, "OggS", 4)) {
237388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (*pageOffset > startOffset) {
238388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                LOGV("skipped %ld bytes of junk to reach next frame",
239388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                     *pageOffset - startOffset);
240388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
241388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
242388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            return OK;
243388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
244388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
245388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        ++*pageOffset;
246388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
247388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
248388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
24938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber// Given the offset of the "current" page, find the page immediately preceding
25038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber// it (if any) and return its granule position.
25138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber// To do this we back up from the "current" page's offset until we find any
25238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber// page preceding it and then scan forward to just before the current page.
25338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huberuint64_t MyVorbisExtractor::findPrevGranulePosition(off_t pageOffset) {
25438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    off_t prevPageOffset = 0;
25538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    off_t prevGuess = pageOffset;
25638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    for (;;) {
25738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        if (prevGuess >= 5000) {
25838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            prevGuess -= 5000;
25938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        } else {
26038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            prevGuess = 0;
26138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        }
26238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
26338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        LOGV("backing up %ld bytes", pageOffset - prevGuess);
26438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
26538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        CHECK_EQ(findNextPage(prevGuess, &prevPageOffset), (status_t)OK);
26638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
26738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        if (prevPageOffset < pageOffset || prevGuess == 0) {
26838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            break;
26938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        }
27038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    }
27138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
27238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    if (prevPageOffset == pageOffset) {
27338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        // We did not find a page preceding this one.
27438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        return 0;
27538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    }
27638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
27738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    LOGV("prevPageOffset at %ld, pageOffset at %ld", prevPageOffset, pageOffset);
27838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
27938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    for (;;) {
28038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        Page prevPage;
28138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        ssize_t n = readPage(prevPageOffset, &prevPage);
28238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
28338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        if (n <= 0) {
28438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            return 0;
28538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        }
28638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
28738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        prevPageOffset += n;
28838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
28938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        if (prevPageOffset == pageOffset) {
29038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            return prevPage.mGranulePosition;
29138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        }
29238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    }
29338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber}
29438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
295388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t MyVorbisExtractor::seekToOffset(off_t offset) {
29634c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber    if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
29734c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber        // Once we know where the actual audio data starts (past the headers)
29834c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber        // don't ever seek to anywhere before that.
29934c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber        offset = mFirstDataOffset;
30034c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber    }
30134c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber
302388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    off_t pageOffset;
303388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    status_t err = findNextPage(offset, &pageOffset);
304388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
305388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (err != OK) {
306388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return err;
307388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
308388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
30938ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    // We found the page we wanted to seek to, but we'll also need
31038ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    // the page preceding it to determine how many valid samples are on
31138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    // this page.
31238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    mPrevGranulePosition = findPrevGranulePosition(pageOffset);
31338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
314388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mOffset = pageOffset;
315388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
316388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mCurrentPageSize = 0;
31738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    mFirstPacketInPage = true;
31838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber    mCurrentPageSamples = 0;
319388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mCurrentPage.mNumSegments = 0;
320388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mNextLaceIndex = 0;
321388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
322388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    // XXX what if new page continues packet from last???
323388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
324388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return OK;
325388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
326388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
327388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberssize_t MyVorbisExtractor::readPage(off_t offset, Page *page) {
328388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    uint8_t header[27];
329388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (mSource->readAt(offset, header, sizeof(header))
330388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            < (ssize_t)sizeof(header)) {
3313386c38d59fa837f4876a24af821fb9b35314712Andreas Huber        LOGV("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
332388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
333388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return ERROR_IO;
334388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
335388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
336388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (memcmp(header, "OggS", 4)) {
337388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return ERROR_MALFORMED;
338388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
339388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
340388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (header[4] != 0) {
341388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        // Wrong version.
342388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
343388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return ERROR_UNSUPPORTED;
344388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
345388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
346388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    page->mFlags = header[5];
347388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
348388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (page->mFlags & ~7) {
349388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        // Only bits 0-2 are defined in version 0.
350388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return ERROR_MALFORMED;
351388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
352388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
353388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    page->mGranulePosition = U64LE_AT(&header[6]);
354388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
355388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#if 0
356388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    printf("granulePosition = %llu (0x%llx)\n",
357388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber           page->mGranulePosition, page->mGranulePosition);
358388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber#endif
359388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
360388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    page->mSerialNo = U32LE_AT(&header[14]);
361388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    page->mPageNo = U32LE_AT(&header[18]);
362388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
363388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    page->mNumSegments = header[26];
364388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (mSource->readAt(
365388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                offset + sizeof(header), page->mLace, page->mNumSegments)
366388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            < (ssize_t)page->mNumSegments) {
367388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return ERROR_IO;
368388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
369388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
370388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    size_t totalSize = 0;;
371388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    for (size_t i = 0; i < page->mNumSegments; ++i) {
372388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        totalSize += page->mLace[i];
373388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
374388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
375eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber#if 0
376388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    String8 tmp;
377388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    for (size_t i = 0; i < page->mNumSegments; ++i) {
378388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        char x[32];
379388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
380388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
381388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        tmp.append(x);
382388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
383388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
384eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
385eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber#endif
386388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
387388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return sizeof(header) + page->mNumSegments + totalSize;
388388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
389388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
390388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberstatus_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
391388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    *out = NULL;
392388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
393388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MediaBuffer *buffer = NULL;
394388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    int64_t timeUs = -1;
395388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
396388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    for (;;) {
397388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        size_t i;
398388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        size_t packetSize = 0;
399388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        bool gotFullPacket = false;
400388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
401388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            uint8_t lace = mCurrentPage.mLace[i];
402388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
403388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            packetSize += lace;
404388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
405388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (lace < 255) {
406388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                gotFullPacket = true;
407388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                ++i;
408388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                break;
409388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
410388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
411388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
412388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (mNextLaceIndex < mCurrentPage.mNumSegments) {
413388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            off_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
414388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            for (size_t j = 0; j < mNextLaceIndex; ++j) {
415388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                dataOffset += mCurrentPage.mLace[j];
416388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
417388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
418388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            size_t fullSize = packetSize;
419388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (buffer != NULL) {
420388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                fullSize += buffer->range_length();
421388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
422388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            MediaBuffer *tmp = new MediaBuffer(fullSize);
423388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (buffer != NULL) {
424388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                memcpy(tmp->data(), buffer->data(), buffer->range_length());
425388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                tmp->set_range(0, buffer->range_length());
426388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                buffer->release();
4271f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber            } else {
428388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // XXX Not only is this not technically the correct time for
429388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // this packet, we also stamp every packet in this page
430388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // with the same time. This needs fixing later.
4311f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber
4321f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                if (mVi.rate) {
4331f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                    // Rate may not have been initialized yet if we're currently
4341f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                    // reading the configuration packets...
4351f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                    // Fortunately, the timestamp doesn't matter for those.
4361f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                    timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
4371f7fba1ffbf5922d999ab52130efb73a35e72077Andreas Huber                }
438388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                tmp->set_range(0, 0);
439388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
440388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            buffer = tmp;
441388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
442388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            ssize_t n = mSource->readAt(
443388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                    dataOffset,
444388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                    (uint8_t *)buffer->data() + buffer->range_length(),
445388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                    packetSize);
446388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
447388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (n < (ssize_t)packetSize) {
4483386c38d59fa837f4876a24af821fb9b35314712Andreas Huber                LOGV("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
449388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                return ERROR_IO;
450388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
451388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
452388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            buffer->set_range(0, fullSize);
453388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
454388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            mNextLaceIndex = i;
455388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
456388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (gotFullPacket) {
457388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // We've just read the entire packet.
458388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
459388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                if (timeUs >= 0) {
460388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
461388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                }
462388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
46338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                if (mFirstPacketInPage) {
46438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                    buffer->meta_data()->setInt32(
46538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                            kKeyValidSamples, mCurrentPageSamples);
46638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                    mFirstPacketInPage = false;
46738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                }
46838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
469388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                *out = buffer;
470388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
471388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                return OK;
472388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
473388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
474388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            // fall through, the buffer now contains the start of the packet.
475388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
476388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
477388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
478388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
479388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        mOffset += mCurrentPageSize;
480388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        ssize_t n = readPage(mOffset, &mCurrentPage);
481388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
482388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (n <= 0) {
483388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (buffer) {
484388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                buffer->release();
485388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                buffer = NULL;
486388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
487388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
4883386c38d59fa837f4876a24af821fb9b35314712Andreas Huber            LOGV("readPage returned %ld", n);
489388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
490388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
491388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
492388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
49338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        mCurrentPageSamples =
49438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber            mCurrentPage.mGranulePosition - mPrevGranulePosition;
49538ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        mFirstPacketInPage = true;
49638ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
49738ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber        mPrevGranulePosition = mCurrentPage.mGranulePosition;
49838ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
499388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        mCurrentPageSize = n;
500388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        mNextLaceIndex = 0;
501388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
502388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        if (buffer != NULL) {
503388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if ((mCurrentPage.mFlags & 1) == 0) {
504388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // This page does not continue the packet, i.e. the packet
505388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                // is already complete.
506388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
507388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                if (timeUs >= 0) {
508388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
509388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                }
510388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
51138ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                buffer->meta_data()->setInt32(
51238ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                        kKeyValidSamples, mCurrentPageSamples);
51338ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber                mFirstPacketInPage = false;
51438ae220bb7c06e3cc82f96dada769c6b12a79d09Andreas Huber
515388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                *out = buffer;
516388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
517388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                return OK;
518388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
519388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
520388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
521388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
522388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
523eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huberstatus_t MyVorbisExtractor::init() {
524388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mMeta = new MetaData;
525388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
526388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
527388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    MediaBuffer *packet;
528eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    status_t err;
529eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if ((err = readNextPacket(&packet)) != OK) {
530eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
531eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
532388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    LOGV("read packet of size %d\n", packet->range_length());
533eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    err = verifyHeader(packet, 1);
534388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet->release();
535388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet = NULL;
536eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if (err != OK) {
537eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
538eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
539388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
540eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if ((err = readNextPacket(&packet)) != OK) {
541eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
542eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
543388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    LOGV("read packet of size %d\n", packet->range_length());
544eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    err = verifyHeader(packet, 3);
545388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet->release();
546388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet = NULL;
547eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if (err != OK) {
548eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
549eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
550388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
551eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if ((err = readNextPacket(&packet)) != OK) {
552eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
553eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
554388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    LOGV("read packet of size %d\n", packet->range_length());
555eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    err = verifyHeader(packet, 5);
556388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet->release();
557388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    packet = NULL;
558eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if (err != OK) {
559eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return err;
560eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
56134c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber
56234c70709a69fbf29dbde2c106d9db5f522f25268Andreas Huber    mFirstDataOffset = mOffset + mCurrentPageSize;
563eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber
564eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    return OK;
565388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
566388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
567eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huberstatus_t MyVorbisExtractor::verifyHeader(
568388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        MediaBuffer *buffer, uint8_t type) {
569388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    const uint8_t *data =
570388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
571388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
572388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    size_t size = buffer->range_length();
573388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
574eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
575eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        return ERROR_MALFORMED;
576eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
577388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
578388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ogg_buffer buf;
579388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    buf.data = (uint8_t *)data;
580388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    buf.size = size;
581388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    buf.refcount = 1;
582388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    buf.ptr.owner = NULL;
583388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
584388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ogg_reference ref;
585388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ref.buffer = &buf;
586388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ref.begin = 0;
587388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ref.length = size;
588388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    ref.next = NULL;
589388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
590388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    oggpack_buffer bits;
591388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    oggpack_readinit(&bits, &ref);
592388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
593388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    CHECK_EQ(oggpack_read(&bits, 8), type);
594388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    for (size_t i = 0; i < 6; ++i) {
595388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        oggpack_read(&bits, 8);  // skip 'vorbis'
596388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
597388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
598388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    switch (type) {
599388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        case 1:
600388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        {
601388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
602388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
603388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            mMeta->setData(kKeyVorbisInfo, 0, data, size);
604388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            mMeta->setInt32(kKeySampleRate, mVi.rate);
605388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            mMeta->setInt32(kKeyChannelCount, mVi.channels);
606388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
607388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            LOGV("lower-bitrate = %ld", mVi.bitrate_lower);
608388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            LOGV("upper-bitrate = %ld", mVi.bitrate_upper);
609388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            LOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
610388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            LOGV("window-bitrate = %ld", mVi.bitrate_window);
611388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
612388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            off_t size;
613388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            if (mSource->getSize(&size) == OK) {
614388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                uint64_t bps = approxBitrate();
615388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
616388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber                mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
617388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            }
618388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            break;
619388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
620388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
621388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        case 3:
622388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        {
623eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber            if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
624eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber                return ERROR_MALFORMED;
625eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber            }
626c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
627c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            parseFileMetaData();
628388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            break;
629388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
630388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
631388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        case 5:
632388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        {
633eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber            if (0 != _vorbis_unpack_books(&mVi, &bits)) {
634eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber                return ERROR_MALFORMED;
635eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber            }
636388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
637388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            mMeta->setData(kKeyVorbisBooks, 0, data, size);
638388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber            break;
639388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        }
640388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
641eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber
642eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    return OK;
643388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
644388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
645388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberuint64_t MyVorbisExtractor::approxBitrate() {
646388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (mVi.bitrate_nominal != 0) {
647388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return mVi.bitrate_nominal;
648388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
649388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
650388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
651388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
652388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
653c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Hubervoid MyVorbisExtractor::parseFileMetaData() {
654c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    mFileMeta = new MetaData;
655c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
656c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
657c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    struct {
658c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        const char *const mTag;
659c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        uint32_t mKey;
660c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    } kMap[] = {
661c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "TITLE", kKeyTitle },
662c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "ARTIST", kKeyArtist },
663ba77a3f9cb1d68b2ed4813aaae856444578e3a75Marco Nelissen        { "ALBUMARTIST", kKeyAlbumArtist },
664ba77a3f9cb1d68b2ed4813aaae856444578e3a75Marco Nelissen        { "ALBUM ARTIST", kKeyAlbumArtist },
665ba77a3f9cb1d68b2ed4813aaae856444578e3a75Marco Nelissen        { "COMPILATION", kKeyCompilation },
666c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "ALBUM", kKeyAlbum },
667c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "COMPOSER", kKeyComposer },
668c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "GENRE", kKeyGenre },
669c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "AUTHOR", kKeyAuthor },
670c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "TRACKNUMBER", kKeyCDTrackNumber },
671c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "DISCNUMBER", kKeyDiscNumber },
672c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "DATE", kKeyDate },
673c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "LYRICIST", kKeyWriter },
674c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
6759fee0b2a02daa6fcf286ed930e45400dd3ba8dbaAndreas Huber        { "ANDROID_LOOP", kKeyAutoLoop },
676c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    };
677c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
678c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    for (int i = 0; i < mVc.comments; ++i) {
679c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        const char *comment = mVc.user_comments[i];
680c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
681c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
682c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            size_t tagLen = strlen(kMap[j].mTag);
683c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
684c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                    && comment[tagLen] == '=') {
685c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                if (kMap[j].mKey == kKeyAlbumArt) {
686c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                    extractAlbumArt(
687c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                            &comment[tagLen + 1],
688c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                            mVc.comment_lengths[i] - tagLen - 1);
6899fee0b2a02daa6fcf286ed930e45400dd3ba8dbaAndreas Huber                } else if (kMap[j].mKey == kKeyAutoLoop) {
6909fee0b2a02daa6fcf286ed930e45400dd3ba8dbaAndreas Huber                    if (!strcasecmp(&comment[tagLen + 1], "true")) {
6919fee0b2a02daa6fcf286ed930e45400dd3ba8dbaAndreas Huber                        mFileMeta->setInt32(kKeyAutoLoop, true);
6929fee0b2a02daa6fcf286ed930e45400dd3ba8dbaAndreas Huber                    }
693c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                } else {
694c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                    mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
695c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                }
696c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            }
697c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        }
698c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
699c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
700c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber#if 0
701c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    for (int i = 0; i < mVc.comments; ++i) {
702c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
703c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
704c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber#endif
705c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber}
706c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
707c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber// The returned buffer should be free()d.
708c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huberstatic uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
709c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    *outSize = 0;
710c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
711c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if ((size % 4) != 0) {
712c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        return NULL;
713c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
714c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
715c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    size_t n = size;
716c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    size_t padding = 0;
717c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (n >= 1 && s[n - 1] == '=') {
718c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        padding = 1;
719c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
720c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        if (n >= 2 && s[n - 2] == '=') {
721c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            padding = 2;
722c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        }
723c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
724c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
725c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    size_t outLen = 3 * size / 4 - padding;
726c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
727c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    *outSize = outLen;
728c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
729c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    void *buffer = malloc(outLen);
730c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
731c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint8_t *out = (uint8_t *)buffer;
732c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    size_t j = 0;
733c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint32_t accum = 0;
734c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    for (size_t i = 0; i < n; ++i) {
735c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        char c = s[i];
736c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        unsigned value;
737c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        if (c >= 'A' && c <= 'Z') {
738c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = c - 'A';
739c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else if (c >= 'a' && c <= 'z') {
740c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = 26 + c - 'a';
741c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else if (c >= '0' && c <= '9') {
742c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = 52 + c - '0';
743c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else if (c == '+') {
744c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = 62;
745c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else if (c == '/') {
746c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = 63;
747c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else if (c != '=') {
748c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            return NULL;
749c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        } else {
750c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            if (i < n - padding) {
751c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber                return NULL;
752c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            }
753c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
754c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            value = 0;
755c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        }
756c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
757c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        accum = (accum << 6) | value;
758c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
759c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        if (((i + 1) % 4) == 0) {
760c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            out[j++] = (accum >> 16);
761c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
762c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
763c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            if (j < outLen) { out[j++] = accum & 0xff; }
764c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
765c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            accum = 0;
766c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        }
767c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
768c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
769c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    return (uint8_t *)buffer;
770c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber}
771c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
772c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Hubervoid MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
773c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    LOGV("extractAlbumArt from '%s'", (const char *)data);
774c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
775c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    size_t flacSize;
776c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
777c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
778c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (flac == NULL) {
779c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        LOGE("malformed base64 encoded data.");
780c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        return;
781c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
782c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
783c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    LOGV("got flac of size %d", flacSize);
784c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
785c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint32_t picType;
786c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint32_t typeLen;
787c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint32_t descLen;
788c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    uint32_t dataLen;
789c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    char type[128];
790c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
791c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (flacSize < 8) {
792c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
793c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
794c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
795c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    picType = U32_AT(flac);
796c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
797c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (picType != 3) {
798c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        // This is not a front cover.
799c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
800c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
801c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
802c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    typeLen = U32_AT(&flac[4]);
803c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (typeLen + 1 > sizeof(type)) {
804c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
805c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
806c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
807c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (flacSize < 8 + typeLen) {
808c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
809c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
810c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
811c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    memcpy(type, &flac[8], typeLen);
812c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    type[typeLen] = '\0';
813c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
814c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    LOGV("picType = %d, type = '%s'", picType, type);
815c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
816c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (!strcmp(type, "-->")) {
817c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        // This is not inline cover art, but an external url instead.
818c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
819c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
820c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
821c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    descLen = U32_AT(&flac[8 + typeLen]);
822c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
823c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (flacSize < 32 + typeLen + descLen) {
824c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
825c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
826c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
827c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
828c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
829c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    if (flacSize < 32 + typeLen + descLen + dataLen) {
830c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber        goto exit;
831c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    }
832c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
833c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    LOGV("got image data, %d trailing bytes",
834c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber         flacSize - 32 - typeLen - descLen - dataLen);
835c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
836c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    mFileMeta->setData(
837c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
838c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
839c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    mFileMeta->setCString(kKeyAlbumArtMIME, type);
840c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
841c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huberexit:
842c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    free(flac);
843c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    flac = NULL;
844c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber}
845c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber
846388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber////////////////////////////////////////////////////////////////////////////////
847388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
848388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberOggExtractor::OggExtractor(const sp<DataSource> &source)
849388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    : mDataSource(source),
850388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber      mInitCheck(NO_INIT),
851388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber      mImpl(NULL) {
852388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mImpl = new MyVorbisExtractor(mDataSource);
853eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    mInitCheck = mImpl->seekToOffset(0);
854388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
855eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    if (mInitCheck == OK) {
856eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber        mInitCheck = mImpl->init();
857eae953bfd4ea86a51f7fdd845de9f3d82646dff8Andreas Huber    }
858388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
859388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
860388379f8b4cabe7bccf280d450a6db2c3149796bAndreas HuberOggExtractor::~OggExtractor() {
861388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    delete mImpl;
862388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mImpl = NULL;
863388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
864388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
865388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersize_t OggExtractor::countTracks() {
866388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return mInitCheck != OK ? 0 : 1;
867388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
868388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
869388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersp<MediaSource> OggExtractor::getTrack(size_t index) {
870388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (index >= 1) {
871388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return NULL;
872388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
873388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
874388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return new OggSource(this);
875388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
876388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
877388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersp<MetaData> OggExtractor::getTrackMetaData(
878388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        size_t index, uint32_t flags) {
879388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (index >= 1) {
880388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return NULL;
881388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
882388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
883388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return mImpl->getFormat();
884388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
885388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
886388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Hubersp<MetaData> OggExtractor::getMetaData() {
887c6c62e12c930b137e62c16931cfe340bc93aa8f4Andreas Huber    return mImpl->getFileMetaData();
888388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
889388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
890388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huberbool SniffOgg(
891efdd088a71ddd0a96cf9ca2f58e8703fe8c5c494Andreas Huber        const sp<DataSource> &source, String8 *mimeType, float *confidence,
892efdd088a71ddd0a96cf9ca2f58e8703fe8c5c494Andreas Huber        sp<AMessage> *) {
893388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    char tmp[4];
894388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
895388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber        return false;
896388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    }
897388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
898388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
899388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    *confidence = 0.2f;
900388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
901388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber    return true;
902388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}
903388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber
904388379f8b4cabe7bccf280d450a6db2c3149796bAndreas Huber}  // namespace android
905