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 "APacketSource" 19#include <utils/Log.h> 20 21#include "APacketSource.h" 22 23#include "ARawAudioAssembler.h" 24#include "ASessionDescription.h" 25 26#include <ctype.h> 27 28#include <media/stagefright/foundation/ABitReader.h> 29#include <media/stagefright/foundation/ABuffer.h> 30#include <media/stagefright/foundation/ADebug.h> 31#include <media/stagefright/foundation/AMessage.h> 32#include <media/stagefright/foundation/AString.h> 33#include <media/stagefright/foundation/avc_utils.h> 34#include <media/stagefright/foundation/base64.h> 35#include <media/stagefright/foundation/hexdump.h> 36#include <media/stagefright/MediaDefs.h> 37#include <media/stagefright/MediaErrors.h> 38#include <media/stagefright/MetaData.h> 39#include <utils/Vector.h> 40 41namespace android { 42 43static bool GetAttribute(const char *s, const char *key, AString *value) { 44 value->clear(); 45 46 size_t keyLen = strlen(key); 47 48 for (;;) { 49 while (isspace(*s)) { 50 ++s; 51 } 52 53 const char *colonPos = strchr(s, ';'); 54 55 size_t len = 56 (colonPos == NULL) ? strlen(s) : colonPos - s; 57 58 if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { 59 value->setTo(&s[keyLen + 1], len - keyLen - 1); 60 return true; 61 } 62 63 if (colonPos == NULL) { 64 return false; 65 } 66 67 s = colonPos + 1; 68 } 69} 70 71static sp<ABuffer> decodeHex(const AString &s) { 72 if ((s.size() % 2) != 0) { 73 return NULL; 74 } 75 76 size_t outLen = s.size() / 2; 77 sp<ABuffer> buffer = new ABuffer(outLen); 78 uint8_t *out = buffer->data(); 79 80 uint8_t accum = 0; 81 for (size_t i = 0; i < s.size(); ++i) { 82 char c = s.c_str()[i]; 83 unsigned value; 84 if (c >= '0' && c <= '9') { 85 value = c - '0'; 86 } else if (c >= 'a' && c <= 'f') { 87 value = c - 'a' + 10; 88 } else if (c >= 'A' && c <= 'F') { 89 value = c - 'A' + 10; 90 } else { 91 return NULL; 92 } 93 94 accum = (accum << 4) | value; 95 96 if (i & 1) { 97 *out++ = accum; 98 99 accum = 0; 100 } 101 } 102 103 return buffer; 104} 105 106static sp<ABuffer> MakeAVCCodecSpecificData( 107 const char *params, int32_t *width, int32_t *height) { 108 *width = 0; 109 *height = 0; 110 111 AString val; 112 sp<ABuffer> profileLevelID = NULL; 113 if (GetAttribute(params, "profile-level-id", &val)) { 114 profileLevelID = decodeHex(val); 115 CHECK_EQ(profileLevelID->size(), 3u); 116 } 117 118 Vector<sp<ABuffer> > paramSets; 119 120 size_t numSeqParameterSets = 0; 121 size_t totalSeqParameterSetSize = 0; 122 size_t numPicParameterSets = 0; 123 size_t totalPicParameterSetSize = 0; 124 125 if (!GetAttribute(params, "sprop-parameter-sets", &val)) { 126 return NULL; 127 } 128 129 size_t start = 0; 130 for (;;) { 131 ssize_t commaPos = val.find(",", start); 132 size_t end = (commaPos < 0) ? val.size() : commaPos; 133 134 AString nalString(val, start, end - start); 135 sp<ABuffer> nal = decodeBase64(nalString); 136 CHECK(nal != NULL); 137 CHECK_GT(nal->size(), 0u); 138 CHECK_LE(nal->size(), 65535u); 139 140 uint8_t nalType = nal->data()[0] & 0x1f; 141 if (numSeqParameterSets == 0) { 142 CHECK_EQ((unsigned)nalType, 7u); 143 } else if (numPicParameterSets > 0) { 144 CHECK_EQ((unsigned)nalType, 8u); 145 } 146 if (nalType == 7) { 147 ++numSeqParameterSets; 148 totalSeqParameterSetSize += nal->size(); 149 } else { 150 CHECK_EQ((unsigned)nalType, 8u); 151 ++numPicParameterSets; 152 totalPicParameterSetSize += nal->size(); 153 } 154 155 paramSets.push(nal); 156 157 if (commaPos < 0) { 158 break; 159 } 160 161 start = commaPos + 1; 162 } 163 164 CHECK_LT(numSeqParameterSets, 32u); 165 CHECK_LE(numPicParameterSets, 255u); 166 167 size_t csdSize = 168 1 + 3 + 1 + 1 169 + 2 * numSeqParameterSets + totalSeqParameterSetSize 170 + 1 + 2 * numPicParameterSets + totalPicParameterSetSize; 171 172 sp<ABuffer> csd = new ABuffer(csdSize); 173 uint8_t *out = csd->data(); 174 175 *out++ = 0x01; // configurationVersion 176 if (profileLevelID != NULL) { 177 memcpy(out, profileLevelID->data(), 3); 178 out += 3; 179 } else { 180 *out++ = 0x42; // Baseline profile 181 *out++ = 0xE0; // Common subset for all profiles 182 *out++ = 0x0A; // Level 1 183 } 184 185 *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes 186 *out++ = 0xe0 | numSeqParameterSets; 187 188 for (size_t i = 0; i < numSeqParameterSets; ++i) { 189 sp<ABuffer> nal = paramSets.editItemAt(i); 190 191 *out++ = nal->size() >> 8; 192 *out++ = nal->size() & 0xff; 193 194 memcpy(out, nal->data(), nal->size()); 195 196 out += nal->size(); 197 198 if (i == 0) { 199 FindAVCDimensions(nal, width, height); 200 ALOGI("dimensions %dx%d", *width, *height); 201 } 202 } 203 204 *out++ = numPicParameterSets; 205 206 for (size_t i = 0; i < numPicParameterSets; ++i) { 207 sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets); 208 209 *out++ = nal->size() >> 8; 210 *out++ = nal->size() & 0xff; 211 212 memcpy(out, nal->data(), nal->size()); 213 214 out += nal->size(); 215 } 216 217 // hexdump(csd->data(), csd->size()); 218 219 return csd; 220} 221 222static sp<ABuffer> MakeAACCodecSpecificData(const char *params) { 223 AString val; 224 CHECK(GetAttribute(params, "config", &val)); 225 226 sp<ABuffer> config = decodeHex(val); 227 CHECK(config != NULL); 228 CHECK_GE(config->size(), 4u); 229 230 const uint8_t *data = config->data(); 231 uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; 232 x = (x >> 1) & 0xffff; 233 234 static const uint8_t kStaticESDS[] = { 235 0x03, 22, 236 0x00, 0x00, // ES_ID 237 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 238 239 0x04, 17, 240 0x40, // Audio ISO/IEC 14496-3 241 0x00, 0x00, 0x00, 0x00, 242 0x00, 0x00, 0x00, 0x00, 243 0x00, 0x00, 0x00, 0x00, 244 245 0x05, 2, 246 // AudioSpecificInfo follows 247 }; 248 249 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2); 250 memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS)); 251 csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff; 252 csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff; 253 254 // hexdump(csd->data(), csd->size()); 255 256 return csd; 257} 258 259// From mpeg4-generic configuration data. 260static sp<ABuffer> MakeAACCodecSpecificData2(const char *params) { 261 AString val; 262 unsigned long objectType; 263 if (GetAttribute(params, "objectType", &val)) { 264 const char *s = val.c_str(); 265 char *end; 266 objectType = strtoul(s, &end, 10); 267 CHECK(end > s && *end == '\0'); 268 } else { 269 objectType = 0x40; // Audio ISO/IEC 14496-3 270 } 271 272 CHECK(GetAttribute(params, "config", &val)); 273 274 sp<ABuffer> config = decodeHex(val); 275 CHECK(config != NULL); 276 277 // Make sure size fits into a single byte and doesn't have to 278 // be encoded. 279 CHECK_LT(20 + config->size(), 128u); 280 281 static const uint8_t kStaticESDS[] = { 282 0x03, 22, 283 0x00, 0x00, // ES_ID 284 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 285 286 0x04, 17, 287 0x40, // Audio ISO/IEC 14496-3 288 0x00, 0x00, 0x00, 0x00, 289 0x00, 0x00, 0x00, 0x00, 290 0x00, 0x00, 0x00, 0x00, 291 292 0x05, 2, 293 // AudioSpecificInfo follows 294 }; 295 296 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + config->size()); 297 uint8_t *dst = csd->data(); 298 *dst++ = 0x03; 299 *dst++ = 20 + config->size(); 300 *dst++ = 0x00; // ES_ID 301 *dst++ = 0x00; 302 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag 303 *dst++ = 0x04; 304 *dst++ = 15 + config->size(); 305 *dst++ = objectType; 306 for (int i = 0; i < 12; ++i) { *dst++ = 0x00; } 307 *dst++ = 0x05; 308 *dst++ = config->size(); 309 memcpy(dst, config->data(), config->size()); 310 311 // hexdump(csd->data(), csd->size()); 312 313 return csd; 314} 315 316static size_t GetSizeWidth(size_t x) { 317 size_t n = 1; 318 while (x > 127) { 319 ++n; 320 x >>= 7; 321 } 322 return n; 323} 324 325static uint8_t *EncodeSize(uint8_t *dst, size_t x) { 326 while (x > 127) { 327 *dst++ = (x & 0x7f) | 0x80; 328 x >>= 7; 329 } 330 *dst++ = x; 331 return dst; 332} 333 334static bool ExtractDimensionsMPEG4Config( 335 const sp<ABuffer> &config, int32_t *width, int32_t *height) { 336 *width = 0; 337 *height = 0; 338 339 const uint8_t *ptr = config->data(); 340 size_t offset = 0; 341 bool foundVOL = false; 342 while (offset + 3 < config->size()) { 343 if (memcmp("\x00\x00\x01", &ptr[offset], 3) 344 || (ptr[offset + 3] & 0xf0) != 0x20) { 345 ++offset; 346 continue; 347 } 348 349 foundVOL = true; 350 break; 351 } 352 353 if (!foundVOL) { 354 return false; 355 } 356 357 return ExtractDimensionsFromVOLHeader( 358 &ptr[offset], config->size() - offset, width, height); 359} 360 361static sp<ABuffer> MakeMPEG4VideoCodecSpecificData( 362 const char *params, int32_t *width, int32_t *height) { 363 *width = 0; 364 *height = 0; 365 366 AString val; 367 CHECK(GetAttribute(params, "config", &val)); 368 369 sp<ABuffer> config = decodeHex(val); 370 CHECK(config != NULL); 371 372 if (!ExtractDimensionsMPEG4Config(config, width, height)) { 373 return NULL; 374 } 375 376 ALOGI("VOL dimensions = %dx%d", *width, *height); 377 378 size_t len1 = config->size() + GetSizeWidth(config->size()) + 1; 379 size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13; 380 size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3; 381 382 sp<ABuffer> csd = new ABuffer(len3); 383 uint8_t *dst = csd->data(); 384 *dst++ = 0x03; 385 dst = EncodeSize(dst, len2 + 3); 386 *dst++ = 0x00; // ES_ID 387 *dst++ = 0x00; 388 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag 389 390 *dst++ = 0x04; 391 dst = EncodeSize(dst, len1 + 13); 392 *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile 393 for (size_t i = 0; i < 12; ++i) { 394 *dst++ = 0x00; 395 } 396 397 *dst++ = 0x05; 398 dst = EncodeSize(dst, config->size()); 399 memcpy(dst, config->data(), config->size()); 400 dst += config->size(); 401 402 // hexdump(csd->data(), csd->size()); 403 404 return csd; 405} 406 407APacketSource::APacketSource( 408 const sp<ASessionDescription> &sessionDesc, size_t index) 409 : mInitCheck(NO_INIT), 410 mFormat(new MetaData) { 411 unsigned long PT; 412 AString desc; 413 AString params; 414 sessionDesc->getFormatType(index, &PT, &desc, ¶ms); 415 416 int64_t durationUs; 417 if (sessionDesc->getDurationUs(&durationUs)) { 418 mFormat->setInt64(kKeyDuration, durationUs); 419 } else { 420 mFormat->setInt64(kKeyDuration, -1ll); 421 } 422 423 mInitCheck = OK; 424 if (!strncmp(desc.c_str(), "H264/", 5)) { 425 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 426 427 int32_t width, height; 428 if (!sessionDesc->getDimensions(index, PT, &width, &height)) { 429 width = -1; 430 height = -1; 431 } 432 433 int32_t encWidth, encHeight; 434 sp<ABuffer> codecSpecificData = 435 MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight); 436 437 if (codecSpecificData != NULL) { 438 if (width < 0) { 439 // If no explicit width/height given in the sdp, use the dimensions 440 // extracted from the first sequence parameter set. 441 width = encWidth; 442 height = encHeight; 443 } 444 445 mFormat->setData( 446 kKeyAVCC, 0, 447 codecSpecificData->data(), codecSpecificData->size()); 448 } else if (width < 0) { 449 mInitCheck = ERROR_UNSUPPORTED; 450 return; 451 } 452 453 mFormat->setInt32(kKeyWidth, width); 454 mFormat->setInt32(kKeyHeight, height); 455 } else if (!strncmp(desc.c_str(), "H263-2000/", 10) 456 || !strncmp(desc.c_str(), "H263-1998/", 10)) { 457 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); 458 459 int32_t width, height; 460 if (!sessionDesc->getDimensions(index, PT, &width, &height)) { 461 mInitCheck = ERROR_UNSUPPORTED; 462 return; 463 } 464 465 mFormat->setInt32(kKeyWidth, width); 466 mFormat->setInt32(kKeyHeight, height); 467 } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) { 468 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 469 470 int32_t sampleRate, numChannels; 471 ASessionDescription::ParseFormatDesc( 472 desc.c_str(), &sampleRate, &numChannels); 473 474 mFormat->setInt32(kKeySampleRate, sampleRate); 475 mFormat->setInt32(kKeyChannelCount, numChannels); 476 477 sp<ABuffer> codecSpecificData = 478 MakeAACCodecSpecificData(params.c_str()); 479 480 mFormat->setData( 481 kKeyESDS, 0, 482 codecSpecificData->data(), codecSpecificData->size()); 483 } else if (!strncmp(desc.c_str(), "AMR/", 4)) { 484 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB); 485 486 int32_t sampleRate, numChannels; 487 ASessionDescription::ParseFormatDesc( 488 desc.c_str(), &sampleRate, &numChannels); 489 490 mFormat->setInt32(kKeySampleRate, sampleRate); 491 mFormat->setInt32(kKeyChannelCount, numChannels); 492 493 if (sampleRate != 8000 || numChannels != 1) { 494 mInitCheck = ERROR_UNSUPPORTED; 495 } 496 } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) { 497 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB); 498 499 int32_t sampleRate, numChannels; 500 ASessionDescription::ParseFormatDesc( 501 desc.c_str(), &sampleRate, &numChannels); 502 503 mFormat->setInt32(kKeySampleRate, sampleRate); 504 mFormat->setInt32(kKeyChannelCount, numChannels); 505 506 if (sampleRate != 16000 || numChannels != 1) { 507 mInitCheck = ERROR_UNSUPPORTED; 508 } 509 } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) { 510 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 511 512 int32_t width, height; 513 if (!sessionDesc->getDimensions(index, PT, &width, &height)) { 514 width = -1; 515 height = -1; 516 } 517 518 int32_t encWidth, encHeight; 519 sp<ABuffer> codecSpecificData = 520 MakeMPEG4VideoCodecSpecificData( 521 params.c_str(), &encWidth, &encHeight); 522 523 if (codecSpecificData != NULL) { 524 mFormat->setData( 525 kKeyESDS, 0, 526 codecSpecificData->data(), codecSpecificData->size()); 527 528 if (width < 0) { 529 width = encWidth; 530 height = encHeight; 531 } 532 } else if (width < 0) { 533 mInitCheck = ERROR_UNSUPPORTED; 534 return; 535 } 536 537 mFormat->setInt32(kKeyWidth, width); 538 mFormat->setInt32(kKeyHeight, height); 539 } else if (!strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) { 540 AString val; 541 if (!GetAttribute(params.c_str(), "mode", &val) 542 || (strcasecmp(val.c_str(), "AAC-lbr") 543 && strcasecmp(val.c_str(), "AAC-hbr"))) { 544 mInitCheck = ERROR_UNSUPPORTED; 545 return; 546 } 547 548 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 549 550 int32_t sampleRate, numChannels; 551 ASessionDescription::ParseFormatDesc( 552 desc.c_str(), &sampleRate, &numChannels); 553 554 mFormat->setInt32(kKeySampleRate, sampleRate); 555 mFormat->setInt32(kKeyChannelCount, numChannels); 556 mFormat->setInt32(kKeyIsADTS, true); 557 558 sp<ABuffer> codecSpecificData = 559 MakeAACCodecSpecificData2(params.c_str()); 560 561 mFormat->setData( 562 kKeyESDS, 0, 563 codecSpecificData->data(), codecSpecificData->size()); 564 } else if (ARawAudioAssembler::Supports(desc.c_str())) { 565 ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat); 566 } else if (!strncasecmp("MP2T/", desc.c_str(), 5)) { 567 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 568 } else { 569 mInitCheck = ERROR_UNSUPPORTED; 570 } 571} 572 573APacketSource::~APacketSource() { 574} 575 576status_t APacketSource::initCheck() const { 577 return mInitCheck; 578} 579 580sp<MetaData> APacketSource::getFormat() { 581 return mFormat; 582} 583 584} // namespace android 585