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), 253309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih mDiscontinuitySeq(0), 254dcb89b3b505522efde173c105a851c412f947178Chong Zhang mSelectedIndex(-1) { 255e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber mInitCheck = parse(data, size); 256e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 257e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 258e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::~M3UParser() { 259e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 260e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 261e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::initCheck() const { 262e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return mInitCheck; 263e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 264e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 265e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isExtM3U() const { 266e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return mIsExtM3U; 267e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 268e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 269e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isVariantPlaylist() const { 270e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return mIsVariantPlaylist; 271e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 272e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 273bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huberbool M3UParser::isComplete() const { 274bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber return mIsComplete; 275bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber} 276bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber 277b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huberbool M3UParser::isEvent() const { 278b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber return mIsEvent; 279b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber} 280b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber 281309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihsize_t M3UParser::getDiscontinuitySeq() const { 282309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih return mDiscontinuitySeq; 283309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih} 284309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 285e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersp<AMessage> M3UParser::meta() { 286e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return mMeta; 287e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 288e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 289e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersize_t M3UParser::size() { 290e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return mItems.size(); 291e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 292e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 293e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) { 2940f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber if (uri) { 2950f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber uri->clear(); 2960f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber } 2970f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber 2980f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber if (meta) { 2990f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber *meta = NULL; 3000f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber } 301e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 302e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (index >= mItems.size()) { 303e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return false; 304e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 305e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 3060f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber if (uri) { 3070f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber *uri = mItems.itemAt(index).mURI; 3080f30bd90272c818aa37c0bb22d22eaa7d3689879Andreas Huber } 309e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 310e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (meta) { 311e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *meta = mItems.itemAt(index).mMeta; 312e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 313e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 314e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return true; 315e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 316e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 31714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Hubervoid M3UParser::pickRandomMediaItems() { 31814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber for (size_t i = 0; i < mMediaGroups.size(); ++i) { 31914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber mMediaGroups.valueAt(i)->pickRandomMediaItems(); 32014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 32114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber} 32214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 323dcb89b3b505522efde173c105a851c412f947178Chong Zhangstatus_t M3UParser::selectTrack(size_t index, bool select) { 324dcb89b3b505522efde173c105a851c412f947178Chong Zhang for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) { 325dcb89b3b505522efde173c105a851c412f947178Chong Zhang sp<MediaGroup> group = mMediaGroups.valueAt(i); 326dcb89b3b505522efde173c105a851c412f947178Chong Zhang size_t tracks = group->countTracks(); 327dcb89b3b505522efde173c105a851c412f947178Chong Zhang if (ii < tracks) { 328dcb89b3b505522efde173c105a851c412f947178Chong Zhang status_t err = group->selectTrack(ii, select); 329dcb89b3b505522efde173c105a851c412f947178Chong Zhang if (err == OK) { 330dcb89b3b505522efde173c105a851c412f947178Chong Zhang mSelectedIndex = select ? index : -1; 331dcb89b3b505522efde173c105a851c412f947178Chong Zhang } 332dcb89b3b505522efde173c105a851c412f947178Chong Zhang return err; 333dcb89b3b505522efde173c105a851c412f947178Chong Zhang } 334dcb89b3b505522efde173c105a851c412f947178Chong Zhang ii -= tracks; 335dcb89b3b505522efde173c105a851c412f947178Chong Zhang } 336dcb89b3b505522efde173c105a851c412f947178Chong Zhang return INVALID_OPERATION; 337dcb89b3b505522efde173c105a851c412f947178Chong Zhang} 338dcb89b3b505522efde173c105a851c412f947178Chong Zhang 339404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsize_t M3UParser::getTrackCount() const { 340dcb89b3b505522efde173c105a851c412f947178Chong Zhang size_t trackCount = 0; 341dcb89b3b505522efde173c105a851c412f947178Chong Zhang for (size_t i = 0; i < mMediaGroups.size(); ++i) { 342dcb89b3b505522efde173c105a851c412f947178Chong Zhang trackCount += mMediaGroups.valueAt(i)->countTracks(); 343dcb89b3b505522efde173c105a851c412f947178Chong Zhang } 344404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang return trackCount; 345404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang} 346dcb89b3b505522efde173c105a851c412f947178Chong Zhang 347404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhangsp<AMessage> M3UParser::getTrackInfo(size_t index) const { 348404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang for (size_t i = 0, ii = index; i < mMediaGroups.size(); ++i) { 349404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang sp<MediaGroup> group = mMediaGroups.valueAt(i); 350404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang size_t tracks = group->countTracks(); 351404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang if (ii < tracks) { 352404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang return group->getTrackInfo(ii); 353404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang } 354404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang ii -= tracks; 355dcb89b3b505522efde173c105a851c412f947178Chong Zhang } 356404fced9bfa8fa423ee210a271ca051ffd1bec13Chong Zhang return NULL; 357dcb89b3b505522efde173c105a851c412f947178Chong Zhang} 358dcb89b3b505522efde173c105a851c412f947178Chong Zhang 359dcb89b3b505522efde173c105a851c412f947178Chong Zhangssize_t M3UParser::getSelectedIndex() const { 360dcb89b3b505522efde173c105a851c412f947178Chong Zhang return mSelectedIndex; 361dcb89b3b505522efde173c105a851c412f947178Chong Zhang} 362dcb89b3b505522efde173c105a851c412f947178Chong Zhang 36389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shihssize_t M3UParser::getSelectedTrack(media_track_type type) const { 36489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih MediaGroup::Type groupType; 36589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih switch (type) { 36689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih case MEDIA_TRACK_TYPE_VIDEO: 36789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih groupType = MediaGroup::TYPE_VIDEO; 36889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih break; 36989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 37089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih case MEDIA_TRACK_TYPE_AUDIO: 37189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih groupType = MediaGroup::TYPE_AUDIO; 37289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih break; 37389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 37489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih case MEDIA_TRACK_TYPE_SUBTITLE: 37589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih groupType = MediaGroup::TYPE_SUBS; 37689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih break; 37789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 37889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih default: 37989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih return -1; 38089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih } 38189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 38289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih for (size_t i = 0, ii = 0; i < mMediaGroups.size(); ++i) { 38389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih sp<MediaGroup> group = mMediaGroups.valueAt(i); 38489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih size_t tracks = group->countTracks(); 38589bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih if (groupType != group->mType) { 38689bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih ii += tracks; 38789bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih } else if (group->mSelectedIndex >= 0) { 38889bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih return ii + group->mSelectedIndex; 38989bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih } 39089bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih } 39189bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 39289bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih return -1; 39389bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih} 39489bf2525c5b57f17260de5b00c5f3f78ac4b881eRobert Shih 39514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberbool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const { 39614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!mIsVariantPlaylist) { 39714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *uri = mBaseURI; 39814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 39914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber // Assume media without any more specific attribute contains 40014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber // audio and video, but no subtitles. 40114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return !strcmp("audio", key) || !strcmp("video", key); 40214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 40314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 40414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber CHECK_LT(index, mItems.size()); 40514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 40614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber sp<AMessage> meta = mItems.itemAt(index).mMeta; 40714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 40814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString groupID; 40914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!meta->findString(key, &groupID)) { 41014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *uri = mItems.itemAt(index).mURI; 41114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 412ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih AString codecs; 413ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (!meta->findString("codecs", &codecs)) { 414ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // Assume media without any more specific attribute contains 415ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // audio and video, but no subtitles. 416ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return !strcmp("audio", key) || !strcmp("video", key); 417ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } else { 418ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // Split the comma separated list of codecs. 419ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih size_t offset = 0; 420ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih ssize_t commaPos = -1; 421ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih codecs.append(','); 422ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih while ((commaPos = codecs.find(",", offset)) >= 0) { 423ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih AString codec(codecs, offset, commaPos - offset); 4241ac1638077277de52d1dd4c54db71e67753f1960Robert Shih codec.trim(); 425ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // return true only if a codec of type `key` ("audio"/"video") 426ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // is found. 427ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (codecIsType(codec, key)) { 428ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return true; 429ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 430ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih offset = commaPos + 1; 431ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 432ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return false; 433ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 43414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 43514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 43614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber sp<MediaGroup> group = mMediaGroups.valueFor(groupID); 43714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!group->getActiveURI(uri)) { 43814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return false; 43914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 44014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 44114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if ((*uri).empty()) { 44214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber *uri = mItems.itemAt(index).mURI; 44314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 44414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 44514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return true; 44614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber} 44714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 448e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatic bool MakeURL(const char *baseURL, const char *url, AString *out) { 449e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber out->clear(); 450e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 4512a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (strncasecmp("http://", baseURL, 7) 452df42f949c8bd05b81d94633767514fff88f52062Andreas Huber && strncasecmp("https://", baseURL, 8) 4532a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber && strncasecmp("file://", baseURL, 7)) { 454e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber // Base URL must be absolute 455e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return false; 456e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 457a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar const size_t schemeEnd = (strstr(baseURL, "//") - baseURL) + 2; 458a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar CHECK(schemeEnd == 7 || schemeEnd == 8); 459e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 460df42f949c8bd05b81d94633767514fff88f52062Andreas Huber if (!strncasecmp("http://", url, 7) || !strncasecmp("https://", url, 8)) { 461e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber // "url" is already an absolute URL, ignore base URL. 462e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber out->setTo(url); 463ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber 4643856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str()); 465ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber 466e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return true; 467e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 468e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 469d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber if (url[0] == '/') { 470d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber // URL is an absolute path. 471d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber 472d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber char *protocolEnd = strstr(baseURL, "//") + 2; 473d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber char *pathStart = strchr(protocolEnd, '/'); 474e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 475d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber if (pathStart != NULL) { 476d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber out->setTo(baseURL, pathStart - baseURL); 477e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } else { 478e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber out->setTo(baseURL); 479e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 480e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 481e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber out->append(url); 482d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber } else { 483d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber // URL is a relative path 484d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber 4858883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo // Check for a possible query string 4868883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo const char *qsPos = strchr(baseURL, '?'); 4878883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo size_t end; 4888883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo if (qsPos != NULL) { 4898883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo end = qsPos - baseURL; 490d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber } else { 4918883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo end = strlen(baseURL); 4928883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo } 4938883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo // Check for the last slash before a potential query string 494e175d77bb610675ba2f70f24449189995ddeaf5bMarco Nelissen for (ssize_t pos = end - 1; pos >= 0; pos--) { 4958883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo if (baseURL[pos] == '/') { 4968883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo end = pos; 4978883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo break; 498d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber } 4998883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo } 500d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber 5018883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo // Check whether the found slash actually is part of the path 5028883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo // and not part of the "http://". 503a8454c29b15748964b5eb556d1e23fbb1ee19cebLajos Molnar if (end >= schemeEnd) { 5048883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo out->setTo(baseURL, end); 5058883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo } else { 5068883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo out->setTo(baseURL); 507d6a46a6bda23667e06ee5ccca3781e407c7d1204Andreas Huber } 5088883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo 5098883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo out->append("/"); 5108883a38a308fb02a653c990118ec7931a47b749bMartin Storsjo out->append(url); 511e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 512e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 5133856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("base:'%s', url:'%s' => '%s'", baseURL, url, out->c_str()); 514ac13b81c590386b3a42e381b31d7614ca53b79c5Andreas Huber 515e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return true; 516e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 517e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 518e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parse(const void *_data, size_t size) { 519e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber int32_t lineNo = 0; 520e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 521e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber sp<AMessage> itemMeta; 522e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 523e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber const char *data = (const char *)_data; 524e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber size_t offset = 0; 5252aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber uint64_t segmentRangeOffset = 0; 526e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber while (offset < size) { 527e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber size_t offsetLF = offset; 528e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber while (offsetLF < size && data[offsetLF] != '\n') { 529e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber ++offsetLF; 530e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 531e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 532e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber AString line; 533e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (offsetLF > offset && data[offsetLF - 1] == '\r') { 534e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber line.setTo(&data[offset], offsetLF - offset - 1); 535e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } else { 536e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber line.setTo(&data[offset], offsetLF - offset); 537e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 538e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 539df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block // ALOGI("#%s#", line.c_str()); 5402a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 5412a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (line.empty()) { 5422a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber offset = offsetLF + 1; 5432a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber continue; 5442a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 545e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 546e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (lineNo == 0 && line == "#EXTM3U") { 547e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber mIsExtM3U = true; 548e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 549e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 550e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (mIsExtM3U) { 551e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber status_t err = OK; 552e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 553e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (line.startsWith("#EXT-X-TARGETDURATION")) { 554e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (mIsVariantPlaylist) { 555e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 556e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 557e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber err = parseMetaData(line, &mMeta, "target-duration"); 558e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) { 559e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (mIsVariantPlaylist) { 560e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 561e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 562e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber err = parseMetaData(line, &mMeta, "media-sequence"); 563e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } else if (line.startsWith("#EXT-X-KEY")) { 564e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (mIsVariantPlaylist) { 565e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber return ERROR_MALFORMED; 566e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 567decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber err = parseCipherInfo(line, &itemMeta, mBaseURI); 568bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber } else if (line.startsWith("#EXT-X-ENDLIST")) { 569bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber mIsComplete = true; 570b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber } else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:EVENT")) { 571b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber mIsEvent = true; 572e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } else if (line.startsWith("#EXTINF")) { 573e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (mIsVariantPlaylist) { 574e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 575e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 5769067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber err = parseMetaDataDuration(line, &itemMeta, "durationUs"); 5772a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } else if (line.startsWith("#EXT-X-DISCONTINUITY")) { 5782a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (mIsVariantPlaylist) { 5792a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber return ERROR_MALFORMED; 5802a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 5812a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (itemMeta == NULL) { 5822a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber itemMeta = new AMessage; 5832a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 5842a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber itemMeta->setInt32("discontinuity", true); 585e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } else if (line.startsWith("#EXT-X-STREAM-INF")) { 586e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (mMeta != NULL) { 587e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 588e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 589e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber mIsVariantPlaylist = true; 5902a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber err = parseStreamInf(line, &itemMeta); 5912aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } else if (line.startsWith("#EXT-X-BYTERANGE")) { 5922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (mIsVariantPlaylist) { 5932aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber return ERROR_MALFORMED; 5942aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 5952aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 5962aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber uint64_t length, offset; 5972aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber err = parseByteRange(line, segmentRangeOffset, &length, &offset); 5982aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 5992aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (err == OK) { 6002aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (itemMeta == NULL) { 6012aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber itemMeta = new AMessage; 6022aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 6032aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 6042aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber itemMeta->setInt64("range-offset", offset); 6052aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber itemMeta->setInt64("range-length", length); 6062aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 6072aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber segmentRangeOffset = offset + length; 6082aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 60914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (line.startsWith("#EXT-X-MEDIA")) { 61014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber err = parseMedia(line); 611309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE")) { 612309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih size_t seq; 613309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih err = parseDiscontinuitySequence(line, &seq); 614309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih if (err == OK) { 615309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih mDiscontinuitySeq = seq; 616309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } 617e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 618e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 619e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (err != OK) { 620e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return err; 621e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 622e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 623e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 624e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (!line.startsWith("#")) { 625e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (!mIsVariantPlaylist) { 6269067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber int64_t durationUs; 627e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (itemMeta == NULL 6289067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber || !itemMeta->findInt64("durationUs", &durationUs)) { 629e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 630e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 631e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 632e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 633e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber mItems.push(); 634e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber Item *item = &mItems.editItemAt(mItems.size() - 1); 635e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 636e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI)); 637e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 638e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber item->mMeta = itemMeta; 639e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 640e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber itemMeta.clear(); 641e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 642e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 643e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber offset = offsetLF + 1; 644e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber ++lineNo; 645e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 646e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 647e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return OK; 648e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 649e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 650e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static 651e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parseMetaData( 652e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber const AString &line, sp<AMessage> *meta, const char *key) { 653e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber ssize_t colonPos = line.find(":"); 654e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 655e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (colonPos < 0) { 656e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 657e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 658e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 659e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber int32_t x; 660e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber status_t err = ParseInt32(line.c_str() + colonPos + 1, &x); 661e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 662e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (err != OK) { 663e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return err; 664e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 665e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 666e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (meta->get() == NULL) { 667e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *meta = new AMessage; 668e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 669e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber (*meta)->setInt32(key, x); 670e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 671e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return OK; 672e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 673e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 674e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static 6759067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::parseMetaDataDuration( 6769067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber const AString &line, sp<AMessage> *meta, const char *key) { 6779067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber ssize_t colonPos = line.find(":"); 6789067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 6799067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber if (colonPos < 0) { 6809067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber return ERROR_MALFORMED; 6819067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber } 6829067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 6839067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber double x; 6849067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber status_t err = ParseDouble(line.c_str() + colonPos + 1, &x); 6859067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 6869067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber if (err != OK) { 6879067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber return err; 6889067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber } 6899067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 6909067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber if (meta->get() == NULL) { 6919067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber *meta = new AMessage; 6929067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber } 693abd5feeea499ee7337125223df4ea22cae19cd20Oscar Rydhé (*meta)->setInt64(key, (int64_t)(x * 1E6)); 6949067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 6959067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber return OK; 6969067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber} 6979067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 69814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Find the next occurence of the character "what" at or after "offset", 69914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// but ignore occurences between quotation marks. 70014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber// Return the index of the occurrence or -1 if not found. 70114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatic ssize_t FindNextUnquoted( 70214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber const AString &line, char what, size_t offset) { 70314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber CHECK_NE((int)what, (int)'"'); 70414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 70514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool quoted = false; 70614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber while (offset < line.size()) { 70714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber char c = line.c_str()[offset]; 70814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 70914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (c == '"') { 71014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber quoted = !quoted; 71114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (c == what && !quoted) { 71214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return offset; 71314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 71414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 71514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ++offset; 71614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 71714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 71814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return -1; 71914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber} 72014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 7212a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huberstatus_t M3UParser::parseStreamInf( 72214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber const AString &line, sp<AMessage> *meta) const { 7232a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber ssize_t colonPos = line.find(":"); 7242a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7252a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (colonPos < 0) { 7262a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber return ERROR_MALFORMED; 7272a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 7282a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7292a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber size_t offset = colonPos + 1; 7302a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7312a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber while (offset < line.size()) { 73214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t end = FindNextUnquoted(line, ',', offset); 7332a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (end < 0) { 7342a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber end = line.size(); 7352a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 7362a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7372a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber AString attr(line, offset, end - offset); 7382a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber attr.trim(); 7392a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7402a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber offset = end + 1; 7412a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7422a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber ssize_t equalPos = attr.find("="); 7432a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (equalPos < 0) { 7442a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber continue; 7452a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 7462a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7472a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber AString key(attr, 0, equalPos); 7482a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber key.trim(); 7492a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7502a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber AString val(attr, equalPos + 1, attr.size() - equalPos - 1); 7512a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber val.trim(); 7522a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7533856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("key=%s value=%s", key.c_str(), val.c_str()); 7542a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7552a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (!strcasecmp("bandwidth", key.c_str())) { 7562a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber const char *s = val.c_str(); 7572a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber char *end; 7582a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber unsigned long x = strtoul(s, &end, 10); 7592a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7602a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (end == s || *end != '\0') { 7612a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber // malformed 7622a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber continue; 7632a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 7642a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 7652a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber if (meta->get() == NULL) { 7662a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber *meta = new AMessage; 7672a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber } 7682a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber (*meta)->setInt32("bandwidth", x); 769ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } else if (!strcasecmp("codecs", key.c_str())) { 770ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (!isQuotedString(val)) { 771ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih ALOGE("Expected quoted string for %s attribute, " 772ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih "got '%s' instead.", 773ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih key.c_str(), val.c_str());; 774ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 775ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return ERROR_MALFORMED; 776ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 777ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 778ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih key.tolower(); 779ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih const AString &codecs = unquoteString(val); 7805154f98277922aba7103ac19529ecc00b1889c1eRobert Shih if (meta->get() == NULL) { 7815154f98277922aba7103ac19529ecc00b1889c1eRobert Shih *meta = new AMessage; 7825154f98277922aba7103ac19529ecc00b1889c1eRobert Shih } 783ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih (*meta)->setString(key.c_str(), codecs.c_str()); 78414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("audio", key.c_str()) 78514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || !strcasecmp("video", key.c_str()) 78614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || !strcasecmp("subtitles", key.c_str())) { 787ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (!isQuotedString(val)) { 78814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected quoted string for %s attribute, " 78914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "got '%s' instead.", 79014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber key.c_str(), val.c_str()); 79114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 79214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 79314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 7942a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 795ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih const AString &groupID = unquoteString(val); 79614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t groupIndex = mMediaGroups.indexOfKey(groupID); 7972a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber 79814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (groupIndex < 0) { 79914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Undefined media group '%s' referenced in stream info.", 80014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupID.c_str()); 8010a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber 80214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 80314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 8040a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber 80514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber key.tolower(); 8065154f98277922aba7103ac19529ecc00b1889c1eRobert Shih if (meta->get() == NULL) { 8075154f98277922aba7103ac19529ecc00b1889c1eRobert Shih *meta = new AMessage; 8085154f98277922aba7103ac19529ecc00b1889c1eRobert Shih } 80914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber (*meta)->setString(key.c_str(), groupID.c_str()); 8100a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber } 8110a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber } 8120a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber 81314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return OK; 8140a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber} 8150a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber 8162a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber// static 817e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huberstatus_t M3UParser::parseCipherInfo( 818decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber const AString &line, sp<AMessage> *meta, const AString &baseURI) { 819e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber ssize_t colonPos = line.find(":"); 820e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 821e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (colonPos < 0) { 822e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber return ERROR_MALFORMED; 823e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 824e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 825e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber size_t offset = colonPos + 1; 826e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 827e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber while (offset < line.size()) { 8280a73d81f213fb2d6f2fdd59c4dda047bf453bb1cAndreas Huber ssize_t end = FindNextUnquoted(line, ',', offset); 829e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (end < 0) { 830e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber end = line.size(); 831e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 832e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 833e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber AString attr(line, offset, end - offset); 834e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber attr.trim(); 835e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 836e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber offset = end + 1; 837e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 838e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber ssize_t equalPos = attr.find("="); 839e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (equalPos < 0) { 840e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber continue; 841e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 842e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 843e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber AString key(attr, 0, equalPos); 844e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber key.trim(); 845e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 846e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber AString val(attr, equalPos + 1, attr.size() - equalPos - 1); 847e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber val.trim(); 848e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 8493856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("key=%s value=%s", key.c_str(), val.c_str()); 850e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 851e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber key.tolower(); 852e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 853e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (key == "method" || key == "uri" || key == "iv") { 854e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber if (meta->get() == NULL) { 855e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber *meta = new AMessage; 856e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 857e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 858decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber if (key == "uri") { 859decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber if (val.size() >= 2 860decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber && val.c_str()[0] == '"' 861decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber && val.c_str()[val.size() - 1] == '"') { 862decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber // Remove surrounding quotes. 863decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber AString tmp(val, 1, val.size() - 2); 864decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber val = tmp; 865decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber } 866decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber 867decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber AString absURI; 868decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber if (MakeURL(baseURI.c_str(), val.c_str(), &absURI)) { 869decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber val = absURI; 870decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber } else { 871a1df816c0677185534babba6ffc29970b048e52eLajos Molnar ALOGE("failed to make absolute url for %s.", 872a1df816c0677185534babba6ffc29970b048e52eLajos Molnar uriDebugString(baseURI).c_str()); 873decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber } 874decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber } 875decd96988e495133e4a1728f612d4c9fdb4d218eAndreas Huber 876e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber key.insert(AString("cipher-"), 0); 877e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 878e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber (*meta)->setString(key.c_str(), val.c_str(), val.size()); 879e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 880e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber } 881e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 882e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber return OK; 883e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber} 884e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber 885e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber// static 8862aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huberstatus_t M3UParser::parseByteRange( 8872aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber const AString &line, uint64_t curOffset, 8882aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber uint64_t *length, uint64_t *offset) { 8892aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber ssize_t colonPos = line.find(":"); 8902aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 8912aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (colonPos < 0) { 8922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber return ERROR_MALFORMED; 8932aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 8942aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 8952aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber ssize_t atPos = line.find("@", colonPos + 1); 8962aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 8972aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber AString lenStr; 8982aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (atPos < 0) { 8992aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1); 9002aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } else { 9012aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber lenStr = AString(line, colonPos + 1, atPos - colonPos - 1); 9022aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 9032aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9042aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber lenStr.trim(); 9052aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9062aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber const char *s = lenStr.c_str(); 9072aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber char *end; 9082aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber *length = strtoull(s, &end, 10); 9092aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9102aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (s == end || *end != '\0') { 9112aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber return ERROR_MALFORMED; 9122aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 9132aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9142aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (atPos >= 0) { 9152aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber AString offStr = AString(line, atPos + 1, line.size() - atPos - 1); 9162aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber offStr.trim(); 9172aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9182aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber const char *s = offStr.c_str(); 9192aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber *offset = strtoull(s, &end, 10); 9202aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9212aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber if (s == end || *end != '\0') { 9222aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber return ERROR_MALFORMED; 9232aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 9242aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } else { 9252aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber *offset = curOffset; 9262aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber } 9272aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 9282aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber return OK; 9292aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber} 9302aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber 93114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberstatus_t M3UParser::parseMedia(const AString &line) { 93214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t colonPos = line.find(":"); 93314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 93414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (colonPos < 0) { 93514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 93614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 93714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 93814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupType = false; 93914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber MediaGroup::Type groupType = MediaGroup::TYPE_AUDIO; 94014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 94114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupID = false; 94214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString groupID; 94314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 94414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupLanguage = false; 94514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString groupLanguage; 94614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 94714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupName = false; 94814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString groupName; 94914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 95014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupAutoselect = false; 95114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool groupAutoselect = false; 95214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 95314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupDefault = false; 95414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool groupDefault = false; 95514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 95614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupForced = false; 95714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool groupForced = false; 95814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 95914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber bool haveGroupURI = false; 96014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString groupURI; 96114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 96214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber size_t offset = colonPos + 1; 96314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 96414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber while (offset < line.size()) { 96514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t end = FindNextUnquoted(line, ',', offset); 96614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (end < 0) { 96714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber end = line.size(); 96814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 96914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 97014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString attr(line, offset, end - offset); 97114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber attr.trim(); 97214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 97314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber offset = end + 1; 97414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 97514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t equalPos = attr.find("="); 97614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (equalPos < 0) { 97714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber continue; 97814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 97914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 98014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString key(attr, 0, equalPos); 98114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber key.trim(); 98214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 98314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString val(attr, equalPos + 1, attr.size() - equalPos - 1); 98414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.trim(); 98514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 98614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGV("key=%s value=%s", key.c_str(), val.c_str()); 98714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 98814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!strcasecmp("type", key.c_str())) { 98914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!strcasecmp("subtitles", val.c_str())) { 99014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupType = MediaGroup::TYPE_SUBS; 99114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("audio", val.c_str())) { 99214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupType = MediaGroup::TYPE_AUDIO; 99314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("video", val.c_str())) { 99414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupType = MediaGroup::TYPE_VIDEO; 99599cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang } else if (!strcasecmp("closed-captions", val.c_str())){ 99699cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang groupType = MediaGroup::TYPE_CC; 99714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else { 99814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Invalid media group type '%s'", val.c_str()); 99914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 100014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 100114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 100214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupType = true; 100314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("group-id", key.c_str())) { 100414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (val.size() < 2 100514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[0] != '"' 100614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[val.size() - 1] != '"') { 100714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected quoted string for GROUP-ID, got '%s' instead.", 100814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 100914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 101014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 101114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 101214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 101314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupID.setTo(val, 1, val.size() - 2); 101414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupID = true; 101514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("language", key.c_str())) { 101614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (val.size() < 2 101714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[0] != '"' 101814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[val.size() - 1] != '"') { 101914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected quoted string for LANGUAGE, got '%s' instead.", 102014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 102114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 102214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 102314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 102414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 102514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupLanguage.setTo(val, 1, val.size() - 2); 102614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupLanguage = true; 102714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("name", key.c_str())) { 102814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (val.size() < 2 102914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[0] != '"' 103014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[val.size() - 1] != '"') { 103114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected quoted string for NAME, got '%s' instead.", 103214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 103314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 103414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 103514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 103614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 103714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupName.setTo(val, 1, val.size() - 2); 103814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupName = true; 103914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("autoselect", key.c_str())) { 104014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupAutoselect = false; 104114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!strcasecmp("YES", val.c_str())) { 104214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupAutoselect = true; 104314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("NO", val.c_str())) { 104414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupAutoselect = false; 104514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else { 104614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected YES or NO for AUTOSELECT attribute, " 104714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "got '%s' instead.", 104814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 104914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 105014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 105114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 105214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 105314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupAutoselect = true; 105414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("default", key.c_str())) { 105514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupDefault = false; 105614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!strcasecmp("YES", val.c_str())) { 105714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupDefault = true; 105814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("NO", val.c_str())) { 105914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupDefault = false; 106014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else { 106114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected YES or NO for DEFAULT attribute, " 106214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "got '%s' instead.", 106314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 106414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 106514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 106614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 106714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 106814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupDefault = true; 106914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("forced", key.c_str())) { 107014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupForced = false; 107114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!strcasecmp("YES", val.c_str())) { 107214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupForced = true; 107314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("NO", val.c_str())) { 107414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupForced = false; 107514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else { 107614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected YES or NO for FORCED attribute, " 107714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "got '%s' instead.", 107814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 107914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 108014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 108114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 108214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 108314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupForced = true; 108414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else if (!strcasecmp("uri", key.c_str())) { 108514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (val.size() < 2 108614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[0] != '"' 108714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber || val.c_str()[val.size() - 1] != '"') { 108814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Expected quoted string for URI, got '%s' instead.", 108914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber val.c_str()); 109014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 109114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 109214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 109314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 109414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber AString tmp(val, 1, val.size() - 2); 109514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 109614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!MakeURL(mBaseURI.c_str(), tmp.c_str(), &groupURI)) { 109714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGI("Failed to make absolute URI from '%s'.", tmp.c_str()); 109814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 109914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 110014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupURI = true; 110114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 110214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 110314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 110414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (!haveGroupType || !haveGroupID || !haveGroupName) { 110514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Incomplete EXT-X-MEDIA element."); 110614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 110714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 110814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 110999cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang if (groupType == MediaGroup::TYPE_CC) { 111099cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang // TODO: ignore this for now. 111199cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang // CC track will be detected by CCDecoder. But we still need to 111299cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang // pass the CC track flags (lang, auto) to the app in the future. 111399cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang return OK; 111499cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang } 111599cef1ef1cf1232966fabf3793ce7964c01474d7Chong Zhang 111614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber uint32_t flags = 0; 111714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (haveGroupAutoselect && groupAutoselect) { 111814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags |= MediaGroup::FLAG_AUTOSELECT; 111914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 112014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (haveGroupDefault && groupDefault) { 112114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags |= MediaGroup::FLAG_DEFAULT; 112214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 112314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (haveGroupForced) { 112414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (groupType != MediaGroup::TYPE_SUBS) { 112514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("The FORCED attribute MUST not be present on anything " 112614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "but SUBS media."); 112714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 112814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 112914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 113014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 113114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (groupForced) { 113214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags |= MediaGroup::FLAG_FORCED; 113314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 113414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 113514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (haveGroupLanguage) { 113614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags |= MediaGroup::FLAG_HAS_LANGUAGE; 113714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 113814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (haveGroupURI) { 113914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags |= MediaGroup::FLAG_HAS_URI; 114014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 114114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 114214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ssize_t groupIndex = mMediaGroups.indexOfKey(groupID); 114314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber sp<MediaGroup> group; 114414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 114514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (groupIndex < 0) { 114614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber group = new MediaGroup(groupType); 114714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber mMediaGroups.add(groupID, group); 114814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } else { 114914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber group = mMediaGroups.valueAt(groupIndex); 115014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 115114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber if (group->type() != groupType) { 115214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber ALOGE("Attempt to put media item under group of different type " 115314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber "(groupType = %d, item type = %d", 115414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber group->type(), 115514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupType); 115614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 115714f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return ERROR_MALFORMED; 115814f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 115914f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber } 116014f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 116114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber return group->addMedia( 116214f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber groupName.c_str(), 116314f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupURI ? groupURI.c_str() : NULL, 116414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber haveGroupLanguage ? groupLanguage.c_str() : NULL, 116514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber flags); 116614f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber} 1167309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 1168309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih// static 1169309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shihstatus_t M3UParser::parseDiscontinuitySequence(const AString &line, size_t *seq) { 1170309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih ssize_t colonPos = line.find(":"); 1171309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 1172309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih if (colonPos < 0) { 1173309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih return ERROR_MALFORMED; 1174309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } 1175309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 1176309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih int32_t x; 1177309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih status_t err = ParseInt32(line.c_str() + colonPos + 1, &x); 1178309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih if (err != OK) { 1179309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih return err; 1180309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } 1181309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 1182309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih if (x < 0) { 1183309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih return ERROR_MALFORMED; 1184309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } 1185309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih 1186309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih if (seq) { 1187309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih *seq = x; 1188309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih } 1189309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih return OK; 1190309aa8bf5e4cd66fe988adf2654cac3fadc2a1c3Robert Shih} 119114f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 11922aa4cc04154d82f6658fb86f394f13bb488b0468Andreas Huber// static 1193e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::ParseInt32(const char *s, int32_t *x) { 1194e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber char *end; 1195e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber long lval = strtol(s, &end, 10); 1196e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 1197e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber if (end == s || (*end != '\0' && *end != ',')) { 1198e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return ERROR_MALFORMED; 1199e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber } 1200e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 1201e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber *x = (int32_t)lval; 1202e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 1203e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber return OK; 1204e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} 1205e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber 12069067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber// static 12079067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huberstatus_t M3UParser::ParseDouble(const char *s, double *x) { 12089067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber char *end; 12099067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber double dval = strtod(s, &end); 12109067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 12119067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber if (end == s || (*end != '\0' && *end != ',')) { 12129067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber return ERROR_MALFORMED; 12139067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber } 12149067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 12159067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber *x = dval; 12169067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 12179067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber return OK; 12189067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber} 12199067e30b3ccb3a07e41b61af22c036378053a9a3Andreas Huber 1220ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static 1221ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::isQuotedString(const AString &str) { 1222ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (str.size() < 2 1223ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih || str.c_str()[0] != '"' 1224ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih || str.c_str()[str.size() - 1] != '"') { 1225ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return false; 1226ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 1227ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return true; 1228ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih} 1229ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 1230ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static 1231ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert ShihAString M3UParser::unquoteString(const AString &str) { 1232ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (!isQuotedString(str)) { 1233ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return str; 1234ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 1235ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return AString(str, 1, str.size() - 2); 1236ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih} 1237ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 1238ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih// static 1239ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shihbool M3UParser::codecIsType(const AString &codec, const char *type) { 1240ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih if (codec.size() < 4) { 1241ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return false; 1242ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 1243ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih const char *c = codec.c_str(); 1244ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih switch (FOURCC(c[0], c[1], c[2], c[3])) { 1245ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih // List extracted from http://www.mp4ra.org/codecs.html 1246ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'ac-3': 1247ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'alac': 1248ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dra1': 1249ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dtsc': 1250ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dtse': 1251ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dtsh': 1252ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dtsl': 1253ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'ec-3': 1254ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'enca': 1255ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'g719': 1256ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'g726': 1257ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'm4ae': 1258ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mlpa': 1259ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mp4a': 1260ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'raw ': 1261ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'samr': 1262ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'sawb': 1263ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'sawp': 1264ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'sevc': 1265ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'sqcp': 1266ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'ssmv': 1267ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'twos': 1268ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'agsm': 1269ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'alaw': 1270ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dvi ': 1271ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'fl32': 1272ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'fl64': 1273ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'ima4': 1274ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'in24': 1275ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'in32': 1276ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'lpcm': 1277ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Qclp': 1278ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'QDM2': 1279ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'QDMC': 1280ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'ulaw': 1281ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'vdva': 1282ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return !strcmp("audio", type); 1283ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 1284ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'avc1': 1285ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'avc2': 1286ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'avcp': 1287ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'drac': 1288ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'encv': 1289ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mjp2': 1290ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mp4v': 1291ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mvc1': 1292ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mvc2': 1293ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'resv': 1294ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 's263': 1295ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'svc1': 1296ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'vc-1': 1297ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'CFHD': 1298ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'civd': 1299ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'DV10': 1300ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dvh5': 1301ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dvh6': 1302ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'dvhp': 1303ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'DVOO': 1304ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'DVOR': 1305ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'DVTV': 1306ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'DVVT': 1307ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'flic': 1308ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'gif ': 1309ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'h261': 1310ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'h263': 1311ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'HD10': 1312ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'jpeg': 1313ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'M105': 1314ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mjpa': 1315ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'mjpb': 1316ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'png ': 1317ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'PNTG': 1318ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'rle ': 1319ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'rpza': 1320ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Shr0': 1321ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Shr1': 1322ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Shr2': 1323ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Shr3': 1324ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'Shr4': 1325ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'SVQ1': 1326ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'SVQ3': 1327ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'tga ': 1328ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'tiff': 1329ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih case 'WRLE': 1330ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return !strcmp("video", type); 1331ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 1332ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih default: 1333ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih return false; 1334ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih } 1335ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih} 1336ef8adf8ce4ece039a839f42a22b436d8ae077f37Robert Shih 1337e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber} // namespace android 1338