OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / media / libstagefright / rtsp / ASessionDescription.cpp
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ASessionDescription"
19 #include <utils/Log.h>
20
21 #include "ASessionDescription.h"
22
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/AString.h>
25
26 #include <stdlib.h>
27
28 namespace android {
29
30 ASessionDescription::ASessionDescription()
31     : mIsValid(false) {
32 }
33
34 ASessionDescription::~ASessionDescription() {
35 }
36
37 bool ASessionDescription::setTo(const void *data, size_t size) {
38     mIsValid = parse(data, size);
39
40     if (!mIsValid) {
41         mTracks.clear();
42         mFormats.clear();
43     }
44
45     return mIsValid;
46 }
47
48 bool ASessionDescription::parse(const void *data, size_t size) {
49     mTracks.clear();
50     mFormats.clear();
51
52     mTracks.push(Attribs());
53     mFormats.push(AString("[root]"));
54
55     AString desc((const char *)data, size);
56
57     size_t i = 0;
58     for (;;) {
59         ssize_t eolPos = desc.find("\n", i);
60
61         if (eolPos < 0) {
62             break;
63         }
64
65         AString line;
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);
70         } else {
71             line.setTo(desc, i, eolPos - i);
72         }
73
74         if (line.size() < 2 || line.c_str()[1] != '=') {
75             return false;
76         }
77
78         LOGI("%s", line.c_str());
79
80         switch (line.c_str()[0]) {
81             case 'v':
82             {
83                 if (strcmp(line.c_str(), "v=0")) {
84                     return false;
85                 }
86                 break;
87             }
88
89             case 'a':
90             case 'b':
91             {
92                 AString key, value;
93
94                 ssize_t colonPos = line.find(":", 2);
95                 if (colonPos < 0) {
96                     key = line;
97                 } else {
98                     key.setTo(line, 0, colonPos);
99
100                     if (key == "a=fmtp" || key == "a=rtpmap"
101                             || key == "a=framesize") {
102                         ssize_t spacePos = line.find(" ", colonPos + 1);
103                         if (spacePos < 0) {
104                             return false;
105                         }
106
107                         key.setTo(line, 0, spacePos);
108
109                         colonPos = spacePos;
110                     }
111
112                     value.setTo(line, colonPos + 1, line.size() - colonPos - 1);
113                 }
114
115                 key.trim();
116                 value.trim();
117
118                 LOGV("adding '%s' => '%s'", key.c_str(), value.c_str());
119
120                 mTracks.editItemAt(mTracks.size() - 1).add(key, value);
121                 break;
122             }
123
124             case 'm':
125             {
126                 LOGV("new section '%s'",
127                      AString(line, 2, line.size() - 2).c_str());
128
129                 mTracks.push(Attribs());
130                 mFormats.push(AString(line, 2, line.size() - 2));
131                 break;
132             }
133
134             default:
135             {
136                 AString key, value;
137
138                 ssize_t equalPos = line.find("=");
139
140                 key = AString(line, 0, equalPos + 1);
141                 value = AString(line, equalPos + 1, line.size() - equalPos - 1);
142
143                 key.trim();
144                 value.trim();
145
146                 LOGV("adding '%s' => '%s'", key.c_str(), value.c_str());
147
148                 mTracks.editItemAt(mTracks.size() - 1).add(key, value);
149                 break;
150             }
151         }
152
153         i = eolPos + 1;
154     }
155
156     return true;
157 }
158
159 bool ASessionDescription::isValid() const {
160     return mIsValid;
161 }
162
163 size_t ASessionDescription::countTracks() const {
164     return mTracks.size();
165 }
166
167 void ASessionDescription::getFormat(size_t index, AString *value) const {
168     CHECK_GE(index, 0u);
169     CHECK_LT(index, mTracks.size());
170
171     *value = mFormats.itemAt(index);
172 }
173
174 bool ASessionDescription::findAttribute(
175         size_t index, const char *key, AString *value) const {
176     CHECK_GE(index, 0u);
177     CHECK_LT(index, mTracks.size());
178
179     value->clear();
180
181     const Attribs &track = mTracks.itemAt(index);
182     ssize_t i = track.indexOfKey(AString(key));
183
184     if (i < 0) {
185         return false;
186     }
187
188     *value = track.valueAt(i);
189
190     return true;
191 }
192
193 void ASessionDescription::getFormatType(
194         size_t index, unsigned long *PT,
195         AString *desc, AString *params) const {
196     AString format;
197     getFormat(index, &format);
198
199     char *lastSpacePos = strrchr(format.c_str(), ' ');
200     CHECK(lastSpacePos != NULL);
201
202     char *end;
203     unsigned long x = strtoul(lastSpacePos + 1, &end, 10);
204     CHECK_GT(end, lastSpacePos + 1);
205     CHECK_EQ(*end, '\0');
206
207     *PT = x;
208
209     char key[20];
210     sprintf(key, "a=rtpmap:%lu", x);
211
212     CHECK(findAttribute(index, key, desc));
213
214     sprintf(key, "a=fmtp:%lu", x);
215     if (!findAttribute(index, key, params)) {
216         params->clear();
217     }
218 }
219
220 bool ASessionDescription::getDimensions(
221         size_t index, unsigned long PT,
222         int32_t *width, int32_t *height) const {
223     *width = 0;
224     *height = 0;
225
226     char key[20];
227     sprintf(key, "a=framesize:%lu", PT);
228     AString value;
229     if (!findAttribute(index, key, &value)) {
230         return false;
231     }
232
233     const char *s = value.c_str();
234     char *end;
235     *width = strtoul(s, &end, 10);
236     CHECK_GT(end, s);
237     CHECK_EQ(*end, '-');
238
239     s = end + 1;
240     *height = strtoul(s, &end, 10);
241     CHECK_GT(end, s);
242     CHECK_EQ(*end, '\0');
243
244     return true;
245 }
246
247 bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
248     *durationUs = 0;
249
250     CHECK(mIsValid);
251
252     AString value;
253     if (!findAttribute(0, "a=range", &value)) {
254         return false;
255     }
256
257     if (strncmp(value.c_str(), "npt=", 4)) {
258         return false;
259     }
260
261     float from, to;
262     if (!parseNTPRange(value.c_str() + 4, &from, &to)) {
263         return false;
264     }
265
266     *durationUs = (int64_t)((to - from) * 1E6);
267
268     return true;
269 }
270
271 // static
272 void ASessionDescription::ParseFormatDesc(
273         const char *desc, int32_t *timescale, int32_t *numChannels) {
274     const char *slash1 = strchr(desc, '/');
275     CHECK(slash1 != NULL);
276
277     const char *s = slash1 + 1;
278     char *end;
279     unsigned long x = strtoul(s, &end, 10);
280     CHECK_GT(end, s);
281     CHECK(*end == '\0' || *end == '/');
282
283     *timescale = x;
284     *numChannels = 1;
285
286     if (*end == '/') {
287         s = end + 1;
288         unsigned long x = strtoul(s, &end, 10);
289         CHECK_GT(end, s);
290         CHECK_EQ(*end, '\0');
291
292         *numChannels = x;
293     }
294 }
295
296 // static
297 bool ASessionDescription::parseNTPRange(
298         const char *s, float *npt1, float *npt2) {
299     if (s[0] == '-') {
300         return false;  // no start time available.
301     }
302
303     if (!strncmp("now", s, 3)) {
304         return false;  // no absolute start time available
305     }
306
307     char *end;
308     *npt1 = strtof(s, &end);
309
310     if (end == s || *end != '-') {
311         // Failed to parse float or trailing "dash".
312         return false;
313     }
314
315     s = end + 1;  // skip the dash.
316
317     if (!strncmp("now", s, 3)) {
318         return false;  // no absolute end time available
319     }
320
321     *npt2 = strtof(s, &end);
322
323     if (end == s || *end != '\0') {
324         return false;
325     }
326
327     return *npt2 > *npt1;
328 }
329
330 }  // namespace android
331