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");
606985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih            } else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE")) {
607985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                if (mIsVariantPlaylist) {
608985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                    return ERROR_MALFORMED;
609985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                }
610985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                size_t seq;
611985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                err = parseDiscontinuitySequence(line, &seq);
612985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                if (err == OK) {
613985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                    mDiscontinuitySeq = seq;
614985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                    ALOGI("mDiscontinuitySeq %zu", mDiscontinuitySeq);
615985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                } else {
616985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                    ALOGI("Failed to parseDiscontinuitySequence %d", err);
617985746d11c888e110d5ea34d815efeb1115de0c6Robert Shih                }
6182a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
6192a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (mIsVariantPlaylist) {
6202a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    return ERROR_MALFORMED;
6212a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
6222a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (itemMeta == NULL) {
6232a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    itemMeta = new AMessage;
6242a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
6252a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                itemMeta->setInt32("discontinuity", true);
626c4547ba77f78632172db3647a09659d9863d3b5cChong Zhang                ++mDiscontinuityCount;
627e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-STREAM-INF")) {
628e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mMeta != NULL) {
629e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
630e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
631e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                mIsVariantPlaylist = true;
6322a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                err = parseStreamInf(line, &itemMeta);
6332aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            } else if (line.startsWith("#EXT-X-BYTERANGE")) {
6342aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (mIsVariantPlaylist) {
6352aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    return ERROR_MALFORMED;
6362aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
6372aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6382aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                uint64_t length, offset;
6392aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                err = parseByteRange(line, segmentRangeOffset, &length, &offset);
6402aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6412aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                if (err == OK) {
6422aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    if (itemMeta == NULL) {
6432aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                        itemMeta = new AMessage;
6442aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    }
6452aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6462aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-offset", offset);
6472aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    itemMeta->setInt64("range-length", length);
6482aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
6492aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                    segmentRangeOffset = offset + length;
6502aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber                }
65114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (line.startsWith("#EXT-X-MEDIA")) {
65214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                err = parseMedia(line);
653e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
654e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
655e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (err != OK) {
656e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                return err;
657e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
658e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
659e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
660e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (!line.startsWith("#")) {
661e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (!mIsVariantPlaylist) {
6629067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                int64_t durationUs;
663e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (itemMeta == NULL
6649067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber                        || !itemMeta->findInt64("durationUs", &durationUs)) {
665e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
666e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
667d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                itemMeta->setInt32("discontinuity-sequence",
668d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang                        mDiscontinuitySeq + mDiscontinuityCount);
669e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
670e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
671e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mItems.push();
672e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            Item *item = &mItems.editItemAt(mItems.size() - 1);
673e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
674e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
675e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
676e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            item->mMeta = itemMeta;
677e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
678e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            itemMeta.clear();
679e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
680e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
681e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        offset = offsetLF + 1;
682e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        ++lineNo;
683e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
684e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
685d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    // error checking of all fields that's required to appear once
686978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    // (currently only checking "target-duration"), and
687978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    // initialization of playlist properties (eg. mTargetDurationUs)
688978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang    if (!mIsVariantPlaylist) {
689978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        int32_t targetDurationSecs;
690978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (mMeta == NULL || !mMeta->findInt32(
691978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang                "target-duration", &targetDurationSecs)) {
692978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            ALOGE("Media playlist missing #EXT-X-TARGETDURATION");
693978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            return ERROR_MALFORMED;
694978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
695978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mTargetDurationUs = targetDurationSecs * 1000000ll;
696978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang
697978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mFirstSeqNumber = 0;
698978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        if (mMeta != NULL) {
699978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang            mMeta->findInt32("media-sequence", &mFirstSeqNumber);
700978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        }
701978449984366946a2e5c9f7cf350746f4306caf8Chong Zhang        mLastSeqNumber = mFirstSeqNumber + mItems.size() - 1;
702d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang    }
703d47dfcb5a2e5901c96fc92662cec7aa30f7f8843Chong Zhang
704af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih    for (size_t i = 0; i < mItems.size(); ++i) {
705af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih        sp<AMessage> meta = mItems.itemAt(i).mMeta;
706af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih        const char *keys[] = {"audio", "video", "subtitles"};
707af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih        for (size_t j = 0; j < sizeof(keys) / sizeof(const char *); ++j) {
708af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih            AString groupID;
709af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih            if (meta->findString(keys[j], &groupID)) {
710af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);
711af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                if (groupIndex < 0) {
712af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                    ALOGE("Undefined media group '%s' referenced in stream info.",
713af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                          groupID.c_str());
714af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                    return ERROR_MALFORMED;
715af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih                }
716af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih            }
717af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih        }
718af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih    }
719af464030d7f0a1d97eb308a06a873b7320f86aa9Robert Shih
720e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
721e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
722e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
723e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
724e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parseMetaData(
725e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
726e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    ssize_t colonPos = line.find(":");
727e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
728e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (colonPos < 0) {
729e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
730e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
731e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
732e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t x;
733e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
734e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
735e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (err != OK) {
736e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return err;
737e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
738e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
739e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta->get() == NULL) {
740e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = new AMessage;
741e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
742e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    (*meta)->setInt32(key, x);
743e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
744e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
745e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
746e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
747e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
7489067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::parseMetaDataDuration(
7499067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
7509067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    ssize_t colonPos = line.find(":");
7519067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7529067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (colonPos < 0) {
7539067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
7549067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
7559067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7569067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double x;
7579067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    status_t err = ParseDouble(line.c_str() + colonPos + 1, &x);
7589067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7599067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (err != OK) {
7609067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return err;
7619067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
7629067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7639067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (meta->get() == NULL) {
7649067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        *meta = new AMessage;
7659067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
766abd5feeea499ee7337125223df4ea22cae19cd20Oscar Rydhé    (*meta)->setInt64(key, (int64_t)(x * 1E6));
7679067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
7689067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
7699067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
7709067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
77114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Find the next occurence of the character "what" at or after "offset",
77214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// but ignore occurences between quotation marks.
77314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Return the index of the occurrence or -1 if not found.
77414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatic ssize_t FindNextUnquoted(
77514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const AString &line, char what, size_t offset) {
77614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    CHECK_NE((int)what, (int)'"');
77714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
77814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool quoted = false;
77914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (offset < line.size()) {
78014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        char c = line.c_str()[offset];
78114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
78214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (c == '"') {
78314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            quoted = !quoted;
78414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (c == what && !quoted) {
78514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return offset;
78614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
78714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
78814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ++offset;
78914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
79014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
79114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return -1;
79214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
79314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
7942a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huberstatus_t M3UParser::parseStreamInf(
79514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        const AString &line, sp<AMessage> *meta) const {
7962a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    ssize_t colonPos = line.find(":");
7972a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
7982a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (colonPos < 0) {
7992a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        return ERROR_MALFORMED;
8002a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
8012a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8022a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    size_t offset = colonPos + 1;
8032a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8042a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    while (offset < line.size()) {
80514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
8062a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (end < 0) {
8072a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            end = line.size();
8082a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
8092a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8102a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString attr(line, offset, end - offset);
8112a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        attr.trim();
8122a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8132a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        offset = end + 1;
8142a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8152a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t equalPos = attr.find("=");
8162a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (equalPos < 0) {
8172a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
8182a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
8192a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8202a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString key(attr, 0, equalPos);
8212a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        key.trim();
8222a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8232a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
8242a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        val.trim();
8252a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8263856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
8272a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8282a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (!strcasecmp("bandwidth", key.c_str())) {
8292a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            const char *s = val.c_str();
8302a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            char *end;
8312a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            unsigned long x = strtoul(s, &end, 10);
8322a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8332a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (end == s || *end != '\0') {
8342a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                // malformed
8352a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                continue;
8362a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
8372a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
8382a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (meta->get() == NULL) {
8392a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                *meta = new AMessage;
8402a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
8412a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            (*meta)->setInt32("bandwidth", x);
842ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        } else if (!strcasecmp("codecs", key.c_str())) {
843ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            if (!isQuotedString(val)) {
844ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                ALOGE("Expected quoted string for %s attribute, "
845ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                      "got '%s' instead.",
846ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                      key.c_str(), val.c_str());;
847ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
848ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih                return ERROR_MALFORMED;
849ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            }
850ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
851ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            key.tolower();
852ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            const AString &codecs = unquoteString(val);
8535154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            if (meta->get() == NULL) {
8545154f98277922aba7103ac19529ecc00b1889c1eRobert Shih                *meta = new AMessage;
8555154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            }
856ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            (*meta)->setString(key.c_str(), codecs.c_str());
857a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang        } else if (!strcasecmp("resolution", key.c_str())) {
858a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            const char *s = val.c_str();
859a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            char *end;
860a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            unsigned long width = strtoul(s, &end, 10);
861a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
862a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (end == s || *end != 'x') {
863a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                // malformed
864a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                continue;
865a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
866a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
867a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            s = end + 1;
868a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            unsigned long height = strtoul(s, &end, 10);
869a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
870a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (end == s || *end != '\0') {
871a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                // malformed
872a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                continue;
873a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
874a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang
875a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            if (meta->get() == NULL) {
876a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang                *meta = new AMessage;
877a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            }
878a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            (*meta)->setInt32("width", width);
879a0d0ba51ad60a68117a0ee78e37ab78715b8a069Chong Zhang            (*meta)->setInt32("height", height);
88014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("audio", key.c_str())
88114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                || !strcasecmp("video", key.c_str())
88214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                || !strcasecmp("subtitles", key.c_str())) {
883ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            if (!isQuotedString(val)) {
88414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for %s attribute, "
88514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
88614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      key.c_str(), val.c_str());
88714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
88814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
88914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
8902a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
891ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            const AString &groupID = unquoteString(val);
89214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            key.tolower();
8935154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            if (meta->get() == NULL) {
8945154f98277922aba7103ac19529ecc00b1889c1eRobert Shih                *meta = new AMessage;
8955154f98277922aba7103ac19529ecc00b1889c1eRobert Shih            }
89614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            (*meta)->setString(key.c_str(), groupID.c_str());
8970a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        }
8980a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber    }
8990a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
90014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return OK;
9010a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber}
9020a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber
9032a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber// static
904e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huberstatus_t M3UParser::parseCipherInfo(
905decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber        const AString &line, sp<AMessage> *meta, const AString &baseURI) {
906e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    ssize_t colonPos = line.find(":");
907e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
908e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    if (colonPos < 0) {
909e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        return ERROR_MALFORMED;
910e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
911e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
912e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    size_t offset = colonPos + 1;
913e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
914e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    while (offset < line.size()) {
9150a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
916e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (end < 0) {
917e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            end = line.size();
918e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
919e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
920e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString attr(line, offset, end - offset);
921e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        attr.trim();
922e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
923e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        offset = end + 1;
924e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
925e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        ssize_t equalPos = attr.find("=");
926e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (equalPos < 0) {
927e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            continue;
928e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
929e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
930e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString key(attr, 0, equalPos);
931e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.trim();
932e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
933e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
934e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        val.trim();
935e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
9363856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
937e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
938e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.tolower();
939e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
940e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (key == "method" || key == "uri" || key == "iv") {
941e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            if (meta->get() == NULL) {
942e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                *meta = new AMessage;
943e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            }
944e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
945decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            if (key == "uri") {
946decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (val.size() >= 2
947decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[0] == '"'
948decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                        && val.c_str()[val.size() - 1] == '"') {
949decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    // Remove surrounding quotes.
950decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    AString tmp(val, 1, val.size() - 2);
951decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = tmp;
952decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
953decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
954decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                AString absURI;
955decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) {
956decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                    val = absURI;
957decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                } else {
958a1df816c0677185534babba6ffc29970b048e52eLajos Molnar                    ALOGE("failed to make absolute url for %s.",
959a1df816c0677185534babba6ffc29970b048e52eLajos Molnar                            uriDebugString(baseURI).c_str());
960decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber                }
961decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber            }
962decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber
963e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            key.insert(AString("cipher-"), 0);
964e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
965e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            (*meta)->setString(key.c_str(), val.c_str(), val.size());
966e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
967e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
968e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
969e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    return OK;
970e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber}
971e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
972e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber// static
9732aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huberstatus_t M3UParser::parseByteRange(
9742aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const AString &line, uint64_t curOffset,
9752aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        uint64_t *length, uint64_t *offset) {
9762aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t colonPos = line.find(":");
9772aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9782aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (colonPos < 0) {
9792aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
9802aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
9812aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9822aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    ssize_t atPos = line.find("@", colonPos + 1);
9832aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9842aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    AString lenStr;
9852aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos < 0) {
9862aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1);
9872aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
9882aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        lenStr = AString(line, colonPos + 1, atPos - colonPos - 1);
9892aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
9902aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9912aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    lenStr.trim();
9922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9932aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    const char *s = lenStr.c_str();
9942aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    char *end;
9952aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    *length = strtoull(s, &end, 10);
9962aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
9972aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (s == end || *end != '\0') {
9982aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        return ERROR_MALFORMED;
9992aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
10002aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
10012aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    if (atPos >= 0) {
10022aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        AString offStr = AString(line, atPos + 1, line.size() - atPos - 1);
10032aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        offStr.trim();
10042aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
10052aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        const char *s = offStr.c_str();
10062aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = strtoull(s, &end, 10);
10072aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
10082aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        if (s == end || *end != '\0') {
10092aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber            return ERROR_MALFORMED;
10102aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        }
10112aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    } else {
10122aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber        *offset = curOffset;
10132aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    }
10142aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
10152aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber    return OK;
10162aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber}
10172aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber
101814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t M3UParser::parseMedia(const AString &line) {
101914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t colonPos = line.find(":");
102014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (colonPos < 0) {
102214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_MALFORMED;
102314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
102414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupType = false;
102614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    MediaGroup::Type groupType = MediaGroup::TYPE_AUDIO;
102714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
102814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupID = false;
102914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupID;
103014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupLanguage = false;
103214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupLanguage;
103314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupName = false;
103514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupName;
103614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
103714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupAutoselect = false;
103814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupAutoselect = false;
103914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupDefault = false;
104114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupDefault = false;
104214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupForced = false;
104414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool groupForced = false;
104514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    bool haveGroupURI = false;
104714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    AString groupURI;
104814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
104914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    size_t offset = colonPos + 1;
105014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
105114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    while (offset < line.size()) {
105214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t end = FindNextUnquoted(line, ',', offset);
105314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (end < 0) {
105414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            end = line.size();
105514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
105614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
105714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString attr(line, offset, end - offset);
105814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        attr.trim();
105914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        offset = end + 1;
106114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ssize_t equalPos = attr.find("=");
106314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (equalPos < 0) {
106414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            continue;
106514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
106614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
106714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString key(attr, 0, equalPos);
106814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        key.trim();
106914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
107014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
107114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        val.trim();
107214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
107314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGV("key=%s value=%s", key.c_str(), val.c_str());
107414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
107514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (!strcasecmp("type", key.c_str())) {
107614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("subtitles", val.c_str())) {
107714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_SUBS;
107814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("audio", val.c_str())) {
107914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_AUDIO;
108014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("video", val.c_str())) {
108114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupType = MediaGroup::TYPE_VIDEO;
108299cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang            } else if (!strcasecmp("closed-captions", val.c_str())){
108399cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang                groupType = MediaGroup::TYPE_CC;
108414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
108514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Invalid media group type '%s'", val.c_str());
108614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
108714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
108814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
108914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupType = true;
109014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("group-id", key.c_str())) {
109114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
109214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
109314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
109414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for GROUP-ID, got '%s' instead.",
109514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
109614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
109714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
109814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
109914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
110014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupID.setTo(val, 1, val.size() - 2);
110114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupID = true;
110214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("language", key.c_str())) {
110314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
110414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
110514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
110614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for LANGUAGE, got '%s' instead.",
110714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
110814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
110914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
111014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
111114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
111214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupLanguage.setTo(val, 1, val.size() - 2);
111314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupLanguage = true;
111414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("name", key.c_str())) {
111514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
111614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
111714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
111814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for NAME, got '%s' instead.",
111914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
112014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
112114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
112214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
112314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
112414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupName.setTo(val, 1, val.size() - 2);
112514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupName = true;
112614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("autoselect", key.c_str())) {
112714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupAutoselect = false;
112814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
112914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupAutoselect = true;
113014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
113114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupAutoselect = false;
113214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
113314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for AUTOSELECT attribute, "
113414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
113514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
113614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
113714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
113814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
113914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
114014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupAutoselect = true;
114114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("default", key.c_str())) {
114214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupDefault = false;
114314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
114414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupDefault = true;
114514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
114614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupDefault = false;
114714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
114814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for DEFAULT attribute, "
114914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
115014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
115114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
115214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
115314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
115414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
115514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupDefault = true;
115614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("forced", key.c_str())) {
115714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupForced = false;
115814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!strcasecmp("YES", val.c_str())) {
115914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupForced = true;
116014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else if (!strcasecmp("NO", val.c_str())) {
116114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                groupForced = false;
116214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            } else {
116314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected YES or NO for FORCED attribute, "
116414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      "got '%s' instead.",
116514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
116614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
116714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
116814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
116914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
117014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupForced = true;
117114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        } else if (!strcasecmp("uri", key.c_str())) {
117214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (val.size() < 2
117314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[0] != '"'
117414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                    || val.c_str()[val.size() - 1] != '"') {
117514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGE("Expected quoted string for URI, got '%s' instead.",
117614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                      val.c_str());
117714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
117814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                return ERROR_MALFORMED;
117914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
118014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
118114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            AString tmp(val, 1, val.size() - 2);
118214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
118314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            if (!MakeURL(mBaseURI.c_str(), tmp.c_str(), &groupURI)) {
118414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                ALOGI("Failed to make absolute URI from '%s'.", tmp.c_str());
118514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            }
118614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
118714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupURI = true;
118814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
118914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
119014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
119114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (!haveGroupType || !haveGroupID || !haveGroupName) {
119214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        ALOGE("Incomplete EXT-X-MEDIA element.");
119314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        return ERROR_MALFORMED;
119414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
119514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
119699cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang    if (groupType == MediaGroup::TYPE_CC) {
119799cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // TODO: ignore this for now.
119899cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // CC track will be detected by CCDecoder. But we still need to
119999cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        // pass the CC track flags (lang, auto) to the app in the future.
120099cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang        return OK;
120199cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang    }
120299cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang
120314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    uint32_t flags = 0;
120414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupAutoselect && groupAutoselect) {
120514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_AUTOSELECT;
120614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
120714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupDefault && groupDefault) {
120814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_DEFAULT;
120914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
121014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupForced) {
121114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (groupType != MediaGroup::TYPE_SUBS) {
121214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("The FORCED attribute MUST not be present on anything "
121314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  "but SUBS media.");
121414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
121514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
121614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
121714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
121814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (groupForced) {
121914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            flags |= MediaGroup::FLAG_FORCED;
122014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
122114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
122214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupLanguage) {
122314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_HAS_LANGUAGE;
122414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
122514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (haveGroupURI) {
122614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        flags |= MediaGroup::FLAG_HAS_URI;
122714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
122814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
122914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    ssize_t groupIndex = mMediaGroups.indexOfKey(groupID);
123014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    sp<MediaGroup> group;
123114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
123214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    if (groupIndex < 0) {
123314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        group = new MediaGroup(groupType);
123414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        mMediaGroups.add(groupID, group);
123514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    } else {
123614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        group = mMediaGroups.valueAt(groupIndex);
123714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
123814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        if (group->type() != groupType) {
123914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            ALOGE("Attempt to put media item under group of different type "
124014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  "(groupType = %d, item type = %d",
124114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  group->type(),
124214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber                  groupType);
124314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
124414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            return ERROR_MALFORMED;
124514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber        }
124614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    }
124714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
124814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber    return group->addMedia(
124914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            groupName.c_str(),
125014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupURI ? groupURI.c_str() : NULL,
125114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            haveGroupLanguage ? groupLanguage.c_str() : NULL,
125214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber            flags);
125314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber}
1254309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1255309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih// static
1256309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihstatus_t M3UParser::parseDiscontinuitySequence(const AString &line, size_t *seq) {
1257309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    ssize_t colonPos = line.find(":");
1258309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1259309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (colonPos < 0) {
1260309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return ERROR_MALFORMED;
1261309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1262309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1263309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    int32_t x;
1264309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
1265309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (err != OK) {
1266309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return err;
1267309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1268309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1269309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (x < 0) {
1270309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        return ERROR_MALFORMED;
1271309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1272309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih
1273309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    if (seq) {
1274309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih        *seq = x;
1275309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    }
1276309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih    return OK;
1277309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih}
127814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber
12792aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber// static
1280e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::ParseInt32(const char *s, int32_t *x) {
1281e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    char *end;
1282e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    long lval = strtol(s, &end, 10);
1283e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1284e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
1285e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
1286e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
1287e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1288e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    *x = (int32_t)lval;
1289e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1290e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
1291e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
1292e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
12939067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber// static
12949067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::ParseDouble(const char *s, double *x) {
12959067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    char *end;
12969067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    double dval = strtod(s, &end);
12979067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
12989067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
12999067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber        return ERROR_MALFORMED;
13009067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    }
13019067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
13029067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    *x = dval;
13039067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
13049067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber    return OK;
13059067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber}
13069067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber
1307ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1308ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::isQuotedString(const AString &str) {
1309ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    if (str.size() < 2
1310ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            || str.c_str()[0] != '"'
1311ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            || str.c_str()[str.size() - 1] != '"') {
1312ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        return false;
1313ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1314ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    return true;
1315ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1316ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1317ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1318ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert ShihAString M3UParser::unquoteString(const AString &str) {
1319ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     if (!isQuotedString(str)) {
1320ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih         return str;
1321ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     }
1322ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih     return AString(str, 1, str.size() - 2);
1323ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1324ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1325ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static
1326ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::codecIsType(const AString &codec, const char *type) {
1327ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    if (codec.size() < 4) {
1328ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        return false;
1329ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1330ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    const char *c = codec.c_str();
1331ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    switch (FOURCC(c[0], c[1], c[2], c[3])) {
1332ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        // List extracted from http://www.mp4ra.org/codecs.html
1333ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ac-3':
1334ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'alac':
1335ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dra1':
1336ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsc':
1337ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtse':
1338ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsh':
1339ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dtsl':
1340ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ec-3':
1341ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'enca':
1342ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'g719':
1343ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'g726':
1344ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'm4ae':
1345ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mlpa':
1346ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mp4a':
1347ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'raw ':
1348ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'samr':
1349ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sawb':
1350ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sawp':
1351ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sevc':
1352ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'sqcp':
1353ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ssmv':
1354ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'twos':
1355ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'agsm':
1356ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'alaw':
1357ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvi ':
1358ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'fl32':
1359ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'fl64':
1360ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ima4':
1361ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'in24':
1362ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'in32':
1363ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'lpcm':
1364ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Qclp':
1365ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'QDM2':
1366ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'QDMC':
1367ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'ulaw':
1368ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'vdva':
1369ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return !strcmp("audio", type);
1370ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1371ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avc1':
1372ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avc2':
1373ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'avcp':
1374ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'drac':
1375ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'encv':
1376ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjp2':
1377ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mp4v':
1378ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mvc1':
1379ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mvc2':
1380ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'resv':
1381ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 's263':
1382ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'svc1':
1383ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'vc-1':
1384ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'CFHD':
1385ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'civd':
1386ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DV10':
1387ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvh5':
1388ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvh6':
1389ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'dvhp':
1390ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVOO':
1391ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVOR':
1392ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVTV':
1393ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'DVVT':
1394ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'flic':
1395ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'gif ':
1396ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'h261':
1397ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'h263':
1398ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'HD10':
1399ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'jpeg':
1400ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'M105':
1401ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjpa':
1402ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'mjpb':
1403ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'png ':
1404ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'PNTG':
1405ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'rle ':
1406ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'rpza':
1407ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr0':
1408ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr1':
1409ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr2':
1410ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr3':
1411ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'Shr4':
1412ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'SVQ1':
1413ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'SVQ3':
1414ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'tga ':
1415ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'tiff':
1416ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        case 'WRLE':
1417ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return !strcmp("video", type);
1418ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1419ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih        default:
1420ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih            return false;
1421ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih    }
1422ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih}
1423ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih
1424e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}  // namespace android
1425