2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ASessionDescription"
19 #include <utils/Log.h>
21 #include "ASessionDescription.h"
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/AString.h>
30 ASessionDescription::ASessionDescription()
34 ASessionDescription::~ASessionDescription() {
37 bool ASessionDescription::setTo(const void *data, size_t size) {
38 mIsValid = parse(data, size);
48 bool ASessionDescription::parse(const void *data, size_t size) {
52 mTracks.push(Attribs());
53 mFormats.push(AString("[root]"));
55 AString desc((const char *)data, size);
59 ssize_t eolPos = desc.find("\n", i);
66 if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') {
67 // We accept both '\n' and '\r\n' line endings, if it's
68 // the latter, strip the '\r' as well.
69 line.setTo(desc, i, eolPos - i - 1);
71 line.setTo(desc, i, eolPos - i);
74 if (line.size() < 2 || line.c_str()[1] != '=') {
78 LOGI("%s", line.c_str());
80 switch (line.c_str()[0]) {
83 if (strcmp(line.c_str(), "v=0")) {
94 ssize_t colonPos = line.find(":", 2);
98 key.setTo(line, 0, colonPos);
100 if (key == "a=fmtp" || key == "a=rtpmap"
101 || key == "a=framesize") {
102 ssize_t spacePos = line.find(" ", colonPos + 1);
107 key.setTo(line, 0, spacePos);
112 value.setTo(line, colonPos + 1, line.size() - colonPos - 1);
118 LOGV("adding '%s' => '%s'", key.c_str(), value.c_str());
120 mTracks.editItemAt(mTracks.size() - 1).add(key, value);
126 LOGV("new section '%s'",
127 AString(line, 2, line.size() - 2).c_str());
129 mTracks.push(Attribs());
130 mFormats.push(AString(line, 2, line.size() - 2));
138 ssize_t equalPos = line.find("=");
140 key = AString(line, 0, equalPos + 1);
141 value = AString(line, equalPos + 1, line.size() - equalPos - 1);
146 LOGV("adding '%s' => '%s'", key.c_str(), value.c_str());
148 mTracks.editItemAt(mTracks.size() - 1).add(key, value);
159 bool ASessionDescription::isValid() const {
163 size_t ASessionDescription::countTracks() const {
164 return mTracks.size();
167 void ASessionDescription::getFormat(size_t index, AString *value) const {
169 CHECK_LT(index, mTracks.size());
171 *value = mFormats.itemAt(index);
174 bool ASessionDescription::findAttribute(
175 size_t index, const char *key, AString *value) const {
177 CHECK_LT(index, mTracks.size());
181 const Attribs &track = mTracks.itemAt(index);
182 ssize_t i = track.indexOfKey(AString(key));
188 *value = track.valueAt(i);
193 void ASessionDescription::getFormatType(
194 size_t index, unsigned long *PT,
195 AString *desc, AString *params) const {
197 getFormat(index, &format);
199 char *lastSpacePos = strrchr(format.c_str(), ' ');
200 CHECK(lastSpacePos != NULL);
203 unsigned long x = strtoul(lastSpacePos + 1, &end, 10);
204 CHECK_GT(end, lastSpacePos + 1);
205 CHECK_EQ(*end, '\0');
210 sprintf(key, "a=rtpmap:%lu", x);
212 CHECK(findAttribute(index, key, desc));
214 sprintf(key, "a=fmtp:%lu", x);
215 if (!findAttribute(index, key, params)) {
220 bool ASessionDescription::getDimensions(
221 size_t index, unsigned long PT,
222 int32_t *width, int32_t *height) const {
227 sprintf(key, "a=framesize:%lu", PT);
229 if (!findAttribute(index, key, &value)) {
233 const char *s = value.c_str();
235 *width = strtoul(s, &end, 10);
240 *height = strtoul(s, &end, 10);
242 CHECK_EQ(*end, '\0');
247 bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
253 if (!findAttribute(0, "a=range", &value)) {
257 if (strncmp(value.c_str(), "npt=", 4)) {
262 if (!parseNTPRange(value.c_str() + 4, &from, &to)) {
266 *durationUs = (int64_t)((to - from) * 1E6);
272 void ASessionDescription::ParseFormatDesc(
273 const char *desc, int32_t *timescale, int32_t *numChannels) {
274 const char *slash1 = strchr(desc, '/');
275 CHECK(slash1 != NULL);
277 const char *s = slash1 + 1;
279 unsigned long x = strtoul(s, &end, 10);
281 CHECK(*end == '\0' || *end == '/');
288 unsigned long x = strtoul(s, &end, 10);
290 CHECK_EQ(*end, '\0');
297 bool ASessionDescription::parseNTPRange(
298 const char *s, float *npt1, float *npt2) {
300 return false; // no start time available.
303 if (!strncmp("now", s, 3)) {
304 return false; // no absolute start time available
308 *npt1 = strtof(s, &end);
310 if (end == s || *end != '-') {
311 // Failed to parse float or trailing "dash".
315 s = end + 1; // skip the dash.
317 if (!strncmp("now", s, 3)) {
318 return false; // no absolute end time available
321 *npt2 = strtof(s, &end);
323 if (end == s || *end != '\0') {
327 return *npt2 > *npt1;
330 } // namespace android