ASessionDescription.cpp revision cf7b9c7aae758ac0b99833915053c63c2ac46e09
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#include "ASessionDescription.h" 18 19#include <media/stagefright/foundation/ADebug.h> 20#include <media/stagefright/foundation/AString.h> 21 22#include <stdlib.h> 23 24namespace android { 25 26ASessionDescription::ASessionDescription() 27 : mIsValid(false) { 28} 29 30ASessionDescription::~ASessionDescription() { 31} 32 33bool ASessionDescription::setTo(const void *data, size_t size) { 34 mIsValid = parse(data, size); 35 36 if (!mIsValid) { 37 mTracks.clear(); 38 mFormats.clear(); 39 } 40 41 return mIsValid; 42} 43 44bool ASessionDescription::parse(const void *data, size_t size) { 45 mTracks.clear(); 46 mFormats.clear(); 47 48 mTracks.push(Attribs()); 49 mFormats.push(AString("[root]")); 50 51 AString desc((const char *)data, size); 52 LOG(VERBOSE) << desc; 53 54 size_t i = 0; 55 for (;;) { 56 ssize_t eolPos = desc.find("\r\n", i); 57 if (eolPos < 0) { 58 break; 59 } 60 61 AString line(desc, i, eolPos - i); 62 63 if (line.size() < 2 || line.c_str()[1] != '=') { 64 return false; 65 } 66 67 switch (line.c_str()[0]) { 68 case 'v': 69 { 70 if (strcmp(line.c_str(), "v=0")) { 71 return false; 72 } 73 break; 74 } 75 76 case 'a': 77 case 'b': 78 { 79 AString key, value; 80 81 ssize_t colonPos = line.find(":", 2); 82 if (colonPos < 0) { 83 key = line; 84 } else { 85 key.setTo(line, 0, colonPos); 86 87 if (key == "a=fmtp" || key == "a=rtpmap" 88 || key == "a=framesize") { 89 ssize_t spacePos = line.find(" ", colonPos + 1); 90 if (spacePos < 0) { 91 return false; 92 } 93 94 key.setTo(line, 0, spacePos); 95 96 colonPos = spacePos; 97 } 98 99 value.setTo(line, colonPos + 1, line.size() - colonPos - 1); 100 } 101 102 key.trim(); 103 value.trim(); 104 105 LOG(VERBOSE) << "adding '" << key << "' => '" << value << "'"; 106 107 mTracks.editItemAt(mTracks.size() - 1).add(key, value); 108 break; 109 } 110 111 case 'm': 112 { 113 LOG(VERBOSE) << "new section '" << AString(line, 2, line.size() - 2) << "'"; 114 115 mTracks.push(Attribs()); 116 mFormats.push(AString(line, 2, line.size() - 2)); 117 break; 118 } 119 } 120 121 i = eolPos + 2; 122 } 123 124 return true; 125} 126 127bool ASessionDescription::isValid() const { 128 return mIsValid; 129} 130 131size_t ASessionDescription::countTracks() const { 132 return mTracks.size(); 133} 134 135void ASessionDescription::getFormat(size_t index, AString *value) const { 136 CHECK_GE(index, 0u); 137 CHECK_LT(index, mTracks.size()); 138 139 *value = mFormats.itemAt(index); 140} 141 142bool ASessionDescription::findAttribute( 143 size_t index, const char *key, AString *value) const { 144 CHECK_GE(index, 0u); 145 CHECK_LT(index, mTracks.size()); 146 147 value->clear(); 148 149 const Attribs &track = mTracks.itemAt(index); 150 ssize_t i = track.indexOfKey(AString(key)); 151 152 if (i < 0) { 153 return false; 154 } 155 156 *value = track.valueAt(i); 157 158 return true; 159} 160 161void ASessionDescription::getFormatType( 162 size_t index, unsigned long *PT, 163 AString *desc, AString *params) const { 164 AString format; 165 getFormat(index, &format); 166 167 char *lastSpacePos = strrchr(format.c_str(), ' '); 168 CHECK(lastSpacePos != NULL); 169 170 char *end; 171 unsigned long x = strtoul(lastSpacePos + 1, &end, 10); 172 CHECK_GT(end, lastSpacePos + 1); 173 CHECK_EQ(*end, '\0'); 174 175 *PT = x; 176 177 char key[20]; 178 sprintf(key, "a=rtpmap:%lu", x); 179 180 CHECK(findAttribute(index, key, desc)); 181 182 sprintf(key, "a=fmtp:%lu", x); 183 if (!findAttribute(index, key, params)) { 184 params->clear(); 185 } 186} 187 188void ASessionDescription::getDimensions( 189 size_t index, unsigned long PT, 190 int32_t *width, int32_t *height) const { 191 char key[20]; 192 sprintf(key, "a=framesize:%lu", PT); 193 AString value; 194 CHECK(findAttribute(index, key, &value)); 195 196 const char *s = value.c_str(); 197 char *end; 198 *width = strtoul(s, &end, 10); 199 CHECK_GT(end, s); 200 CHECK_EQ(*end, '-'); 201 202 s = end + 1; 203 *height = strtoul(s, &end, 10); 204 CHECK_GT(end, s); 205 CHECK_EQ(*end, '\0'); 206} 207 208bool ASessionDescription::getDurationUs(int64_t *durationUs) const { 209 *durationUs = 0; 210 211 CHECK(mIsValid); 212 213 AString value; 214 if (!findAttribute(0, "a=range", &value)) { 215 return false; 216 } 217 218 if (value == "npt=now-") { 219 return false; 220 } 221 222 if (strncmp(value.c_str(), "npt=", 4)) { 223 return false; 224 } 225 226 const char *s = value.c_str() + 4; 227 char *end; 228 double from = strtod(s, &end); 229 CHECK_GT(end, s); 230 CHECK_EQ(*end, '-'); 231 232 s = end + 1; 233 double to = strtod(s, &end); 234 CHECK_GT(end, s); 235 CHECK_EQ(*end, '\0'); 236 237 CHECK_GE(to, from); 238 239 *durationUs = (int64_t)((to - from) * 1E6); 240 241 return true; 242} 243 244// static 245void ASessionDescription::ParseFormatDesc( 246 const char *desc, int32_t *timescale, int32_t *numChannels) { 247 const char *slash1 = strchr(desc, '/'); 248 CHECK(slash1 != NULL); 249 250 const char *s = slash1 + 1; 251 char *end; 252 unsigned long x = strtoul(s, &end, 10); 253 CHECK_GT(end, s); 254 CHECK(*end == '\0' || *end == '/'); 255 256 *timescale = x; 257 *numChannels = 1; 258 259 if (*end == '/') { 260 s = end + 1; 261 unsigned long x = strtoul(s, &end, 10); 262 CHECK_GT(end, s); 263 CHECK_EQ(*end, '\0'); 264 265 *numChannels = x; 266 } 267} 268 269} // namespace android 270 271