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