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