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