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