MediaMuxer.cpp revision 6269d53cce5c1c9350565d3d72d92116594260cb
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
36namespace android {
37
38MediaMuxer::MediaMuxer(const char* pathOut)
39    : mState(INITED) {
40    mWriter = new MPEG4Writer(pathOut);
41}
42
43MediaMuxer::MediaMuxer(int fd)
44    : mState(INITED) {
45    mWriter = new MPEG4Writer(fd);
46}
47
48MediaMuxer::~MediaMuxer() {
49    Mutex::Autolock autoLock(mMuxerLock);
50
51    // Clean up all the internal resources.
52    mWriter.clear();
53    mTrackList.clear();
54}
55
56ssize_t MediaMuxer::addTrack(const sp<AMessage> &format) {
57    Mutex::Autolock autoLock(mMuxerLock);
58
59    if (format.get() == NULL) {
60        ALOGE("addTrack() get a null format");
61        return -EINVAL;
62    }
63
64    if (mState != INITED) {
65        ALOGE("addTrack() must be called after constructor and before start().");
66        return INVALID_OPERATION;
67    }
68
69    sp<MetaData> meta = new MetaData;
70    convertMessageToMetaData(format, meta);
71
72    sp<MediaAdapter> newTrack = new MediaAdapter(meta);
73    return mTrackList.add(newTrack);
74}
75
76status_t MediaMuxer::start() {
77    Mutex::Autolock autoLock(mMuxerLock);
78
79    if (mState == INITED) {
80        mState = STARTED;
81        for (size_t i = 0 ; i < mTrackList.size(); i++) {
82            mWriter->addSource(mTrackList[i]);
83        }
84        return mWriter->start();
85    } else {
86        ALOGE("start() is called in invalid state %d", mState);
87        return INVALID_OPERATION;
88    }
89}
90
91status_t MediaMuxer::stop() {
92    Mutex::Autolock autoLock(mMuxerLock);
93
94    if (mState == STARTED) {
95        mState = STOPPED;
96        for (size_t i = 0; i < mTrackList.size(); i++) {
97            mTrackList[i]->stop();
98        }
99        return mWriter->stop();
100    } else {
101        ALOGE("stop() is called in invalid state %d", mState);
102        return INVALID_OPERATION;
103    }
104}
105
106status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackIndex,
107                                     int64_t timeUs, uint32_t flags) {
108    Mutex::Autolock autoLock(mMuxerLock);
109
110    sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
111
112    if (buffer.get() == NULL) {
113        ALOGE("WriteSampleData() get an NULL buffer.");
114        return -EINVAL;
115    }
116
117    if (mState != STARTED) {
118        ALOGE("WriteSampleData() is called in invalid state %d", mState);
119        return INVALID_OPERATION;
120    }
121
122    if (trackIndex >= mTrackList.size()) {
123        ALOGE("WriteSampleData() get an invalid index %d", trackIndex);
124        return -EINVAL;
125    }
126
127    MediaBuffer* mediaBuffer = new MediaBuffer(buffer);
128
129    mediaBuffer->add_ref(); // Released in MediaAdapter::signalBufferReturned().
130    mediaBuffer->set_range(buffer->offset(), buffer->size());
131
132    sp<MetaData> metaData = mediaBuffer->meta_data();
133    metaData->setInt64(kKeyTime, timeUs);
134    // Just set the kKeyDecodingTime as the presentation time for now.
135    metaData->setInt64(kKeyDecodingTime, timeUs);
136
137    if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
138        metaData->setInt32(kKeyIsSyncFrame, true);
139    }
140
141    // This pushBuffer will wait until the mediaBuffer is consumed.
142    return currentTrack->pushBuffer(mediaBuffer);
143}
144
145}  // namespace android
146