Converter.cpp revision e1957358f11031a554c57d4fb46988dd6044acc1
1/*
2 * Copyright 2012, 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 "Converter"
19#include <utils/Log.h>
20
21#include "Converter.h"
22
23#include <gui/SurfaceTextureClient.h>
24#include <media/ICrypto.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
28#include <media/stagefright/MediaCodec.h>
29#include <media/stagefright/MediaDefs.h>
30#include <media/stagefright/MediaErrors.h>
31
32namespace android {
33
34Converter::Converter(
35        const sp<AMessage> &notify,
36        const sp<ALooper> &codecLooper,
37        const sp<AMessage> &format)
38    : mInitCheck(NO_INIT),
39      mNotify(notify),
40      mCodecLooper(codecLooper),
41      mInputFormat(format),
42      mDoMoreWorkPending(false) {
43    mInitCheck = initEncoder();
44}
45
46Converter::~Converter() {
47    if (mEncoder != NULL) {
48        mEncoder->release();
49        mEncoder.clear();
50    }
51}
52
53status_t Converter::initCheck() const {
54    return mInitCheck;
55}
56
57size_t Converter::getInputBufferCount() const {
58    return mEncoderInputBuffers.size();
59}
60
61sp<AMessage> Converter::getOutputFormat() const {
62    return mOutputFormat;
63}
64
65status_t Converter::initEncoder() {
66    AString inputMIME;
67    CHECK(mInputFormat->findString("mime", &inputMIME));
68
69    AString outputMIME;
70    bool isAudio = false;
71    if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
72        outputMIME = MEDIA_MIMETYPE_AUDIO_AAC;
73        isAudio = true;
74    } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
75        outputMIME = MEDIA_MIMETYPE_VIDEO_AVC;
76    } else {
77        TRESPASS();
78    }
79
80    mEncoder = MediaCodec::CreateByType(
81            mCodecLooper, outputMIME.c_str(), true /* encoder */);
82
83    if (mEncoder == NULL) {
84        return ERROR_UNSUPPORTED;
85    }
86
87    mOutputFormat = mInputFormat->dup();
88    mOutputFormat->setString("mime", outputMIME.c_str());
89
90    if (isAudio) {
91        mOutputFormat->setInt32("bitrate", 64000);      // 64 kBit/sec
92    } else {
93        mOutputFormat->setInt32("bitrate", 10000000);    // 10Mbit/sec
94        mOutputFormat->setInt32("frame-rate", 60);
95        mOutputFormat->setInt32("i-frame-interval", 3);  // Iframes every 3 secs
96    }
97
98    ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
99
100    status_t err = mEncoder->configure(
101            mOutputFormat,
102            NULL /* nativeWindow */,
103            NULL /* crypto */,
104            MediaCodec::CONFIGURE_FLAG_ENCODE);
105
106    if (err != OK) {
107        return err;
108    }
109
110    err = mEncoder->start();
111
112    if (err != OK) {
113        return err;
114    }
115
116    err = mEncoder->getInputBuffers(&mEncoderInputBuffers);
117
118    if (err != OK) {
119        return err;
120    }
121
122    return mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
123}
124
125void Converter::feedAccessUnit(const sp<ABuffer> &accessUnit) {
126    sp<AMessage> msg = new AMessage(kWhatFeedAccessUnit, id());
127    msg->setBuffer("accessUnit", accessUnit);
128    msg->post();
129}
130
131void Converter::signalEOS() {
132    (new AMessage(kWhatInputEOS, id()))->post();
133}
134
135void Converter::notifyError(status_t err) {
136    sp<AMessage> notify = mNotify->dup();
137    notify->setInt32("what", kWhatError);
138    notify->setInt32("err", err);
139    notify->post();
140}
141
142void Converter::onMessageReceived(const sp<AMessage> &msg) {
143    switch (msg->what()) {
144        case kWhatFeedAccessUnit:
145        {
146            sp<ABuffer> accessUnit;
147            CHECK(msg->findBuffer("accessUnit", &accessUnit));
148
149            mInputBufferQueue.push_back(accessUnit);
150
151            feedEncoderInputBuffers();
152
153            scheduleDoMoreWork();
154            break;
155        }
156
157        case kWhatInputEOS:
158        {
159            mInputBufferQueue.push_back(NULL);
160
161            feedEncoderInputBuffers();
162
163            scheduleDoMoreWork();
164            break;
165        }
166
167        case kWhatDoMoreWork:
168        {
169            mDoMoreWorkPending = false;
170            status_t err = doMoreWork();
171
172            if (err != OK) {
173                notifyError(err);
174            } else {
175                scheduleDoMoreWork();
176            }
177            break;
178        }
179
180        default:
181            TRESPASS();
182    }
183}
184
185void Converter::scheduleDoMoreWork() {
186    if (mDoMoreWorkPending) {
187        return;
188    }
189
190    mDoMoreWorkPending = true;
191    (new AMessage(kWhatDoMoreWork, id()))->post(1000ll);
192}
193
194status_t Converter::feedEncoderInputBuffers() {
195    while (!mInputBufferQueue.empty()
196            && !mAvailEncoderInputIndices.empty()) {
197        sp<ABuffer> buffer = *mInputBufferQueue.begin();
198        mInputBufferQueue.erase(mInputBufferQueue.begin());
199
200        size_t bufferIndex = *mAvailEncoderInputIndices.begin();
201        mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
202
203        int64_t timeUs = 0ll;
204        uint32_t flags = 0;
205
206        if (buffer != NULL) {
207            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
208
209            memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
210                   buffer->data(),
211                   buffer->size());
212
213            void *mediaBuffer;
214            if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer)
215                    && mediaBuffer != NULL) {
216                mEncoderInputBuffers.itemAt(bufferIndex)->meta()
217                    ->setPointer("mediaBuffer", mediaBuffer);
218
219                buffer->meta()->setPointer("mediaBuffer", NULL);
220            }
221        } else {
222            flags = MediaCodec::BUFFER_FLAG_EOS;
223        }
224
225        status_t err = mEncoder->queueInputBuffer(
226                bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(),
227                timeUs, flags);
228
229        if (err != OK) {
230            return err;
231        }
232    }
233
234    return OK;
235}
236
237status_t Converter::doMoreWork() {
238    size_t bufferIndex;
239    status_t err = mEncoder->dequeueInputBuffer(&bufferIndex);
240
241    if (err == OK) {
242        mAvailEncoderInputIndices.push_back(bufferIndex);
243        feedEncoderInputBuffers();
244    }
245
246    size_t offset;
247    size_t size;
248    int64_t timeUs;
249    uint32_t flags;
250    err = mEncoder->dequeueOutputBuffer(
251            &bufferIndex, &offset, &size, &timeUs, &flags);
252
253    if (err == OK) {
254        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
255            sp<AMessage> notify = mNotify->dup();
256            notify->setInt32("what", kWhatEOS);
257            notify->post();
258        } else {
259            sp<ABuffer> buffer = new ABuffer(size);
260            buffer->meta()->setInt64("timeUs", timeUs);
261
262            memcpy(buffer->data(),
263                   mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset,
264                   size);
265
266            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
267                mOutputFormat->setBuffer("csd-0", buffer);
268            } else {
269                sp<AMessage> notify = mNotify->dup();
270                notify->setInt32("what", kWhatAccessUnit);
271                notify->setBuffer("accessUnit", buffer);
272                notify->post();
273            }
274        }
275
276        err = mEncoder->releaseOutputBuffer(bufferIndex);
277    } else if (err == -EAGAIN) {
278        err = OK;
279    }
280
281    return err;
282}
283
284}  // namespace android
285
286