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