M3UParser.cpp revision e332a9181cf6a3155ed1a0fd2afc212ccb1f2753
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
17e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include "include/M3UParser.h"
18e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
19e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/foundation/AMessage.h>
20e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/MediaDebug.h>
21e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber#include <media/stagefright/MediaErrors.h>
22e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
23e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubernamespace android {
24e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
25e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::M3UParser(
26e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const char *baseURI, const void *data, size_t size)
27e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    : mInitCheck(NO_INIT),
28e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mBaseURI(baseURI),
29e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber      mIsExtM3U(false),
30bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber      mIsVariantPlaylist(false),
31bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber      mIsComplete(false) {
32e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    mInitCheck = parse(data, size);
33e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
34e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
35e71d10e7ad55ccbcb0756c007caef1c959090384Andreas HuberM3UParser::~M3UParser() {
36e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
37e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
38e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::initCheck() const {
39e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mInitCheck;
40e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
41e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
42e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isExtM3U() const {
43e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsExtM3U;
44e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
45e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
46e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::isVariantPlaylist() const {
47e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mIsVariantPlaylist;
48e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
49e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
50bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huberbool M3UParser::isComplete() const {
51bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber    return mIsComplete;
52bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber}
53bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber
54e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersp<AMessage> M3UParser::meta() {
55e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mMeta;
56e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
57e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
58e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Hubersize_t M3UParser::size() {
59e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return mItems.size();
60e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
61e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
62e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberbool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) {
63e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    uri->clear();
64e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta) { *meta = NULL; }
65e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
66e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (index >= mItems.size()) {
67e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
68e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
69e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
70e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    *uri = mItems.itemAt(index).mURI;
71e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
72e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta) {
73e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = mItems.itemAt(index).mMeta;
74e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
75e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
76e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
77e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
78e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
79e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatic bool MakeURL(const char *baseURL, const char *url, AString *out) {
80e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    out->clear();
81e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
822a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (strncasecmp("http://", baseURL, 7)
832a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            && strncasecmp("file://", baseURL, 7)) {
84e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // Base URL must be absolute
85e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return false;
86e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
87e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
88e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (!strncasecmp("http://", url, 7)) {
89e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        // "url" is already an absolute URL, ignore base URL.
90e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->setTo(url);
91e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return true;
92e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
93e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
94e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    size_t n = strlen(baseURL);
95e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (baseURL[n - 1] == '/') {
96e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->setTo(baseURL);
97e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->append(url);
98e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    } else {
994e2ffa400b82559cab2c5717c8dcdff393d334a9Mike Lockwood        const char *slashPos = strrchr(baseURL, '/');
100e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
101e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (slashPos > &baseURL[6]) {
102e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            out->setTo(baseURL, slashPos - baseURL);
103e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
104e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            out->setTo(baseURL);
105e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
106e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
107e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->append("/");
108e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        out->append(url);
109e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
110e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
111e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return true;
112e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
113e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
114e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parse(const void *_data, size_t size) {
115e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t lineNo = 0;
116e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
117e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    sp<AMessage> itemMeta;
118e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
119e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    const char *data = (const char *)_data;
120e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    size_t offset = 0;
121e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    while (offset < size) {
122e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        size_t offsetLF = offset;
123e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        while (offsetLF < size && data[offsetLF] != '\n') {
124e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            ++offsetLF;
125e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
126e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (offsetLF >= size) {
127e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            break;
128e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
129e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
130e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        AString line;
131e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (offsetLF > offset && data[offsetLF - 1] == '\r') {
132e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset - 1);
133e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        } else {
134e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            line.setTo(&data[offset], offsetLF - offset);
135e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
136e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
1372a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        // LOGI("#%s#", line.c_str());
1382a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
1392a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (line.empty()) {
1402a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            offset = offsetLF + 1;
1412a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
1422a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
143e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
144e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (lineNo == 0 && line == "#EXTM3U") {
145e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mIsExtM3U = true;
146e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
147e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
148e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (mIsExtM3U) {
149e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            status_t err = OK;
150e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
151e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (line.startsWith("#EXT-X-TARGETDURATION")) {
152e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
153e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
154e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
155e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "target-duration");
156e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) {
157e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
158e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
159e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
160e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &mMeta, "media-sequence");
161e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            } else if (line.startsWith("#EXT-X-KEY")) {
162e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                if (mIsVariantPlaylist) {
163e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                    return ERROR_MALFORMED;
164e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                }
165e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                err = parseCipherInfo(line, &itemMeta);
166bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber            } else if (line.startsWith("#EXT-X-ENDLIST")) {
167bff07d0b22a5ee2d9f044f6cb5e4be1532017ab0Andreas Huber                mIsComplete = true;
168e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXTINF")) {
169e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mIsVariantPlaylist) {
170e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
171e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
172e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                err = parseMetaData(line, &itemMeta, "duration");
1732a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
1742a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (mIsVariantPlaylist) {
1752a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    return ERROR_MALFORMED;
1762a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
1772a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                if (itemMeta == NULL) {
1782a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                    itemMeta = new AMessage;
1792a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                }
1802a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                itemMeta->setInt32("discontinuity", true);
181e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            } else if (line.startsWith("#EXT-X-STREAM-INF")) {
182e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (mMeta != NULL) {
183e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
184e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
185e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                mIsVariantPlaylist = true;
1862a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                err = parseStreamInf(line, &itemMeta);
187e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
188e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
189e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (err != OK) {
190e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                return err;
191e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
192e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
193e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
194e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        if (!line.startsWith("#")) {
195e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            if (!mIsVariantPlaylist) {
196e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                int32_t durationSecs;
197e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                if (itemMeta == NULL
198e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                        || !itemMeta->findInt32("duration", &durationSecs)) {
199e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                    return ERROR_MALFORMED;
200e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber                }
201e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            }
202e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
203e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            mItems.push();
204e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            Item *item = &mItems.editItemAt(mItems.size() - 1);
205e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
206e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI));
207e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
208e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            item->mMeta = itemMeta;
209e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
210e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber            itemMeta.clear();
211e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        }
212e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
213e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        offset = offsetLF + 1;
214e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        ++lineNo;
215e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
216e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
217e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
218e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
219e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
220e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
221e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::parseMetaData(
222e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        const AString &line, sp<AMessage> *meta, const char *key) {
223e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    ssize_t colonPos = line.find(":");
224e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
225e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (colonPos < 0) {
226e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
227e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
228e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
229e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    int32_t x;
230e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    status_t err = ParseInt32(line.c_str() + colonPos + 1, &x);
231e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
232e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (err != OK) {
233e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return err;
234e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
235e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
236e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (meta->get() == NULL) {
237e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        *meta = new AMessage;
238e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
239e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    (*meta)->setInt32(key, x);
240e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
241e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
242e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
243e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
244e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber// static
2452a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huberstatus_t M3UParser::parseStreamInf(
2462a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        const AString &line, sp<AMessage> *meta) {
2472a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    ssize_t colonPos = line.find(":");
2482a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2492a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    if (colonPos < 0) {
2502a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        return ERROR_MALFORMED;
2512a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
2522a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2532a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    size_t offset = colonPos + 1;
2542a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2552a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    while (offset < line.size()) {
2562a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t end = line.find(",", offset);
2572a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (end < 0) {
2582a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            end = line.size();
2592a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
2602a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2612a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString attr(line, offset, end - offset);
2622a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        attr.trim();
2632a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2642a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        offset = end + 1;
2652a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2662a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        ssize_t equalPos = attr.find("=");
2672a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (equalPos < 0) {
2682a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            continue;
2692a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
2702a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2712a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString key(attr, 0, equalPos);
2722a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        key.trim();
2732a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2742a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
2752a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        val.trim();
2762a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2772a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        LOGV("key=%s value=%s", key.c_str(), val.c_str());
2782a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2792a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        if (!strcasecmp("bandwidth", key.c_str())) {
2802a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            const char *s = val.c_str();
2812a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            char *end;
2822a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            unsigned long x = strtoul(s, &end, 10);
2832a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2842a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (end == s || *end != '\0') {
2852a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                // malformed
2862a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                continue;
2872a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
2882a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2892a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            if (meta->get() == NULL) {
2902a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber                *meta = new AMessage;
2912a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            }
2922a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber            (*meta)->setInt32("bandwidth", x);
2932a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber        }
2942a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    }
2952a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2962a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber    return OK;
2972a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber}
2982a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber
2992a4d22d79e927f2245537921e10fc5fda1c47a29Andreas Huber// static
300e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huberstatus_t M3UParser::parseCipherInfo(
301e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        const AString &line, sp<AMessage> *meta) {
302e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    ssize_t colonPos = line.find(":");
303e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
304e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    if (colonPos < 0) {
305e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        return ERROR_MALFORMED;
306e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
307e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
308e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    size_t offset = colonPos + 1;
309e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
310e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    while (offset < line.size()) {
311e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        ssize_t end = line.find(",", offset);
312e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (end < 0) {
313e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            end = line.size();
314e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
315e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
316e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString attr(line, offset, end - offset);
317e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        attr.trim();
318e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
319e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        offset = end + 1;
320e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
321e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        ssize_t equalPos = attr.find("=");
322e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (equalPos < 0) {
323e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            continue;
324e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
325e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
326e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString key(attr, 0, equalPos);
327e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.trim();
328e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
329e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        AString val(attr, equalPos + 1, attr.size() - equalPos - 1);
330e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        val.trim();
331e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
332e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        LOGV("key=%s value=%s", key.c_str(), val.c_str());
333e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
334e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        key.tolower();
335e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
336e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        if (key == "method" || key == "uri" || key == "iv") {
337e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            if (meta->get() == NULL) {
338e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber                *meta = new AMessage;
339e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            }
340e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
341e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            key.insert(AString("cipher-"), 0);
342e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
343e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber            (*meta)->setString(key.c_str(), val.c_str(), val.size());
344e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber        }
345e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    }
346e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
347e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber    return OK;
348e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber}
349e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber
350e332a9181cf6a3155ed1a0fd2afc212ccb1f2753Andreas Huber// static
351e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huberstatus_t M3UParser::ParseInt32(const char *s, int32_t *x) {
352e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    char *end;
353e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    long lval = strtol(s, &end, 10);
354e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
355e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    if (end == s || (*end != '\0' && *end != ',')) {
356e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber        return ERROR_MALFORMED;
357e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    }
358e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
359e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    *x = (int32_t)lval;
360e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
361e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber    return OK;
362e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}
363e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber
364e71d10e7ad55ccbcb0756c007caef1c959090384Andreas Huber}  // namespace android
365