1/* 2 * Copyright (C) 2011 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 <fcntl.h> 18#include <inttypes.h> 19#include <sys/prctl.h> 20#include <sys/stat.h> 21#include <sys/types.h> 22 23//#define LOG_NDEBUG 0 24#define LOG_TAG "AACWriter" 25#include <utils/Log.h> 26 27#include <media/openmax/OMX_Audio.h> 28#include <media/stagefright/AACWriter.h> 29#include <media/stagefright/MediaBuffer.h> 30#include <media/stagefright/foundation/ADebug.h> 31#include <media/stagefright/MediaDefs.h> 32#include <media/stagefright/MediaErrors.h> 33#include <media/stagefright/MediaSource.h> 34#include <media/stagefright/MetaData.h> 35#include <media/mediarecorder.h> 36 37namespace android { 38 39AACWriter::AACWriter(const char *filename) 40 : mFd(-1), 41 mInitCheck(NO_INIT), 42 mStarted(false), 43 mPaused(false), 44 mResumed(false), 45 mChannelCount(-1), 46 mSampleRate(-1), 47 mAACProfile(OMX_AUDIO_AACObjectLC) { 48 49 ALOGV("AACWriter Constructor"); 50 51 mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); 52 if (mFd >= 0) { 53 mInitCheck = OK; 54 } 55} 56 57AACWriter::AACWriter(int fd) 58 : mFd(dup(fd)), 59 mInitCheck(mFd < 0? NO_INIT: OK), 60 mStarted(false), 61 mPaused(false), 62 mResumed(false), 63 mChannelCount(-1), 64 mSampleRate(-1), 65 mAACProfile(OMX_AUDIO_AACObjectLC) { 66} 67 68AACWriter::~AACWriter() { 69 if (mStarted) { 70 reset(); 71 } 72 73 if (mFd != -1) { 74 close(mFd); 75 mFd = -1; 76 } 77} 78 79status_t AACWriter::initCheck() const { 80 return mInitCheck; 81} 82 83static int writeInt8(int fd, uint8_t x) { 84 return ::write(fd, &x, 1); 85} 86 87 88status_t AACWriter::addSource(const sp<MediaSource> &source) { 89 if (mInitCheck != OK) { 90 return mInitCheck; 91 } 92 93 if (mSource != NULL) { 94 ALOGE("AAC files only support a single track of audio."); 95 return UNKNOWN_ERROR; 96 } 97 98 sp<MetaData> meta = source->getFormat(); 99 100 const char *mime; 101 CHECK(meta->findCString(kKeyMIMEType, &mime)); 102 103 CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)); 104 CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount)); 105 CHECK(meta->findInt32(kKeySampleRate, &mSampleRate)); 106 CHECK(mChannelCount >= 1 && mChannelCount <= 2); 107 108 // Optionally, we want to check whether AACProfile is also set. 109 if (meta->findInt32(kKeyAACProfile, &mAACProfile)) { 110 ALOGI("AAC profile is changed to %d", mAACProfile); 111 } 112 113 mSource = source; 114 return OK; 115} 116 117status_t AACWriter::start(MetaData * /* params */) { 118 if (mInitCheck != OK) { 119 return mInitCheck; 120 } 121 122 if (mSource == NULL) { 123 return UNKNOWN_ERROR; 124 } 125 126 if (mStarted && mPaused) { 127 mPaused = false; 128 mResumed = true; 129 return OK; 130 } else if (mStarted) { 131 // Already started, does nothing 132 return OK; 133 } 134 135 mFrameDurationUs = (kSamplesPerFrame * 1000000LL + (mSampleRate >> 1)) 136 / mSampleRate; 137 138 status_t err = mSource->start(); 139 140 if (err != OK) { 141 return err; 142 } 143 144 pthread_attr_t attr; 145 pthread_attr_init(&attr); 146 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 147 148 mReachedEOS = false; 149 mDone = false; 150 151 pthread_create(&mThread, &attr, ThreadWrapper, this); 152 pthread_attr_destroy(&attr); 153 154 mStarted = true; 155 156 return OK; 157} 158 159status_t AACWriter::pause() { 160 if (!mStarted) { 161 return OK; 162 } 163 mPaused = true; 164 return OK; 165} 166 167status_t AACWriter::reset() { 168 if (!mStarted) { 169 return OK; 170 } 171 172 mDone = true; 173 174 void *dummy; 175 pthread_join(mThread, &dummy); 176 177 status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); 178 { 179 status_t status = mSource->stop(); 180 if (err == OK && 181 (status != OK && status != ERROR_END_OF_STREAM)) { 182 err = status; 183 } 184 } 185 186 mStarted = false; 187 return err; 188} 189 190bool AACWriter::exceedsFileSizeLimit() { 191 if (mMaxFileSizeLimitBytes == 0) { 192 return false; 193 } 194 return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes; 195} 196 197bool AACWriter::exceedsFileDurationLimit() { 198 if (mMaxFileDurationLimitUs == 0) { 199 return false; 200 } 201 return mEstimatedDurationUs >= mMaxFileDurationLimitUs; 202} 203 204// static 205void *AACWriter::ThreadWrapper(void *me) { 206 return (void *)(uintptr_t)static_cast<AACWriter *>(me)->threadFunc(); 207} 208 209/* 210* Returns an index into the sample rate table if the 211* given sample rate is found; otherwise, returns -1. 212*/ 213static bool getSampleRateTableIndex(int sampleRate, uint8_t* tableIndex) { 214 static const int kSampleRateTable[] = { 215 96000, 88200, 64000, 48000, 44100, 32000, 216 24000, 22050, 16000, 12000, 11025, 8000 217 }; 218 const int tableSize = 219 sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]); 220 221 *tableIndex = 0; 222 for (int index = 0; index < tableSize; ++index) { 223 if (sampleRate == kSampleRateTable[index]) { 224 ALOGV("Sample rate: %d and index: %d", 225 sampleRate, index); 226 *tableIndex = index; 227 return true; 228 } 229 } 230 231 ALOGE("Sampling rate %d bps is not supported", sampleRate); 232 return false; 233} 234 235/* 236 * ADTS (Audio data transport stream) header structure. 237 * It consists of 7 or 9 bytes (with or without CRC): 238 * 12 bits of syncword 0xFFF, all bits must be 1 239 * 1 bit of field ID. 0 for MPEG-4, and 1 for MPEG-2 240 * 2 bits of MPEG layer. If in MPEG-TS, set to 0 241 * 1 bit of protection absense. Set to 1 if no CRC. 242 * 2 bits of profile code. Set to 1 (The MPEG-4 Audio 243 * object type minus 1. We are using AAC-LC = 2) 244 * 4 bits of sampling frequency index code (15 is not allowed) 245 * 1 bit of private stream. Set to 0. 246 * 3 bits of channel configuration code. 0 resevered for inband PCM 247 * 1 bit of originality. Set to 0. 248 * 1 bit of home. Set to 0. 249 * 1 bit of copyrighted steam. Set to 0. 250 * 1 bit of copyright start. Set to 0. 251 * 13 bits of frame length. It included 7 ot 9 bytes header length. 252 * it is set to (protection absense? 7: 9) + size(AAC frame) 253 * 11 bits of buffer fullness. 0x7FF for VBR. 254 * 2 bits of frames count in one packet. Set to 0. 255 */ 256status_t AACWriter::writeAdtsHeader(uint32_t frameLength) { 257 uint8_t data = 0xFF; 258 write(mFd, &data, 1); 259 260 const uint8_t kFieldId = 0; 261 const uint8_t kMpegLayer = 0; 262 const uint8_t kProtectionAbsense = 1; // 1: kAdtsHeaderLength = 7 263 data = 0xF0; 264 data |= (kFieldId << 3); 265 data |= (kMpegLayer << 1); 266 data |= kProtectionAbsense; 267 write(mFd, &data, 1); 268 269 const uint8_t kProfileCode = mAACProfile - 1; 270 uint8_t kSampleFreqIndex; 271 CHECK(getSampleRateTableIndex(mSampleRate, &kSampleFreqIndex)); 272 const uint8_t kPrivateStream = 0; 273 const uint8_t kChannelConfigCode = mChannelCount; 274 data = (kProfileCode << 6); 275 data |= (kSampleFreqIndex << 2); 276 data |= (kPrivateStream << 1); 277 data |= (kChannelConfigCode >> 2); 278 write(mFd, &data, 1); 279 280 // 4 bits from originality to copyright start 281 const uint8_t kCopyright = 0; 282 const uint32_t kFrameLength = frameLength; 283 data = ((kChannelConfigCode & 3) << 6); 284 data |= (kCopyright << 2); 285 data |= ((kFrameLength & 0x1800) >> 11); 286 write(mFd, &data, 1); 287 288 data = ((kFrameLength & 0x07F8) >> 3); 289 write(mFd, &data, 1); 290 291 const uint32_t kBufferFullness = 0x7FF; // VBR 292 data = ((kFrameLength & 0x07) << 5); 293 data |= ((kBufferFullness & 0x07C0) >> 6); 294 write(mFd, &data, 1); 295 296 const uint8_t kFrameCount = 0; 297 data = ((kBufferFullness & 0x03F) << 2); 298 data |= kFrameCount; 299 write(mFd, &data, 1); 300 301 return OK; 302} 303 304status_t AACWriter::threadFunc() { 305 mEstimatedDurationUs = 0; 306 mEstimatedSizeBytes = 0; 307 int64_t previousPausedDurationUs = 0; 308 int64_t maxTimestampUs = 0; 309 status_t err = OK; 310 bool stoppedPrematurely = true; 311 312 prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0); 313 314 while (!mDone && err == OK) { 315 MediaBuffer *buffer; 316 err = mSource->read(&buffer); 317 318 if (err != OK) { 319 break; 320 } 321 322 if (mPaused) { 323 buffer->release(); 324 buffer = NULL; 325 continue; 326 } 327 328 mEstimatedSizeBytes += kAdtsHeaderLength + buffer->range_length(); 329 if (exceedsFileSizeLimit()) { 330 buffer->release(); 331 buffer = NULL; 332 notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0); 333 break; 334 } 335 336 int32_t isCodecSpecific = 0; 337 if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecSpecific) && isCodecSpecific) { 338 ALOGV("Drop codec specific info buffer"); 339 buffer->release(); 340 buffer = NULL; 341 continue; 342 } 343 344 int64_t timestampUs; 345 CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 346 if (timestampUs > mEstimatedDurationUs) { 347 mEstimatedDurationUs = timestampUs; 348 } 349 if (mResumed) { 350 previousPausedDurationUs += (timestampUs - maxTimestampUs - mFrameDurationUs); 351 mResumed = false; 352 } 353 timestampUs -= previousPausedDurationUs; 354 ALOGV("time stamp: %" PRId64 ", previous paused duration: %" PRId64, 355 timestampUs, previousPausedDurationUs); 356 if (timestampUs > maxTimestampUs) { 357 maxTimestampUs = timestampUs; 358 } 359 360 if (exceedsFileDurationLimit()) { 361 buffer->release(); 362 buffer = NULL; 363 notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); 364 break; 365 } 366 367 // Each output AAC audio frame to the file contains 368 // 1. an ADTS header, followed by 369 // 2. the compressed audio data. 370 ssize_t dataLength = buffer->range_length(); 371 uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset(); 372 if (writeAdtsHeader(kAdtsHeaderLength + dataLength) != OK || 373 dataLength != write(mFd, data, dataLength)) { 374 err = ERROR_IO; 375 } 376 377 buffer->release(); 378 buffer = NULL; 379 380 if (err != OK) { 381 break; 382 } 383 384 if (stoppedPrematurely) { 385 stoppedPrematurely = false; 386 } 387 } 388 389 if ((err == OK || err == ERROR_END_OF_STREAM) && stoppedPrematurely) { 390 err = ERROR_MALFORMED; 391 } 392 393 close(mFd); 394 mFd = -1; 395 mReachedEOS = true; 396 if (err == ERROR_END_OF_STREAM) { 397 return OK; 398 } 399 return err; 400} 401 402bool AACWriter::reachedEOS() { 403 return mReachedEOS; 404} 405 406} // namespace android 407