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