APacketSource.cpp revision cf7b9c7aae758ac0b99833915053c63c2ac46e09
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 CHECK(GetAttribute(params, "profile-level-id", &val)); 96 97 sp<ABuffer> profileLevelID = decodeHex(val); 98 CHECK(profileLevelID != NULL); 99 CHECK_EQ(profileLevelID->size(), 3u); 100 101 Vector<sp<ABuffer> > paramSets; 102 103 size_t numSeqParameterSets = 0; 104 size_t totalSeqParameterSetSize = 0; 105 size_t numPicParameterSets = 0; 106 size_t totalPicParameterSetSize = 0; 107 108 CHECK(GetAttribute(params, "sprop-parameter-sets", &val)); 109 size_t start = 0; 110 for (;;) { 111 ssize_t commaPos = val.find(",", start); 112 size_t end = (commaPos < 0) ? val.size() : commaPos; 113 114 AString nalString(val, start, end - start); 115 sp<ABuffer> nal = decodeBase64(nalString); 116 CHECK(nal != NULL); 117 CHECK_GT(nal->size(), 0u); 118 CHECK_LE(nal->size(), 65535u); 119 120 uint8_t nalType = nal->data()[0] & 0x1f; 121 if (numSeqParameterSets == 0) { 122 CHECK_EQ((unsigned)nalType, 7u); 123 } else if (numPicParameterSets > 0) { 124 CHECK_EQ((unsigned)nalType, 8u); 125 } 126 if (nalType == 7) { 127 ++numSeqParameterSets; 128 totalSeqParameterSetSize += nal->size(); 129 } else { 130 CHECK_EQ((unsigned)nalType, 8u); 131 ++numPicParameterSets; 132 totalPicParameterSetSize += nal->size(); 133 } 134 135 paramSets.push(nal); 136 137 if (commaPos < 0) { 138 break; 139 } 140 141 start = commaPos + 1; 142 } 143 144 CHECK_LT(numSeqParameterSets, 32u); 145 CHECK_LE(numPicParameterSets, 255u); 146 147 size_t csdSize = 148 1 + 3 + 1 + 1 149 + 2 * numSeqParameterSets + totalSeqParameterSetSize 150 + 1 + 2 * numPicParameterSets + totalPicParameterSetSize; 151 152 sp<ABuffer> csd = new ABuffer(csdSize); 153 uint8_t *out = csd->data(); 154 155 *out++ = 0x01; // configurationVersion 156 memcpy(out, profileLevelID->data(), 3); 157 out += 3; 158 *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes 159 *out++ = 0xe0 | numSeqParameterSets; 160 161 for (size_t i = 0; i < numSeqParameterSets; ++i) { 162 sp<ABuffer> nal = paramSets.editItemAt(i); 163 164 *out++ = nal->size() >> 8; 165 *out++ = nal->size() & 0xff; 166 167 memcpy(out, nal->data(), nal->size()); 168 169 out += nal->size(); 170 } 171 172 *out++ = numPicParameterSets; 173 174 for (size_t i = 0; i < numPicParameterSets; ++i) { 175 sp<ABuffer> nal = paramSets.editItemAt(i + numSeqParameterSets); 176 177 *out++ = nal->size() >> 8; 178 *out++ = nal->size() & 0xff; 179 180 memcpy(out, nal->data(), nal->size()); 181 182 out += nal->size(); 183 } 184 185 hexdump(csd->data(), csd->size()); 186 187 return csd; 188} 189 190sp<ABuffer> MakeAACCodecSpecificData(const char *params) { 191 AString val; 192 CHECK(GetAttribute(params, "config", &val)); 193 194 sp<ABuffer> config = decodeHex(val); 195 CHECK(config != NULL); 196 CHECK_GE(config->size(), 4u); 197 198 const uint8_t *data = config->data(); 199 uint32_t x = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; 200 x = (x >> 1) & 0xffff; 201 202 static const uint8_t kStaticESDS[] = { 203 0x03, 22, 204 0x00, 0x00, // ES_ID 205 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag 206 207 0x04, 17, 208 0x40, // Audio ISO/IEC 14496-3 209 0x00, 0x00, 0x00, 0x00, 210 0x00, 0x00, 0x00, 0x00, 211 0x00, 0x00, 0x00, 0x00, 212 213 0x05, 2, 214 // AudioSpecificInfo follows 215 }; 216 217 sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2); 218 memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS)); 219 csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff; 220 csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff; 221 222 hexdump(csd->data(), csd->size()); 223 224 return csd; 225} 226 227APacketSource::APacketSource( 228 const sp<ASessionDescription> &sessionDesc, size_t index) 229 : mFormat(new MetaData), 230 mEOSResult(OK) { 231 unsigned long PT; 232 AString desc; 233 AString params; 234 sessionDesc->getFormatType(index, &PT, &desc, ¶ms); 235 236 int64_t durationUs; 237 if (sessionDesc->getDurationUs(&durationUs)) { 238 mFormat->setInt64(kKeyDuration, durationUs); 239 } else { 240 mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll); 241 } 242 243 if (!strncmp(desc.c_str(), "H264/", 5)) { 244 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 245 246 int32_t width, height; 247 sessionDesc->getDimensions(index, PT, &width, &height); 248 249 mFormat->setInt32(kKeyWidth, width); 250 mFormat->setInt32(kKeyHeight, height); 251 252 sp<ABuffer> codecSpecificData = 253 MakeAVCCodecSpecificData(params.c_str()); 254 255 mFormat->setData( 256 kKeyAVCC, 0, 257 codecSpecificData->data(), codecSpecificData->size()); 258 259 } else if (!strncmp(desc.c_str(), "MP4A-LATM", 9)) { 260 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); 261 262 int32_t sampleRate, numChannels; 263 ASessionDescription::ParseFormatDesc( 264 desc.c_str(), &sampleRate, &numChannels); 265 266 mFormat->setInt32(kKeySampleRate, sampleRate); 267 mFormat->setInt32(kKeyChannelCount, numChannels); 268 269 sp<ABuffer> codecSpecificData = 270 MakeAACCodecSpecificData(params.c_str()); 271 272 mFormat->setData( 273 kKeyESDS, 0, 274 codecSpecificData->data(), codecSpecificData->size()); 275 } else { 276 TRESPASS(); 277 } 278} 279 280APacketSource::~APacketSource() { 281} 282 283status_t APacketSource::start(MetaData *params) { 284 return OK; 285} 286 287status_t APacketSource::stop() { 288 return OK; 289} 290 291sp<MetaData> APacketSource::getFormat() { 292 return mFormat; 293} 294 295status_t APacketSource::read( 296 MediaBuffer **out, const ReadOptions *) { 297 *out = NULL; 298 299 Mutex::Autolock autoLock(mLock); 300 while (mEOSResult == OK && mBuffers.empty()) { 301 mCondition.wait(mLock); 302 } 303 304 if (!mBuffers.empty()) { 305 const sp<ABuffer> buffer = *mBuffers.begin(); 306 307 uint64_t ntpTime; 308 CHECK(buffer->meta()->findInt64( 309 "ntp-time", (int64_t *)&ntpTime)); 310 311 int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32)); 312 313 MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size()); 314 mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); 315 memcpy(mediaBuffer->data(), buffer->data(), buffer->size()); 316 *out = mediaBuffer; 317 318 mBuffers.erase(mBuffers.begin()); 319 return OK; 320 } 321 322 return mEOSResult; 323} 324 325void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { 326 int32_t damaged; 327 if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { 328 // LOG(VERBOSE) << "discarding damaged AU"; 329 return; 330 } 331 332 Mutex::Autolock autoLock(mLock); 333 mBuffers.push_back(buffer); 334 mCondition.signal(); 335} 336 337void APacketSource::signalEOS(status_t result) { 338 CHECK(result != OK); 339 340 Mutex::Autolock autoLock(mLock); 341 mEOSResult = result; 342 mCondition.signal(); 343} 344 345} // namespace android 346