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