1e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber/*
2e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Copyright (C) 2010 The Android Open Source Project
3e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
4e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * you may not use this file except in compliance with the License.
6e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * You may obtain a copy of the License at
7e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
8e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *
10e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * Unless required by applicable law or agreed to in writing, software
11e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * See the License for the specific language governing permissions and
14e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber * limitations under the License.
15e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber */
16e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
17ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber//#define LOG_NDEBUG 0
18ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber#define LOG_TAG "M3UParser"
19ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber#include <utils/Log.h>
20ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
2114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include "M3UParser.h"
22dcb89b3b505522efde173c105a851c412f947178Chong Zhang#include <binder/Parcel.h>
2314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#include <cutils/properties.h>
240a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber#include <media/stagefright/foundation/ADebug.h>
25e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/foundation/AMessage.h>
26404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang#include <media/stagefright/MediaDefs.h>
27e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/MediaErrors.h>
28ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih#include <media/stagefright/Utils.h>
29dcb89b3b505522efde173c105a851c412f947178Chong Zhang#include <media/mediaplayer.h>
30e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
31e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubernamespace android {
32e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
3314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstruct M3UParser::MediaGroup : public RefBase {
3414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum Type {
3514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        TYPE_AUDIO,
3614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        TYPE_VIDEO,
3714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        TYPE_SUBS,
3899cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        TYPE_CC,
3914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
4014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    enum FlagBits {
4214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FLAG_AUTOSELECT         = 1,
4314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FLAG_DEFAULT            = 2,
4414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FLAG_FORCED             = 4,
4514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FLAG_HAS_LANGUAGE       = 8,
4614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        FLAG_HAS_URI            = 16,
4714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
4814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
4914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    MediaGroup(Type type);
5014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    Type type() const;
5214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    status_t addMedia(
5414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const char *name,
5514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const char *uri,
5614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const char *language,
5714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            uint32_t flags);
5814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
5914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool getActiveURI(AString *uri) const;
6014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    void pickRandomMediaItems();
62dcb89b3b505522efde173c105a851c412f947178Chong Zhang    status_t selectTrack(size_t index, bool select);
63dcb89b3b505522efde173c105a851c412f947178Chong Zhang    size_t countTracks() const;
64404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    sp<AMessage> getTrackInfo(size_t index) const;
6514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberprotected:
6714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    virtual ~MediaGroup();
6814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
6914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberprivate:
7089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
7189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    friend struct M3UParser;
7289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
7314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    struct Media {
7414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString mName;
7514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString mURI;
7614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString mLanguage;
7714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        uint32_t mFlags;
7814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    };
7914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
8014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    Type mType;
8114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    Vector<Media> mMediaItems;
8214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
8314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t mSelectedIndex;
8414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
8514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    DISALLOW_EVIL_CONSTRUCTORS(MediaGroup);
8614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber};
8714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
8814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas HuberM3UParser::MediaGroup::MediaGroup(Type type)
8914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    : mType(type),
9014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber      mSelectedIndex(-1) {
9114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
9214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
9314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas HuberM3UParser::MediaGroup::~MediaGroup() {
9414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
9514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
9614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas HuberM3UParser::MediaGroup::Type M3UParser::MediaGroup::type() const {
9714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return mType;
9814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
9914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
10014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t M3UParser::MediaGroup::addMedia(
10114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const char *name,
10214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const char *uri,
10314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const char *language,
10414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        uint32_t flags) {
10514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mMediaItems.push();
10614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    Media &item = mMediaItems.editItemAt(mMediaItems.size() - 1);
10714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
10814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    item.mName = name;
10914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (uri) {
11114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        item.mURI = uri;
11214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
11314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (language) {
11514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        item.mLanguage = language;
11614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
11714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
11814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    item.mFlags = flags;
11914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
12114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
12214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid M3UParser::MediaGroup::pickRandomMediaItems() {
12414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#if 1
12514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    switch (mType) {
12614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case TYPE_AUDIO:
12714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
12814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            char value[PROPERTY_VALUE_MAX];
12914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (property_get("media.httplive.audio-index", value, NULL)) {
13014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                char *end;
13114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mSelectedIndex = strtoul(value, &end, 10);
13214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                CHECK(end > value && *end == '\0');
13314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
13484333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber                if (mSelectedIndex >= (ssize_t)mMediaItems.size()) {
13514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    mSelectedIndex = mMediaItems.size() - 1;
13614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                }
13714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
13814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                mSelectedIndex = 0;
13914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
14014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
14114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
14214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
14314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case TYPE_VIDEO:
14414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
14514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mSelectedIndex = 0;
14614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
14714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
14814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
14914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        case TYPE_SUBS:
15014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        {
15114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            mSelectedIndex = -1;
15214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            break;
15314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
15414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
15514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        default:
15614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            TRESPASS();
15714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
15814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#else
15914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    mSelectedIndex = (rand() * mMediaItems.size()) / RAND_MAX;
16014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber#endif
16114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
16214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
163dcb89b3b505522efde173c105a851c412f947178Chong Zhangstatus_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) {
164309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (mType != TYPE_SUBS && mType != TYPE_AUDIO) {
165309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        ALOGE("only select subtitile/audio tracks for now!");
166dcb89b3b505522efde173c105a851c412f947178Chong Zhang        return INVALID_OPERATION;
167dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
168dcb89b3b505522efde173c105a851c412f947178Chong Zhang
169dcb89b3b505522efde173c105a851c412f947178Chong Zhang    if (select) {
170dcb89b3b505522efde173c105a851c412f947178Chong Zhang        if (index >= mMediaItems.size()) {
171b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross            ALOGE("track %zu does not exist", index);
172dcb89b3b505522efde173c105a851c412f947178Chong Zhang            return INVALID_OPERATION;
173dcb89b3b505522efde173c105a851c412f947178Chong Zhang        }
17484333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber        if (mSelectedIndex == (ssize_t)index) {
175b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross            ALOGE("track %zu already selected", index);
176dcb89b3b505522efde173c105a851c412f947178Chong Zhang            return BAD_VALUE;
177dcb89b3b505522efde173c105a851c412f947178Chong Zhang        }
178b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross        ALOGV("selected track %zu", index);
179dcb89b3b505522efde173c105a851c412f947178Chong Zhang        mSelectedIndex = index;
180dcb89b3b505522efde173c105a851c412f947178Chong Zhang    } else {
18184333e0475bc911adc16417f4ca327c975cf6c36Andreas Huber        if (mSelectedIndex != (ssize_t)index) {
182b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross            ALOGE("track %zu is not selected", index);
183dcb89b3b505522efde173c105a851c412f947178Chong Zhang            return BAD_VALUE;
184dcb89b3b505522efde173c105a851c412f947178Chong Zhang        }
185b4a7a2df4c28c3f32b5d877b54831d2cc5d78f81Colin Cross        ALOGV("unselected track %zu", index);
186dcb89b3b505522efde173c105a851c412f947178Chong Zhang        mSelectedIndex = -1;
187dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
188dcb89b3b505522efde173c105a851c412f947178Chong Zhang
189dcb89b3b505522efde173c105a851c412f947178Chong Zhang    return OK;
190dcb89b3b505522efde173c105a851c412f947178Chong Zhang}
191dcb89b3b505522efde173c105a851c412f947178Chong Zhang
192404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsize_t M3UParser::MediaGroup::countTracks() const {
193404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    return mMediaItems.size();
194404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang}
195dcb89b3b505522efde173c105a851c412f947178Chong Zhang
196404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsp<AMessage> M3UParser::MediaGroup::getTrackInfo(size_t index) const {
197404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    if (index >= mMediaItems.size()) {
198404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        return NULL;
199404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    }
200a911f51c21430ac92f1d796b2338878fd98382e9Chong Zhang
201404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    sp<AMessage> format = new AMessage();
202404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang
203404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    int32_t trackType;
204404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    if (mType == TYPE_AUDIO) {
205404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        trackType = MEDIA_TRACK_TYPE_AUDIO;
206404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    } else if (mType == TYPE_VIDEO) {
207404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        trackType = MEDIA_TRACK_TYPE_VIDEO;
208404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    } else if (mType == TYPE_SUBS) {
209404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        trackType = MEDIA_TRACK_TYPE_SUBTITLE;
210404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    } else {
211404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
212404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    }
213404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    format->setInt32("type", trackType);
214404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang
215404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    const Media &item = mMediaItems.itemAt(index);
216404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    const char *lang = item.mLanguage.empty() ? "und" : item.mLanguage.c_str();
217404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    format->setString("language", lang);
218404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang
219404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    if (mType == TYPE_SUBS) {
220404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        // TO-DO: pass in a MediaFormat instead
221404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        format->setString("mime", MEDIA_MIMETYPE_TEXT_VTT);
222404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        format->setInt32("auto", !!(item.mFlags & MediaGroup::FLAG_AUTOSELECT));
223404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        format->setInt32("default", !!(item.mFlags & MediaGroup::FLAG_DEFAULT));
224404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        format->setInt32("forced", !!(item.mFlags & MediaGroup::FLAG_FORCED));
225dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
226dcb89b3b505522efde173c105a851c412f947178Chong Zhang
227404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    return format;
228dcb89b3b505522efde173c105a851c412f947178Chong Zhang}
229dcb89b3b505522efde173c105a851c412f947178Chong Zhang
23014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberbool M3UParser::MediaGroup::getActiveURI(AString *uri) const {
23114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (size_t i = 0; i < mMediaItems.size(); ++i) {
23214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (mSelectedIndex >= 0 && i == (size_t)mSelectedIndex) {
23314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            const Media &item = mMediaItems.itemAt(i);
23414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
23514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            *uri = item.mURI;
23614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return true;
23714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
23814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
23914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
24014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return false;
24114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
24214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
24314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber////////////////////////////////////////////////////////////////////////////////
24414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
245e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::M3UParser(
246e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const char *baseURI, const void *data, size_t size)
247e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    : mInitCheck(NO_INIT),
248e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mBaseURI(baseURI),
249e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mIsExtM3U(false),
250bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber      mIsVariantPlaylist(false),
251b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber      mIsComplete(false),
252dcb89b3b505522efde173c105a851c412f947178Chong Zhang      mIsEvent(false),
253978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang      mFirstSeqNumber(-1),
254978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang      mLastSeqNumber(-1),
255978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang      mTargetDurationUs(-1ll),
256309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih      mDiscontinuitySeq(0),
257c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang      mDiscontinuityCount(0),
258dcb89b3b505522efde173c105a851c412f947178Chong Zhang      mSelectedIndex(-1) {
259e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    mInitCheck = parse(data, size);
260e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
261e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
262e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::~M3UParser() {
263e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
264e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
265e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::initCheck() const {
266e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mInitCheck;
267e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
268e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
269e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isExtM3U() const {
270e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsExtM3U;
271e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
272e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
273e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isVariantPlaylist() const {
274e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsVariantPlaylist;
275e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
276e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
277bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huberbool M3UParser::isComplete() const {
278bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber    return mIsComplete;
279bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber}
280bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber
281b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huberbool M3UParser::isEvent() const {
282b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    return mIsEvent;
283b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber}
284b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber
285309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihsize_t M3UParser::getDiscontinuitySeq() const {
286309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    return mDiscontinuitySeq;
287309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih}
288309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
289978449984366946a2e5c9f7cf350746f4306caf8Chong Zhangint64_t M3UParser::getTargetDuration() const {
290978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    return mTargetDurationUs;
291978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang}
292978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
293978449984366946a2e5c9f7cf350746f4306caf8Chong Zhangint32_t M3UParser::getFirstSeqNumber() const {
294978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    return mFirstSeqNumber;
295978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang}
296978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
297978449984366946a2e5c9f7cf350746f4306caf8Chong Zhangvoid M3UParser::getSeqNumberRange(int32_t *firstSeq, int32_t *lastSeq) const {
298978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    *firstSeq = mFirstSeqNumber;
299978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    *lastSeq = mLastSeqNumber;
300978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang}
301978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
302e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersp<AMessage> M3UParser::meta() {
303e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mMeta;
304e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
305e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
306e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersize_t M3UParser::size() {
307e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mItems.size();
308e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
309e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
310e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) {
3110f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (uri) {
3120f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        uri->clear();
3130f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
3140f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber
3150f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (meta) {
3160f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        *meta = NULL;
3170f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
318e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
319e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (index >= mItems.size()) {
320e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
321e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
322e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
3230f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    if (uri) {
3240f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber        *uri = mItems.itemAt(index).mURI;
3250f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber    }
326e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
327e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta) {
328e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = mItems.itemAt(index).mMeta;
329e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
330e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
331e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
332e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
333e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
33414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid M3UParser::pickRandomMediaItems() {
33514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    for (size_t i = 0; i < mMediaGroups.size(); ++i) {
33614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mMediaGroups.valueAt(i)->pickRandomMediaItems();
33714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
33814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
33914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
340dcb89b3b505522efde173c105a851c412f947178Chong Zhangstatus_t M3UParser::selectTrack(size_t index, bool select) {
341dcb89b3b505522efde173c105a851c412f947178Chong Zhang    for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) {
342dcb89b3b505522efde173c105a851c412f947178Chong Zhang        sp<MediaGroup> group = mMediaGroups.valueAt(i);
343dcb89b3b505522efde173c105a851c412f947178Chong Zhang        size_t tracks = group->countTracks();
344dcb89b3b505522efde173c105a851c412f947178Chong Zhang        if (ii < tracks) {
345dcb89b3b505522efde173c105a851c412f947178Chong Zhang            status_t err = group->selectTrack(ii, select);
346dcb89b3b505522efde173c105a851c412f947178Chong Zhang            if (err == OK) {
347dcb89b3b505522efde173c105a851c412f947178Chong Zhang                mSelectedIndex = select ? index : -1;
348dcb89b3b505522efde173c105a851c412f947178Chong Zhang            }
349dcb89b3b505522efde173c105a851c412f947178Chong Zhang            return err;
350dcb89b3b505522efde173c105a851c412f947178Chong Zhang        }
351dcb89b3b505522efde173c105a851c412f947178Chong Zhang        ii -= tracks;
352dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
353dcb89b3b505522efde173c105a851c412f947178Chong Zhang    return INVALID_OPERATION;
354dcb89b3b505522efde173c105a851c412f947178Chong Zhang}
355dcb89b3b505522efde173c105a851c412f947178Chong Zhang
356404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsize_t M3UParser::getTrackCount() const {
357dcb89b3b505522efde173c105a851c412f947178Chong Zhang    size_t trackCount = 0;
358dcb89b3b505522efde173c105a851c412f947178Chong Zhang    for (size_t i = 0; i < mMediaGroups.size(); ++i) {
359dcb89b3b505522efde173c105a851c412f947178Chong Zhang        trackCount += mMediaGroups.valueAt(i)->countTracks();
360dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
361404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    return trackCount;
362404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang}
363dcb89b3b505522efde173c105a851c412f947178Chong Zhang
364404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsp<AMessage> M3UParser::getTrackInfo(size_t index) const {
365404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) {
366404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        sp<MediaGroup> group = mMediaGroups.valueAt(i);
367404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        size_t tracks = group->countTracks();
368404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        if (ii < tracks) {
369404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang            return group->getTrackInfo(ii);
370404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        }
371404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang        ii -= tracks;
372dcb89b3b505522efde173c105a851c412f947178Chong Zhang    }
373404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang    return NULL;
374dcb89b3b505522efde173c105a851c412f947178Chong Zhang}
375dcb89b3b505522efde173c105a851c412f947178Chong Zhang
376dcb89b3b505522efde173c105a851c412f947178Chong Zhangssize_t M3UParser::getSelectedIndex() const {
377dcb89b3b505522efde173c105a851c412f947178Chong Zhang    return mSelectedIndex;
378dcb89b3b505522efde173c105a851c412f947178Chong Zhang}
379dcb89b3b505522efde173c105a851c412f947178Chong Zhang
38089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shihssize_t M3UParser::getSelectedTrack(media_track_type type) const {
38189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    MediaGroup::Type groupType;
38289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    switch (type) {
38389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        case MEDIA_TRACK_TYPE_VIDEO:
38489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            groupType = MediaGroup::TYPE_VIDEO;
38589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            break;
38689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
38789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        case MEDIA_TRACK_TYPE_AUDIO:
38889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            groupType = MediaGroup::TYPE_AUDIO;
38989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            break;
39089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
39189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        case MEDIA_TRACK_TYPE_SUBTITLE:
39289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            groupType = MediaGroup::TYPE_SUBS;
39389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            break;
39489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
39589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        default:
39689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            return -1;
39789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    }
39889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
39989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    for (size_t i = 0, ii = 0; i < mMediaGroups.size(); ++i) {
40089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        sp<MediaGroup> group = mMediaGroups.valueAt(i);
40189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        size_t tracks = group->countTracks();
40289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        if (groupType != group->mType) {
40389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            ii += tracks;
40489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        } else if (group->mSelectedIndex >= 0) {
40589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih            return ii + group->mSelectedIndex;
40689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih        }
40789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    }
40889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
40989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih    return -1;
41089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih}
41189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih
41214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberbool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
41314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!mIsVariantPlaylist) {
414d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if (uri != NULL) {
415d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            *uri = mBaseURI;
416d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        }
41714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
41814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // Assume media without any more specific attribute contains
41914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        // audio and video, but no subtitles.
42014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return !strcmp("audio", key) || !strcmp("video", key);
42114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
42214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
42314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK_LT(index, mItems.size());
42414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
42514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<AMessage> meta = mItems.itemAt(index).mMeta;
42614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
42714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupID;
42814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!meta->findString(key, &groupID)) {
429d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if (uri != NULL) {
430d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            *uri = mItems.itemAt(index).mURI;
431d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        }
43214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
433ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        AString codecs;
434ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        if (!meta->findString("codecs", &codecs)) {
435ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            // Assume media without any more specific attribute contains
436ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            // audio and video, but no subtitles.
437ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return !strcmp("audio", key) || !strcmp("video", key);
438ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        } else {
439ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            // Split the comma separated list of codecs.
440ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            size_t offset = 0;
441ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            ssize_t commaPos = -1;
442ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            codecs.append(',');
443ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            while ((commaPos = codecs.find(",", offset)) >= 0) {
444ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                AString codec(codecs, offset, commaPos - offset);
4451ac1638077277de52d1dd4c54db71e67753f1960Robert Shih                codec.trim();
446ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                // return true only if a codec of type `key` ("audio"/"video")
447ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                // is found.
448ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                if (codecIsType(codec, key)) {
449ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                    return true;
450ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                }
451ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                offset = commaPos + 1;
452ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            }
453ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return false;
454ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        }
45514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
45614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
457d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    // if uri == NULL, we're only checking if the type is present,
458d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    // don't care about the active URI (or if there is an active one)
459d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    if (uri != NULL) {
460d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        sp<MediaGroup> group = mMediaGroups.valueFor(groupID);
461d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if (!group->getActiveURI(uri)) {
462d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            return false;
463d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        }
46414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
465d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        if ((*uri).empty()) {
466d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang            *uri = mItems.itemAt(index).mURI;
467d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang        }
46814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
46914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
47014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return true;
47114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
47214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
473d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhangbool M3UParser::hasType(size_t index, const char *key) const {
474d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    return getTypeURI(index, key, NULL /* uri */);
475d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang}
476d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang
477e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatic bool MakeURL(const char *baseURL, const char *url, AString *out) {
478e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    out->clear();
479e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
4802a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (strncasecmp("http://", baseURL, 7)
481df42f949c8bd05b81d94633767514fff88f52062Andreas Huber            && strncasecmp("https://", baseURL, 8)
4822a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            && strncasecmp("file://", baseURL, 7)) {
483e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // Base URL must be absolute
484e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
485e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
486a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar    const size_t schemeEnd = (strstr(baseURL, "//") - baseURL) + 2;
487a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar    CHECK(schemeEnd == 7 || schemeEnd == 8);
488e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
489df42f949c8bd05b81d94633767514fff88f52062Andreas Huber    if (!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8)) {
490e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // "url" is already an absolute URL, ignore base URL.
491e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->setTo(url);
492ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
4933856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str());
494ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
495e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return true;
496e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
497e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
498d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber    if (url[0] == '/') {
499d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        // URL is an absolute path.
500d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
501d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        char *protocolEnd = strstr(baseURL, "//") + 2;
502d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        char *pathStart = strchr(protocolEnd, '/');
503e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
504d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        if (pathStart != NULL) {
505d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            out->setTo(baseURL, pathStart - baseURL);
506e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
507e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            out->setTo(baseURL);
508e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
509e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
510e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->append(url);
511d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber    } else {
512d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        // URL is a relative path
513d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
5148883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        // Check for a possible query string
5158883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        const char *qsPos = strchr(baseURL, '?');
5168883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        size_t end;
5178883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        if (qsPos != NULL) {
5188883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo            end = qsPos - baseURL;
519d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        } else {
5208883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo            end = strlen(baseURL);
5218883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        }
5228883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        // Check for the last slash before a potential query string
523e175d77bb610675ba2f70f24449189995ddeaf5bMarco Nelissen        for (ssize_t pos = end - 1; pos >= 0; pos--) {
5248883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo            if (baseURL[pos] == '/') {
5258883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo                end = pos;
5268883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo                break;
527d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber            }
5288883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        }
529d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber
5308883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        // Check whether the found slash actually is part of the path
5318883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        // and not part of the "http://".
532a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar        if (end >= schemeEnd) {
5338883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo            out->setTo(baseURL, end);
5348883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        } else {
5358883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo            out->setTo(baseURL);
536d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber        }
5378883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo
5388883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        out->append("/");
5398883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo        out->append(url);
540e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
541e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
5423856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str());
543ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber
544e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
545e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
546e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
547e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parse(const void *_data, size_t size) {
548e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t lineNo = 0;
549e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
550e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    sp<AMessage> itemMeta;
551e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
552e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    const char *data = (const char *)_data;
553e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    size_t offset = 0;
5542aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    uint64_t segmentRangeOffset = 0;
555e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    while (offset < size) {
556e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        size_t offsetLF = offset;
557e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        while (offsetLF < size && data[offsetLF] != '\n') {
558e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            ++offsetLF;
559e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
560e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
561e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        AString line;
562e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (offsetLF > offset && data[offsetLF - 1] == '\r') {
563e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset - 1);
564e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
565e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset);
566e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
567e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
568df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        // ALOGI("#%s#", line.c_str());
5692a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
5702a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (line.empty()) {
5712a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            offset = offsetLF + 1;
5722a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
5732a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
574e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
575e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (lineNo == 0 && line == "#EXTM3U") {
576e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mIsExtM3U = true;
577e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
578e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
579e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (mIsExtM3U) {
580e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            status_t err = OK;
581e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
582e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (line.startsWith("#EXT-X-TARGETDURATION")) {
583e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
584e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
585e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
586e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "target-duration");
587e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) {
588e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
589e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
590e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
591e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "media-sequence");
592e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            } else if (line.startsWith("#EXT-X-KEY")) {
593e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                if (mIsVariantPlaylist) {
594e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                    return ERROR_MALFORMED;
595e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                }
596decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                err = parseCipherInfo(line, &itemMeta, mBaseURI);
597bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber            } else if (line.startsWith("#EXT-X-ENDLIST")) {
598bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                mIsComplete = true;
599b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber            } else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:EVENT")) {
600b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber                mIsEvent = true;
601e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXTINF")) {
602e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
603e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
604e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
6059067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                err = parseMetaDataDuration(line, &itemMeta, "durationUs");
6062a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
6072a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (mIsVariantPlaylist) {
6082a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    return ERROR_MALFORMED;
6092a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
6102a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (itemMeta == NULL) {
6112a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    itemMeta = new AMessage;
6122a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
6132a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                itemMeta->setInt32("discontinuity", true);
614c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                ++mDiscontinuityCount;
615e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-STREAM-INF")) {
616e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mMeta != NULL) {
617e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
618e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
619e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                mIsVariantPlaylist = true;
6202a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                err = parseStreamInf(line, &itemMeta);
6212aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            } else if (line.startsWith("#EXT-X-BYTERANGE")) {
6222aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (mIsVariantPlaylist) {
6232aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    return ERROR_MALFORMED;
6242aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
6252aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6262aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                uint64_t length, offset;
6272aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                err = parseByteRange(line, segmentRangeOffset, &length, &offset);
6282aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6292aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (err == OK) {
6302aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    if (itemMeta == NULL) {
6312aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                        itemMeta = new AMessage;
6322aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    }
6332aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6342aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-offset", offset);
6352aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-length", length);
6362aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6372aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    segmentRangeOffset = offset + length;
6382aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
63914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (line.startsWith("#EXT-X-MEDIA")) {
64014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                err = parseMedia(line);
641309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih            } else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE")) {
642c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                if (mIsVariantPlaylist) {
643c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                    return ERROR_MALFORMED;
644c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                }
645309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                size_t seq;
646309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                err = parseDiscontinuitySequence(line, &seq);
647309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                if (err == OK) {
648309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                    mDiscontinuitySeq = seq;
649309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih                }
650e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
651e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
652e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (err != OK) {
653e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                return err;
654e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
655e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
656e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
657e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (!line.startsWith("#")) {
658e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (!mIsVariantPlaylist) {
6599067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                int64_t durationUs;
660e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (itemMeta == NULL
6619067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                        || !itemMeta->findInt64("durationUs", &durationUs)) {
662e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
663e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
664d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                itemMeta->setInt32("discontinuity-sequence",
665d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                        mDiscontinuitySeq + mDiscontinuityCount);
666e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
667e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
668e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mItems.push();
669e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            Item *item = &mItems.editItemAt(mItems.size() - 1);
670e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
671e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
672e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
673e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            item->mMeta = itemMeta;
674e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
675e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            itemMeta.clear();
676e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
677e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
678e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        offset = offsetLF + 1;
679e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        ++lineNo;
680e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
681e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
682d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    // error checking of all fields that's required to appear once
683978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    // (currently only checking "target-duration"), and
684978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    // initialization of playlist properties (eg. mTargetDurationUs)
685978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (!mIsVariantPlaylist) {
686978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        int32_t targetDurationSecs;
687978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (mMeta == NULL || !mMeta->findInt32(
688978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                "target-duration", &targetDurationSecs)) {
689978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            ALOGE("Media playlist missing #EXT-X-TARGETDURATION");
690978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            return ERROR_MALFORMED;
691978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
692978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mTargetDurationUs = targetDurationSecs * 1000000ll;
693978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
694978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mFirstSeqNumber = 0;
695978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (mMeta != NULL) {
696978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            mMeta->findInt32("media-sequence", &mFirstSeqNumber);
697978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
698978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mLastSeqNumber = mFirstSeqNumber + mItems.size() - 1;
699d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    }
700d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang
701e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
702e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
703e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
704e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
705e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parseMetaData(
706e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
707e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    ssize_t colonPos = line.find(":");
708e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
709e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (colonPos < 0) {
710e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
711e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
712e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
713e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t x;
714e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
715e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
716e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (err != OK) {
717e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return err;
718e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
719e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
720e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta->get() == NULL) {
721e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = new AMessage;
722e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
723e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    (*meta)->setInt32(key, x);
724e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
725e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
726e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
727e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
728e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
7299067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::parseMetaDataDuration(
7309067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
7319067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    ssize_t colonPos = line.find(":");
7329067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7339067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (colonPos < 0) {
7349067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
7359067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
7369067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7379067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double x;
7389067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    status_t err = ParseDouble(line.c_str() + colonPos + 1, &x);
7399067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7409067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (err != OK) {
7419067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return err;
7429067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
7439067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7449067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (meta->get() == NULL) {
7459067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        *meta = new AMessage;
7469067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
747abd5feeea499ee7337125223df4ea22cae19cd20Oscar Rydhé    (*meta)->setInt64(key, (int64_t)(x * 1E6));
7489067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7499067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
7509067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
7519067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
75214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Find the next occurence of the character "what" at or after "offset",
75314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// but ignore occurences between quotation marks.
75414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Return the index of the occurrence or -1 if not found.
75514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatic ssize_t FindNextUnquoted(
75614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const AString &line, char what, size_t offset) {
75714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK_NE((int)what, (int)'"');
75814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
75914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool quoted = false;
76014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (offset < line.size()) {
76114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        char c = line.c_str()[offset];
76214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
76314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (c == '"') {
76414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            quoted = !quoted;
76514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (c == what && !quoted) {
76614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return offset;
76714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
76814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
76914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ++offset;
77014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
77114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
77214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return -1;
77314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
77414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
7752a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huberstatus_t M3UParser::parseStreamInf(
77614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const AString &line, sp<AMessage> *meta) const {
7772a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    ssize_t colonPos = line.find(":");
7782a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7792a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (colonPos < 0) {
7802a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        return ERROR_MALFORMED;
7812a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
7822a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7832a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    size_t offset = colonPos + 1;
7842a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7852a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    while (offset < line.size()) {
78614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
7872a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (end < 0) {
7882a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            end = line.size();
7892a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
7902a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7912a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString attr(line, offset, end - offset);
7922a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        attr.trim();
7932a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7942a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        offset = end + 1;
7952a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7962a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t equalPos = attr.find("=");
7972a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (equalPos < 0) {
7982a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
7992a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
8002a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8012a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString key(attr, 0, equalPos);
8022a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        key.trim();
8032a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8042a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
8052a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        val.trim();
8062a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8073856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
8082a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8092a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (!strcasecmp("bandwidth", key.c_str())) {
8102a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            const char *s = val.c_str();
8112a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            char *end;
8122a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            unsigned long x = strtoul(s, &end, 10);
8132a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8142a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (end == s || *end != '\0') {
8152a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                // malformed
8162a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                continue;
8172a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
8182a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8192a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (meta->get() == NULL) {
8202a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                *meta = new AMessage;
8212a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
8222a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            (*meta)->setInt32("bandwidth", x);
823ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        } else if (!strcasecmp("codecs", key.c_str())) {
824ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            if (!isQuotedString(val)) {
825ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                ALOGE("Expected quoted string for %s attribute, "
826ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                      "got '%s' instead.",
827ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                      key.c_str(), val.c_str());;
828ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
829ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                return ERROR_MALFORMED;
830ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            }
831ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
832ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            key.tolower();
833ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            const AString &codecs = unquoteString(val);
8345154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            if (meta->get() == NULL) {
8355154f98277922aba7103ac19529ecc00b1889c1eRobert Shih                *meta = new AMessage;
8365154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            }
837ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            (*meta)->setString(key.c_str(), codecs.c_str());
838a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang        } else if (!strcasecmp("resolution", key.c_str())) {
839a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            const char *s = val.c_str();
840a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            char *end;
841a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            unsigned long width = strtoul(s, &end, 10);
842a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
843a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (end == s || *end != 'x') {
844a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                // malformed
845a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                continue;
846a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
847a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
848a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            s = end + 1;
849a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            unsigned long height = strtoul(s, &end, 10);
850a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
851a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (end == s || *end != '\0') {
852a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                // malformed
853a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                continue;
854a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
855a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
856a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (meta->get() == NULL) {
857a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                *meta = new AMessage;
858a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
859a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            (*meta)->setInt32("width", width);
860a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            (*meta)->setInt32("height", height);
86114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("audio", key.c_str())
86214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                || !strcasecmp("video", key.c_str())
86314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                || !strcasecmp("subtitles", key.c_str())) {
864ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            if (!isQuotedString(val)) {
86514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for %s attribute, "
86614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
86714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      key.c_str(), val.c_str());
86814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
86914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
87014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
8712a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
872ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            const AString &groupID = unquoteString(val);
87314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);
8742a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
87514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (groupIndex < 0) {
87614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Undefined media group '%s' referenced in stream info.",
87714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      groupID.c_str());
8780a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
87914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
88014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
8810a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
88214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            key.tolower();
8835154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            if (meta->get() == NULL) {
8845154f98277922aba7103ac19529ecc00b1889c1eRobert Shih                *meta = new AMessage;
8855154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            }
88614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            (*meta)->setString(key.c_str(), groupID.c_str());
8870a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        }
8880a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    }
8890a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
89014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
8910a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber}
8920a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
8932a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber// static
894e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huberstatus_t M3UParser::parseCipherInfo(
895decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber        const AString &line, sp<AMessage> *meta, const AString &baseURI) {
896e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    ssize_t colonPos = line.find(":");
897e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
898e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    if (colonPos < 0) {
899e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        return ERROR_MALFORMED;
900e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
901e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
902e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    size_t offset = colonPos + 1;
903e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
904e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    while (offset < line.size()) {
9050a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
906e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (end < 0) {
907e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            end = line.size();
908e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
909e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
910e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString attr(line, offset, end - offset);
911e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        attr.trim();
912e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
913e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        offset = end + 1;
914e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
915e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        ssize_t equalPos = attr.find("=");
916e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (equalPos < 0) {
917e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            continue;
918e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
919e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
920e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString key(attr, 0, equalPos);
921e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.trim();
922e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
923e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
924e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        val.trim();
925e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
9263856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
927e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
928e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.tolower();
929e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
930e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (key == "method" || key == "uri" || key == "iv") {
931e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            if (meta->get() == NULL) {
932e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                *meta = new AMessage;
933e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            }
934e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
935decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            if (key == "uri") {
936decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (val.size() >= 2
937decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[0] == '"'
938decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[val.size() - 1] == '"') {
939decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    // Remove surrounding quotes.
940decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    AString tmp(val, 1, val.size() - 2);
941decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = tmp;
942decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
943decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
944decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                AString absURI;
945decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) {
946decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = absURI;
947decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                } else {
948a1df816c0677185534babba6ffc29970b048e52eLajos Molnar                    ALOGE("failed to make absolute url for %s.",
949a1df816c0677185534babba6ffc29970b048e52eLajos Molnar                            uriDebugString(baseURI).c_str());
950decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
951decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            }
952decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
953e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            key.insert(AString("cipher-"), 0);
954e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
955e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            (*meta)->setString(key.c_str(), val.c_str(), val.size());
956e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
957e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
958e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
959e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    return OK;
960e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber}
961e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
962e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber// static
9632aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huberstatus_t M3UParser::parseByteRange(
9642aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const AString &line, uint64_t curOffset,
9652aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        uint64_t *length, uint64_t *offset) {
9662aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t colonPos = line.find(":");
9672aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9682aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (colonPos < 0) {
9692aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
9702aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
9712aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9722aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t atPos = line.find("@", colonPos + 1);
9732aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9742aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    AString lenStr;
9752aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos < 0) {
9762aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1);
9772aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
9782aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, atPos - colonPos - 1);
9792aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
9802aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9812aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    lenStr.trim();
9822aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9832aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    const char *s = lenStr.c_str();
9842aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    char *end;
9852aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    *length = strtoull(s, &end, 10);
9862aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9872aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (s == end || *end != '\0') {
9882aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
9892aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
9902aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9912aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos >= 0) {
9922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        AString offStr = AString(line, atPos + 1, line.size() - atPos - 1);
9932aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        offStr.trim();
9942aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9952aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const char *s = offStr.c_str();
9962aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = strtoull(s, &end, 10);
9972aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9982aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        if (s == end || *end != '\0') {
9992aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            return ERROR_MALFORMED;
10002aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        }
10012aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
10022aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = curOffset;
10032aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
10042aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
10052aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    return OK;
10062aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber}
10072aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
100814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t M3UParser::parseMedia(const AString &line) {
100914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t colonPos = line.find(":");
101014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
101114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (colonPos < 0) {
101214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_MALFORMED;
101314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
101414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
101514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupType = false;
101614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    MediaGroup::Type groupType = MediaGroup::TYPE_AUDIO;
101714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
101814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupID = false;
101914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupID;
102014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupLanguage = false;
102214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupLanguage;
102314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupName = false;
102514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupName;
102614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupAutoselect = false;
102814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupAutoselect = false;
102914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupDefault = false;
103114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupDefault = false;
103214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupForced = false;
103414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupForced = false;
103514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupURI = false;
103714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupURI;
103814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    size_t offset = colonPos + 1;
104014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (offset < line.size()) {
104214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
104314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (end < 0) {
104414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            end = line.size();
104514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
104614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString attr(line, offset, end - offset);
104814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        attr.trim();
104914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
105014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        offset = end + 1;
105114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
105214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t equalPos = attr.find("=");
105314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (equalPos < 0) {
105414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            continue;
105514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
105614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
105714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString key(attr, 0, equalPos);
105814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        key.trim();
105914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
106114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        val.trim();
106214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
106414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (!strcasecmp("type", key.c_str())) {
106614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("subtitles", val.c_str())) {
106714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_SUBS;
106814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("audio", val.c_str())) {
106914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_AUDIO;
107014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("video", val.c_str())) {
107114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_VIDEO;
107299cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang            } else if (!strcasecmp("closed-captions", val.c_str())){
107399cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang                groupType = MediaGroup::TYPE_CC;
107414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
107514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Invalid media group type '%s'", val.c_str());
107614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
107714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
107814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
107914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupType = true;
108014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("group-id", key.c_str())) {
108114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
108214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
108314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
108414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for GROUP-ID, got '%s' instead.",
108514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
108614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
108714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
108814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
108914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
109014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupID.setTo(val, 1, val.size() - 2);
109114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupID = true;
109214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("language", key.c_str())) {
109314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
109414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
109514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
109614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for LANGUAGE, got '%s' instead.",
109714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
109814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
109914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
110014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
110114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
110214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupLanguage.setTo(val, 1, val.size() - 2);
110314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupLanguage = true;
110414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("name", key.c_str())) {
110514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
110614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
110714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
110814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for NAME, got '%s' instead.",
110914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
111014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
111114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
111214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
111314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
111414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupName.setTo(val, 1, val.size() - 2);
111514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupName = true;
111614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("autoselect", key.c_str())) {
111714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupAutoselect = false;
111814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
111914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupAutoselect = true;
112014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
112114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupAutoselect = false;
112214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
112314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for AUTOSELECT attribute, "
112414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
112514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
112614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
112714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
112814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
112914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
113014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupAutoselect = true;
113114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("default", key.c_str())) {
113214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupDefault = false;
113314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
113414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupDefault = true;
113514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
113614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupDefault = false;
113714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
113814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for DEFAULT attribute, "
113914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
114014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
114114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
114214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
114314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
114414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
114514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupDefault = true;
114614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("forced", key.c_str())) {
114714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupForced = false;
114814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
114914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupForced = true;
115014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
115114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupForced = false;
115214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
115314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for FORCED attribute, "
115414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
115514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
115614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
115714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
115814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
115914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
116014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupForced = true;
116114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("uri", key.c_str())) {
116214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
116314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
116414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
116514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for URI, got '%s' instead.",
116614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
116714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
116814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
116914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
117014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
117114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            AString tmp(val, 1, val.size() - 2);
117214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
117314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!MakeURL(mBaseURI.c_str(), tmp.c_str(), &groupURI)) {
117414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGI("Failed to make absolute URI from '%s'.", tmp.c_str());
117514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
117614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
117714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupURI = true;
117814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
117914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
118014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
118114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!haveGroupType || !haveGroupID || !haveGroupName) {
118214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGE("Incomplete EXT-X-MEDIA element.");
118314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_MALFORMED;
118414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
118514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
118699cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang    if (groupType == MediaGroup::TYPE_CC) {
118799cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // TODO: ignore this for now.
118899cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // CC track will be detected by CCDecoder. But we still need to
118999cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // pass the CC track flags (lang, auto) to the app in the future.
119099cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        return OK;
119199cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang    }
119299cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang
119314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint32_t flags = 0;
119414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupAutoselect && groupAutoselect) {
119514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_AUTOSELECT;
119614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
119714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupDefault && groupDefault) {
119814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_DEFAULT;
119914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
120014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupForced) {
120114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (groupType != MediaGroup::TYPE_SUBS) {
120214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("The FORCED attribute MUST not be present on anything "
120314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  "but SUBS media.");
120414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
120514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
120614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
120714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
120814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (groupForced) {
120914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            flags |= MediaGroup::FLAG_FORCED;
121014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
121114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
121214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupLanguage) {
121314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_HAS_LANGUAGE;
121414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
121514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupURI) {
121614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_HAS_URI;
121714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
121814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
121914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);
122014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<MediaGroup> group;
122114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
122214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (groupIndex < 0) {
122314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        group = new MediaGroup(groupType);
122414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mMediaGroups.add(groupID, group);
122514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else {
122614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        group = mMediaGroups.valueAt(groupIndex);
122714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
122814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (group->type() != groupType) {
122914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("Attempt to put media item under group of different type "
123014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  "(groupType = %d, item type = %d",
123114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  group->type(),
123214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  groupType);
123314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
123414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
123514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
123614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
123714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
123814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return group->addMedia(
123914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupName.c_str(),
124014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupURI ? groupURI.c_str() : NULL,
124114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupLanguage ? groupLanguage.c_str() : NULL,
124214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            flags);
124314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
1244309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1245309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih// static
1246309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihstatus_t M3UParser::parseDiscontinuitySequence(const AString &line, size_t *seq) {
1247309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    ssize_t colonPos = line.find(":");
1248309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1249309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (colonPos < 0) {
1250309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return ERROR_MALFORMED;
1251309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1252309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1253309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t x;
1254309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
1255309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (err != OK) {
1256309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return err;
1257309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1258309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1259309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (x < 0) {
1260309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return ERROR_MALFORMED;
1261309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1262309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1263309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (seq) {
1264309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        *seq = x;
1265309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1266309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    return OK;
1267309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih}
126814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12692aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber// static
1270e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::ParseInt32(const char *s, int32_t *x) {
1271e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    char *end;
1272e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    long lval = strtol(s, &end, 10);
1273e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1274e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
1275e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
1276e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
1277e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1278e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    *x = (int32_t)lval;
1279e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1280e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
1281e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
1282e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
12839067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber// static
12849067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::ParseDouble(const char *s, double *x) {
12859067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    char *end;
12869067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double dval = strtod(s, &end);
12879067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
12889067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
12899067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
12909067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
12919067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
12929067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    *x = dval;
12939067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
12949067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
12959067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
12969067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
1297ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1298ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::isQuotedString(const AString &str) {
1299ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    if (str.size() < 2
1300ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            || str.c_str()[0] != '"'
1301ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            || str.c_str()[str.size() - 1] != '"') {
1302ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        return false;
1303ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1304ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    return true;
1305ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1306ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1307ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1308ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert ShihAString M3UParser::unquoteString(const AString &str) {
1309ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     if (!isQuotedString(str)) {
1310ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih         return str;
1311ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     }
1312ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     return AString(str, 1, str.size() - 2);
1313ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1314ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1315ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1316ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::codecIsType(const AString &codec, const char *type) {
1317ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    if (codec.size() < 4) {
1318ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        return false;
1319ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1320ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    const char *c = codec.c_str();
1321ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    switch (FOURCC(c[0], c[1], c[2], c[3])) {
1322ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        // List extracted from http://www.mp4ra.org/codecs.html
1323ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ac-3':
1324ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'alac':
1325ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dra1':
1326ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsc':
1327ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtse':
1328ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsh':
1329ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsl':
1330ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ec-3':
1331ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'enca':
1332ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'g719':
1333ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'g726':
1334ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'm4ae':
1335ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mlpa':
1336ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mp4a':
1337ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'raw ':
1338ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'samr':
1339ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sawb':
1340ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sawp':
1341ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sevc':
1342ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sqcp':
1343ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ssmv':
1344ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'twos':
1345ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'agsm':
1346ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'alaw':
1347ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvi ':
1348ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'fl32':
1349ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'fl64':
1350ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ima4':
1351ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'in24':
1352ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'in32':
1353ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'lpcm':
1354ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Qclp':
1355ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'QDM2':
1356ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'QDMC':
1357ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ulaw':
1358ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'vdva':
1359ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return !strcmp("audio", type);
1360ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1361ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avc1':
1362ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avc2':
1363ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avcp':
1364ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'drac':
1365ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'encv':
1366ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjp2':
1367ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mp4v':
1368ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mvc1':
1369ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mvc2':
1370ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'resv':
1371ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 's263':
1372ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'svc1':
1373ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'vc-1':
1374ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'CFHD':
1375ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'civd':
1376ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DV10':
1377ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvh5':
1378ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvh6':
1379ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvhp':
1380ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVOO':
1381ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVOR':
1382ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVTV':
1383ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVVT':
1384ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'flic':
1385ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'gif ':
1386ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'h261':
1387ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'h263':
1388ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'HD10':
1389ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'jpeg':
1390ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'M105':
1391ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjpa':
1392ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjpb':
1393ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'png ':
1394ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'PNTG':
1395ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'rle ':
1396ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'rpza':
1397ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr0':
1398ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr1':
1399ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr2':
1400ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr3':
1401ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr4':
1402ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'SVQ1':
1403ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'SVQ3':
1404ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'tga ':
1405ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'tiff':
1406ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'WRLE':
1407ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return !strcmp("video", type);
1408ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1409ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        default:
1410ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return false;
1411ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1412ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1413ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1414e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}  // namespace android
1415