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