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