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::setLocation(int latitude, int longitude) {
    107     Mutex::Autolock autoLock(mMuxerLock);
    108     if (mState != INITIALIZED) {
    109         ALOGE("setLocation() must be called before start().");
    110         return INVALID_OPERATION;
    111     }
    112     ALOGV("Setting location: latitude = %d, longitude = %d", latitude, longitude);
    113     return mWriter->setGeoData(latitude, longitude);
    114 }
    115 
    116 status_t MediaMuxer::start() {
    117     Mutex::Autolock autoLock(mMuxerLock);
    118     if (mState == INITIALIZED) {
    119         mState = STARTED;
    120         mFileMeta->setInt32(kKeyRealTimeRecording, false);
    121         return mWriter->start(mFileMeta.get());
    122     } else {
    123         ALOGE("start() is called in invalid state %d", mState);
    124         return INVALID_OPERATION;
    125     }
    126 }
    127 
    128 status_t MediaMuxer::stop() {
    129     Mutex::Autolock autoLock(mMuxerLock);
    130 
    131     if (mState == STARTED) {
    132         mState = STOPPED;
    133         for (size_t i = 0; i < mTrackList.size(); i++) {
    134             if (mTrackList[i]->stop() != OK) {
    135                 return INVALID_OPERATION;
    136             }
    137         }
    138         return mWriter->stop();
    139     } else {
    140         ALOGE("stop() is called in invalid state %d", mState);
    141         return INVALID_OPERATION;
    142     }
    143 }
    144 
    145 status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackIndex,
    146                                      int64_t timeUs, uint32_t flags) {
    147     Mutex::Autolock autoLock(mMuxerLock);
    148 
    149     if (buffer.get() == NULL) {
    150         ALOGE("WriteSampleData() get an NULL buffer.");
    151         return -EINVAL;
    152     }
    153 
    154     if (mState != STARTED) {
    155         ALOGE("WriteSampleData() is called in invalid state %d", mState);
    156         return INVALID_OPERATION;
    157     }
    158 
    159     if (trackIndex >= mTrackList.size()) {
    160         ALOGE("WriteSampleData() get an invalid index %d", trackIndex);
    161         return -EINVAL;
    162     }
    163 
    164     MediaBuffer* mediaBuffer = new MediaBuffer(buffer);
    165 
    166     mediaBuffer->add_ref(); // Released in MediaAdapter::signalBufferReturned().
    167     mediaBuffer->set_range(buffer->offset(), buffer->size());
    168 
    169     sp<MetaData> sampleMetaData = mediaBuffer->meta_data();
    170     sampleMetaData->setInt64(kKeyTime, timeUs);
    171     // Just set the kKeyDecodingTime as the presentation time for now.
    172     sampleMetaData->setInt64(kKeyDecodingTime, timeUs);
    173 
    174     if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
    175         sampleMetaData->setInt32(kKeyIsSyncFrame, true);
    176     }
    177 
    178     sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
    179     // This pushBuffer will wait until the mediaBuffer is consumed.
    180     return currentTrack->pushBuffer(mediaBuffer);
    181 }
    182 
    183 }  // namespace android
    184