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