Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright 2013, 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 "MediaMuxer"
     19 #include <utils/Log.h>
     20 
     21 #include <media/stagefright/MediaMuxer.h>
     22 
     23 #include <media/stagefright/foundation/ABuffer.h>
     24 #include <media/stagefright/foundation/ADebug.h>
     25 #include <media/stagefright/foundation/AMessage.h>
     26 #include <media/stagefright/MediaAdapter.h>
     27 #include <media/stagefright/MediaBuffer.h>
     28 #include <media/stagefright/MediaCodec.h>
     29 #include <media/stagefright/MediaDefs.h>
     30 #include <media/stagefright/MediaErrors.h>
     31 #include <media/stagefright/MediaSource.h>
     32 #include <media/stagefright/MetaData.h>
     33 #include <media/stagefright/MPEG4Writer.h>
     34 #include <media/stagefright/Utils.h>
     35 
     36 namespace android {
     37 
     38 MediaMuxer::MediaMuxer(const char *path, OutputFormat format)
     39     : mState(UNINITIALIZED) {
     40     if (format == OUTPUT_FORMAT_MPEG_4) {
     41         mWriter = new MPEG4Writer(path);
     42         mFileMeta = new MetaData;
     43         mState = INITIALIZED;
     44     }
     45 
     46 }
     47 
     48 MediaMuxer::MediaMuxer(int fd, OutputFormat format)
     49     : mState(UNINITIALIZED) {
     50     if (format == OUTPUT_FORMAT_MPEG_4) {
     51         mWriter = new MPEG4Writer(fd);
     52         mFileMeta = new MetaData;
     53         mState = INITIALIZED;
     54     }
     55 }
     56 
     57 MediaMuxer::~MediaMuxer() {
     58     Mutex::Autolock autoLock(mMuxerLock);
     59 
     60     // Clean up all the internal resources.
     61     mFileMeta.clear();
     62     mWriter.clear();
     63     mTrackList.clear();
     64 }
     65 
     66 ssize_t MediaMuxer::addTrack(const sp<AMessage> &format) {
     67     Mutex::Autolock autoLock(mMuxerLock);
     68 
     69     if (format.get() == NULL) {
     70         ALOGE("addTrack() get a null format");
     71         return -EINVAL;
     72     }
     73 
     74     if (mState != INITIALIZED) {
     75         ALOGE("addTrack() must be called after constructor and before start().");
     76         return INVALID_OPERATION;
     77     }
     78 
     79     sp<MetaData> trackMeta = new MetaData;
     80     convertMessageToMetaData(format, trackMeta);
     81 
     82     sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta);
     83     status_t result = mWriter->addSource(newTrack);
     84     if (result == OK) {
     85         return mTrackList.add(newTrack);
     86     }
     87     return -1;
     88 }
     89 
     90 status_t MediaMuxer::setOrientationHint(int degrees) {
     91     Mutex::Autolock autoLock(mMuxerLock);
     92     if (mState != INITIALIZED) {
     93         ALOGE("setOrientationHint() must be called before start().");
     94         return INVALID_OPERATION;
     95     }
     96 
     97     if (degrees != 0 && degrees != 90 && degrees != 180 && degrees != 270) {
     98         ALOGE("setOrientationHint() get invalid degrees");
     99         return -EINVAL;
    100     }
    101 
    102     mFileMeta->setInt32(kKeyRotation, degrees);
    103     return OK;
    104 }
    105 
    106 status_t MediaMuxer::start() {
    107     Mutex::Autolock autoLock(mMuxerLock);
    108     if (mState == INITIALIZED) {
    109         mState = STARTED;
    110         mFileMeta->setInt32(kKeyRealTimeRecording, false);
    111         return mWriter->start(mFileMeta.get());
    112     } else {
    113         ALOGE("start() is called in invalid state %d", mState);
    114         return INVALID_OPERATION;
    115     }
    116 }
    117 
    118 status_t MediaMuxer::stop() {
    119     Mutex::Autolock autoLock(mMuxerLock);
    120 
    121     if (mState == STARTED) {
    122         mState = STOPPED;
    123         for (size_t i = 0; i < mTrackList.size(); i++) {
    124             if (mTrackList[i]->stop() != OK) {
    125                 return INVALID_OPERATION;
    126             }
    127         }
    128         return mWriter->stop();
    129     } else {
    130         ALOGE("stop() is called in invalid state %d", mState);
    131         return INVALID_OPERATION;
    132     }
    133 }
    134 
    135 status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackIndex,
    136                                      int64_t timeUs, uint32_t flags) {
    137     Mutex::Autolock autoLock(mMuxerLock);
    138 
    139     if (buffer.get() == NULL) {
    140         ALOGE("WriteSampleData() get an NULL buffer.");
    141         return -EINVAL;
    142     }
    143 
    144     if (mState != STARTED) {
    145         ALOGE("WriteSampleData() is called in invalid state %d", mState);
    146         return INVALID_OPERATION;
    147     }
    148 
    149     if (trackIndex >= mTrackList.size()) {
    150         ALOGE("WriteSampleData() get an invalid index %d", trackIndex);
    151         return -EINVAL;
    152     }
    153 
    154     MediaBuffer* mediaBuffer = new MediaBuffer(buffer);
    155 
    156     mediaBuffer->add_ref(); // Released in MediaAdapter::signalBufferReturned().
    157     mediaBuffer->set_range(buffer->offset(), buffer->size());
    158 
    159     sp<MetaData> sampleMetaData = mediaBuffer->meta_data();
    160     sampleMetaData->setInt64(kKeyTime, timeUs);
    161     // Just set the kKeyDecodingTime as the presentation time for now.
    162     sampleMetaData->setInt64(kKeyDecodingTime, timeUs);
    163 
    164     if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
    165         sampleMetaData->setInt32(kKeyIsSyncFrame, true);
    166     }
    167 
    168     sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
    169     // This pushBuffer will wait until the mediaBuffer is consumed.
    170     return currentTrack->pushBuffer(mediaBuffer);
    171 }
    172 
    173 }  // namespace android
    174