APacketSource.cpp revision 85f12e9b9062402d6110df3f7099707912040edb
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 "APacketSource.h" 18 19#include "ASessionDescription.h" 20 21#include "avc_utils.h" 22 23#include <ctype.h> 24 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/foundation/AString.h> 29#include <media/stagefright/foundation/base64.h> 30#include <media/stagefright/foundation/hexdump.h> 31#include <media/stagefright/MediaBuffer.h> 32#include <media/stagefright/MediaDefs.h> 33#include <media/stagefright/MetaData.h> 34#include <utils/Vector.h> 35 36namespace android { 37 38static bool GetAttribute(const char *s, const char *key, AString *value) { 39 value->clear(); 40 41 size_t keyLen = strlen(key); 42 43 for (;;) { 44 while (isspace(*s)) { 45 ++s; 46 } 47 48 const char *colonPos = strchr(s, ';'); 49 50 size_t len = 51 (colonPos == NULL) ? strlen(s) : colonPos - s; 52 53 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 54 value->setTo(&s[keyLen + 1], len - keyLen - 1); 55 return true; 56 } 57 58 if (colonPos == NULL) { 59 return false; 60 } 61 62 s = colonPos + 1; 63 } 64} 65 66static sp<ABuffer> decodeHex(const AString &s) { 67 if ((s.size() % 2) != 0) { 68 return NULL; 69 } 70 71 size_t outLen = s.size() / 2; 72 sp<ABuffer> buffer = new ABuffer(outLen); 73 uint8_t *out = buffer->data(); 74 75 uint8_t accum = 0; 76 for (size_t i = 0; i < s.size(); ++i) { 77 char c = s.c_str()[i]; 78 unsigned value; 79 if (c >= '0' && c <= '9') { 80 value = c - '0'; 81 } else if (c >= 'a' && c <= 'f') { 82 value = c - 'a' + 10; 83 } else if (c >= 'A' && c <= 'F') { 84 value = c - 'A' + 10; 85 } else { 86 return NULL; 87 } 88 89 accum = (accum << 4) | value; 90 91 if (i & 1) { 92 *out++ = accum; 93 94 accum = 0; 95 } 96 } 97 98 return buffer; 99} 100 101static sp<ABuffer> MakeAVCCodecSpecificData( 102 const char *params, int32_t *width, int32_t *height) { 103 *width = 0; 104 *height = 0; 105 106 AString val; 107 if (!GetAttribute(params, "profile-level-id", &val)) { 108 return NULL; 109 } 110 111 sp<ABuffer> profileLevelID = decodeHex(val); 112 CHECK(profileLevelID != NULL); 113 CHECK_EQ(profileLevelID->size(), 3u); 114 115 Vector<sp<ABuffer> > paramSets; 116 117 size_t numSeqParameterSets = 0; 118 size_t totalSeqParameterSetSize = 0; 119 size_t numPicParameterSets = 0; 120 size_t totalPicParameterSetSize = 0; 121 122 if (!GetAttribute(params, "sprop-parameter-sets", &val)) { 123 return NULL; 124 } 125 126 size_t start = 0; 127 for (;;) { 128 ssize_t commaPos = val.find(",", start); 129 size_t end = (commaPos < 0) ? val.size() : commaPos; 130 131 AString nalString(val, start, end - start); 132 sp<ABuffer> nal = decodeBase64(nalString); 133 CHECK(nal != NULL); 134 CHECK_GT(nal->size(), 0u); 135 CHECK_LE(nal->size(), 65535u); 136 137 uint8_t nalType = nal->data()[0] & 0x1f; 138 if (numSeqParameterSets == 0) { 139 CHECK_EQ((unsigned)nalType, 7u); 140 } else if (numPicParameterSets > 0) { 141 CHECK_EQ((unsigned)nalType, 8u); 142 } 143 if (nalType == 7) { 144 ++numSeqParameterSets; 145 totalSeqParameterSetSize += nal->size(); 146 } else { 147 CHECK_EQ((unsigned)nalType, 8u); 148 ++numPicParameterSets; 149 totalPicParameterSetSize += nal->size(); 150 } 151 152 paramSets.push(nal); 153 154 if (commaPos < 0) { 155 break; 156 } 157 158 start = commaPos + 1; 159 } 160 161 CHECK_LT(numSeqParameterSets, 32u); 162 CHECK_LE(numPicParameterSets, 255u); 163 164 size_t csdSize = 165 1 + 3 + 1 + 1 166 + 2 * numSeqParameterSets + totalSeqParameterSetSize 167 + 1 + 2 * numPicParameterSets + totalPicParameterSetSize; 168 169 sp<ABuffer> csd = new ABuffer(csdSize); 170 uint8_t *out = csd->data(); 171 172 *out++ = 0x01; // configurationVersion 173 memcpy(out, profileLevelID->data(), 3); 174 out += 3; 175 *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes 176 *out++ = 0xe0 | numSeqParameterSets; 177 178 for (size_t i = 0; i < numSeqParameterSets; ++i) { 179 sp<ABuffer> nal = paramSets.editItemAt(i); 180 181 *out++ = nal->size() >> 8; 182 *out++ = nal->size() & 0xff; 183 184 memcpy(out, nal->data(), nal->size()); 185 186 out += nal->size(); 187 188 if (i == 0) { 189 FindAVCDimensions(nal, width, height); 190 LOG(INFO) << "dimensions " << *width << "x" << *height; 191 } 192 } 193 194 *out++ = numPicParameterSets; 195 196 for (size_t i = 0; i < numPicParameterSets; ++i) { 197 sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets); 198 199 *out++ = nal->size() >> 8; 200 *out++ = nal->size() & 0xff; 201 202 memcpy(out, nal->data(), nal->size()); 203 204 out += nal->size(); 205 } 206 207 // hexdump(csd->data(), csd->size()); 208 209 return csd; 210} 211 212sp<ABuffer> MakeAACCodecSpecificData(const char *params) { 213 AString val; 214 CHECK(GetAttribute(params, "config", &val)); 215 216 sp<ABuffer> config = decodeHex(val); 217 CHECK(config != NULL); 218 CHECK_GE(config->size(), 4u); 219 220 const uint8_t *data = config->data(); 221 uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; 222 x = (x >> 1) & 0xffff; 223 224 static const uint8_t kStaticESDS[] = { 225 0x03, 22, 226 0x00, 0x00, // ES_ID 227 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 228 229 0x04, 17, 230 0x40, // Audio ISO/IEC 14496-3 231 0x00, 0x00, 0x00, 0x00, 232 0x00, 0x00, 0x00, 0x00, 233 0x00, 0x00, 0x00, 0x00, 234 235 0x05, 2, 236 // AudioSpecificInfo follows 237 }; 238 239 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2); 240 memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS)); 241 csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff; 242 csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff; 243 244 // hexdump(csd->data(), csd->size()); 245 246 return csd; 247} 248 249APacketSource::APacketSource( 250 const sp<ASessionDescription> &sessionDesc, size_t index) 251 : mInitCheck(NO_INIT), 252 mFormat(new MetaData), 253 mEOSResult(OK), 254 mFirstAccessUnit(true), 255 mFirstAccessUnitNTP(0) { 256 unsigned long PT; 257 AString desc; 258 AString params; 259 sessionDesc->getFormatType(index, &PT, &desc, ¶ms); 260 261 int64_t durationUs; 262 if (sessionDesc->getDurationUs(&durationUs)) { 263 mFormat->setInt64(kKeyDuration, durationUs); 264 } else { 265 mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll); 266 } 267 268 mInitCheck = OK; 269 if (!strncmp(desc.c_str(), "H264/", 5)) { 270 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 271 272 int32_t width, height; 273 if (!sessionDesc->getDimensions(index, PT, &width, &height)) { 274 width = -1; 275 height = -1; 276 } 277 278 int32_t encWidth, encHeight; 279 sp<ABuffer> codecSpecificData = 280 MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight); 281 282 if (codecSpecificData != NULL) { 283 if (width < 0) { 284 // If no explicit width/height given in the sdp, use the dimensions 285 // extracted from the first sequence parameter set. 286 width = encWidth; 287 height = encHeight; 288 } 289 290 mFormat->setData( 291 kKeyAVCC, 0, 292 codecSpecificData->data(), codecSpecificData->size()); 293 } else if (width < 0) { 294 mInitCheck = ERROR_UNSUPPORTED; 295 return; 296 } 297 298 mFormat->setInt32(kKeyWidth, width); 299 mFormat->setInt32(kKeyHeight, height); 300 } else if (!strncmp(desc.c_str(), "H263-2000/", 10) 301 || !strncmp(desc.c_str(), "H263-1998/", 10)) { 302 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); 303 304 int32_t width, height; 305 if (!sessionDesc->getDimensions(index, PT, &width, &height)) { 306 mInitCheck = ERROR_UNSUPPORTED; 307 return; 308 } 309 310 mFormat->setInt32(kKeyWidth, width); 311 mFormat->setInt32(kKeyHeight, height); 312 } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) { 313 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 314 315 int32_t sampleRate, numChannels; 316 ASessionDescription::ParseFormatDesc( 317 desc.c_str(), &sampleRate, &numChannels); 318 319 mFormat->setInt32(kKeySampleRate, sampleRate); 320 mFormat->setInt32(kKeyChannelCount, numChannels); 321 322 sp<ABuffer> codecSpecificData = 323 MakeAACCodecSpecificData(params.c_str()); 324 325 mFormat->setData( 326 kKeyESDS, 0, 327 codecSpecificData->data(), codecSpecificData->size()); 328 } else if (!strncmp(desc.c_str(), "AMR/", 4)) { 329 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB); 330 331 int32_t sampleRate, numChannels; 332 ASessionDescription::ParseFormatDesc( 333 desc.c_str(), &sampleRate, &numChannels); 334 335 mFormat->setInt32(kKeySampleRate, sampleRate); 336 mFormat->setInt32(kKeyChannelCount, numChannels); 337 338 if (sampleRate != 8000 || numChannels != 1) { 339 mInitCheck = ERROR_UNSUPPORTED; 340 } 341 } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) { 342 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB); 343 344 int32_t sampleRate, numChannels; 345 ASessionDescription::ParseFormatDesc( 346 desc.c_str(), &sampleRate, &numChannels); 347 348 mFormat->setInt32(kKeySampleRate, sampleRate); 349 mFormat->setInt32(kKeyChannelCount, numChannels); 350 351 if (sampleRate != 16000 || numChannels != 1) { 352 mInitCheck = ERROR_UNSUPPORTED; 353 } 354 } else { 355 mInitCheck = ERROR_UNSUPPORTED; 356 } 357} 358 359APacketSource::~APacketSource() { 360} 361 362status_t APacketSource::initCheck() const { 363 return mInitCheck; 364} 365 366status_t APacketSource::start(MetaData *params) { 367 mFirstAccessUnit = true; 368 mFirstAccessUnitNTP = 0; 369 370 return OK; 371} 372 373status_t APacketSource::stop() { 374 return OK; 375} 376 377sp<MetaData> APacketSource::getFormat() { 378 return mFormat; 379} 380 381status_t APacketSource::read( 382 MediaBuffer **out, const ReadOptions *) { 383 *out = NULL; 384 385 Mutex::Autolock autoLock(mLock); 386 while (mEOSResult == OK && mBuffers.empty()) { 387 mCondition.wait(mLock); 388 } 389 390 if (!mBuffers.empty()) { 391 const sp<ABuffer> buffer = *mBuffers.begin(); 392 393 MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size()); 394 395 int64_t timeUs; 396 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 397 398 mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); 399 400 memcpy(mediaBuffer->data(), buffer->data(), buffer->size()); 401 *out = mediaBuffer; 402 403 mBuffers.erase(mBuffers.begin()); 404 return OK; 405 } 406 407 return mEOSResult; 408} 409 410void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { 411 int32_t damaged; 412 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { 413 LOG(VERBOSE) << "discarding damaged AU"; 414 return; 415 } 416 417 uint64_t ntpTime; 418 CHECK(buffer->meta()->findInt64( 419 "ntp-time", (int64_t *)&ntpTime)); 420 421 if (mFirstAccessUnit) { 422 mFirstAccessUnit = false; 423 mFirstAccessUnitNTP = ntpTime; 424 } 425 426 if (ntpTime > mFirstAccessUnitNTP) { 427 ntpTime -= mFirstAccessUnitNTP; 428 } else { 429 ntpTime = 0; 430 } 431 432 int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32)); 433 434 buffer->meta()->setInt64("timeUs", timeUs); 435 436 Mutex::Autolock autoLock(mLock); 437 mBuffers.push_back(buffer); 438 mCondition.signal(); 439} 440 441void APacketSource::signalEOS(status_t result) { 442 CHECK(result != OK); 443 444 Mutex::Autolock autoLock(mLock); 445 mEOSResult = result; 446 mCondition.signal(); 447} 448 449int64_t APacketSource::getQueuedDuration(bool *eos) { 450 Mutex::Autolock autoLock(mLock); 451 452 *eos = (mEOSResult != OK); 453 454 if (mBuffers.empty()) { 455 return 0; 456 } 457 458 sp<ABuffer> buffer = *mBuffers.begin(); 459 460 uint64_t ntpTime; 461 CHECK(buffer->meta()->findInt64( 462 "ntp-time", (int64_t *)&ntpTime)); 463 464 int64_t firstTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32)); 465 466 buffer = *--mBuffers.end(); 467 468 CHECK(buffer->meta()->findInt64( 469 "ntp-time", (int64_t *)&ntpTime)); 470 471 int64_t lastTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32)); 472 473 return lastTimeUs - firstTimeUs; 474} 475 476} // namespace android 477