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