Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2010 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 <media/stagefright/foundation/ADebug.h>
     18 #include <media/stagefright/AMRWriter.h>
     19 #include <media/stagefright/MediaBuffer.h>
     20 #include <media/stagefright/MediaDefs.h>
     21 #include <media/stagefright/MediaErrors.h>
     22 #include <media/stagefright/MediaSource.h>
     23 #include <media/stagefright/MetaData.h>
     24 #include <media/mediarecorder.h>
     25 #include <sys/prctl.h>
     26 #include <sys/types.h>
     27 #include <sys/stat.h>
     28 #include <fcntl.h>
     29 
     30 namespace android {
     31 
     32 AMRWriter::AMRWriter(const char *filename)
     33     : mFd(-1),
     34       mInitCheck(NO_INIT),
     35       mStarted(false),
     36       mPaused(false),
     37       mResumed(false) {
     38 
     39     mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     40     if (mFd >= 0) {
     41         mInitCheck = OK;
     42     }
     43 }
     44 
     45 AMRWriter::AMRWriter(int fd)
     46     : mFd(dup(fd)),
     47       mInitCheck(mFd < 0? NO_INIT: OK),
     48       mStarted(false),
     49       mPaused(false),
     50       mResumed(false) {
     51 }
     52 
     53 AMRWriter::~AMRWriter() {
     54     if (mStarted) {
     55         reset();
     56     }
     57 
     58     if (mFd != -1) {
     59         close(mFd);
     60         mFd = -1;
     61     }
     62 }
     63 
     64 status_t AMRWriter::initCheck() const {
     65     return mInitCheck;
     66 }
     67 
     68 status_t AMRWriter::addSource(const sp<MediaSource> &source) {
     69     if (mInitCheck != OK) {
     70         return mInitCheck;
     71     }
     72 
     73     if (mSource != NULL) {
     74         // AMR files only support a single track of audio.
     75         return UNKNOWN_ERROR;
     76     }
     77 
     78     sp<MetaData> meta = source->getFormat();
     79 
     80     const char *mime;
     81     CHECK(meta->findCString(kKeyMIMEType, &mime));
     82 
     83     bool isWide = false;
     84     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
     85         isWide = true;
     86     } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
     87         return ERROR_UNSUPPORTED;
     88     }
     89 
     90     int32_t channelCount;
     91     int32_t sampleRate;
     92     CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
     93     CHECK_EQ(channelCount, 1);
     94     CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
     95     CHECK_EQ(sampleRate, (isWide ? 16000 : 8000));
     96 
     97     mSource = source;
     98 
     99     const char *kHeader = isWide ? "#!AMR-WB\n" : "#!AMR\n";
    100     ssize_t n = strlen(kHeader);
    101     if (write(mFd, kHeader, n) != n) {
    102         return ERROR_IO;
    103     }
    104 
    105     return OK;
    106 }
    107 
    108 status_t AMRWriter::start(MetaData *params) {
    109     if (mInitCheck != OK) {
    110         return mInitCheck;
    111     }
    112 
    113     if (mSource == NULL) {
    114         return UNKNOWN_ERROR;
    115     }
    116 
    117     if (mStarted && mPaused) {
    118         mPaused = false;
    119         mResumed = true;
    120         return OK;
    121     } else if (mStarted) {
    122         // Already started, does nothing
    123         return OK;
    124     }
    125 
    126     status_t err = mSource->start();
    127 
    128     if (err != OK) {
    129         return err;
    130     }
    131 
    132     pthread_attr_t attr;
    133     pthread_attr_init(&attr);
    134     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    135 
    136     mReachedEOS = false;
    137     mDone = false;
    138 
    139     pthread_create(&mThread, &attr, ThreadWrapper, this);
    140     pthread_attr_destroy(&attr);
    141 
    142     mStarted = true;
    143 
    144     return OK;
    145 }
    146 
    147 status_t AMRWriter::pause() {
    148     if (!mStarted) {
    149         return OK;
    150     }
    151     mPaused = true;
    152     return OK;
    153 }
    154 
    155 status_t AMRWriter::reset() {
    156     if (!mStarted) {
    157         return OK;
    158     }
    159 
    160     mDone = true;
    161 
    162     void *dummy;
    163     pthread_join(mThread, &dummy);
    164 
    165     status_t err = (status_t) dummy;
    166     {
    167         status_t status = mSource->stop();
    168         if (err == OK &&
    169             (status != OK && status != ERROR_END_OF_STREAM)) {
    170             err = status;
    171         }
    172     }
    173 
    174     mStarted = false;
    175     return err;
    176 }
    177 
    178 bool AMRWriter::exceedsFileSizeLimit() {
    179     if (mMaxFileSizeLimitBytes == 0) {
    180         return false;
    181     }
    182     return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
    183 }
    184 
    185 bool AMRWriter::exceedsFileDurationLimit() {
    186     if (mMaxFileDurationLimitUs == 0) {
    187         return false;
    188     }
    189     return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
    190 }
    191 
    192 // static
    193 void *AMRWriter::ThreadWrapper(void *me) {
    194     return (void *) static_cast<AMRWriter *>(me)->threadFunc();
    195 }
    196 
    197 status_t AMRWriter::threadFunc() {
    198     mEstimatedDurationUs = 0;
    199     mEstimatedSizeBytes = 0;
    200     bool stoppedPrematurely = true;
    201     int64_t previousPausedDurationUs = 0;
    202     int64_t maxTimestampUs = 0;
    203     status_t err = OK;
    204 
    205     prctl(PR_SET_NAME, (unsigned long)"AMRWriter", 0, 0, 0);
    206     while (!mDone) {
    207         MediaBuffer *buffer;
    208         err = mSource->read(&buffer);
    209 
    210         if (err != OK) {
    211             break;
    212         }
    213 
    214         if (mPaused) {
    215             buffer->release();
    216             buffer = NULL;
    217             continue;
    218         }
    219 
    220         mEstimatedSizeBytes += buffer->range_length();
    221         if (exceedsFileSizeLimit()) {
    222             buffer->release();
    223             buffer = NULL;
    224             notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
    225             break;
    226         }
    227 
    228         int64_t timestampUs;
    229         CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
    230         if (timestampUs > mEstimatedDurationUs) {
    231             mEstimatedDurationUs = timestampUs;
    232         }
    233         if (mResumed) {
    234             previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
    235             mResumed = false;
    236         }
    237         timestampUs -= previousPausedDurationUs;
    238         ALOGV("time stamp: %lld, previous paused duration: %lld",
    239                 timestampUs, previousPausedDurationUs);
    240         if (timestampUs > maxTimestampUs) {
    241             maxTimestampUs = timestampUs;
    242         }
    243 
    244         if (exceedsFileDurationLimit()) {
    245             buffer->release();
    246             buffer = NULL;
    247             notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
    248             break;
    249         }
    250         ssize_t n = write(mFd,
    251                         (const uint8_t *)buffer->data() + buffer->range_offset(),
    252                         buffer->range_length());
    253 
    254         if (n < (ssize_t)buffer->range_length()) {
    255             buffer->release();
    256             buffer = NULL;
    257             err = ERROR_IO;
    258             break;
    259         }
    260 
    261         if (err != OK) {
    262             break;
    263         }
    264 
    265         if (stoppedPrematurely) {
    266             stoppedPrematurely = false;
    267         }
    268 
    269         buffer->release();
    270         buffer = NULL;
    271     }
    272 
    273     if ((err == OK || err == ERROR_END_OF_STREAM) && stoppedPrematurely) {
    274         err = ERROR_MALFORMED;
    275     }
    276 
    277     close(mFd);
    278     mFd = -1;
    279     mReachedEOS = true;
    280     if (err == ERROR_END_OF_STREAM) {
    281         return OK;
    282     }
    283     return err;
    284 }
    285 
    286 bool AMRWriter::reachedEOS() {
    287     return mReachedEOS;
    288 }
    289 
    290 }  // namespace android
    291