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