Converter.cpp revision 4a8b9a2363b7b7b4f98022e6d9aae8b8aa8e35e5
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 "MediaPuller.h"
24
25#include <cutils/properties.h>
26#include <gui/SurfaceTextureClient.h>
27#include <media/ICrypto.h>
28#include <media/stagefright/foundation/ABuffer.h>
29#include <media/stagefright/foundation/ADebug.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/MediaBuffer.h>
32#include <media/stagefright/MediaCodec.h>
33#include <media/stagefright/MediaDefs.h>
34#include <media/stagefright/MediaErrors.h>
35
36namespace android {
37
38Converter::Converter(
39        const sp<AMessage> &notify,
40        const sp<ALooper> &codecLooper,
41        const sp<AMessage> &format)
42    : mInitCheck(NO_INIT),
43      mNotify(notify),
44      mCodecLooper(codecLooper),
45      mInputFormat(format),
46      mIsVideo(false),
47      mDoMoreWorkPending(false) {
48    AString mime;
49    CHECK(mInputFormat->findString("mime", &mime));
50
51    if (!strncasecmp("video/", mime.c_str(), 6)) {
52        mIsVideo = true;
53    }
54
55    mInitCheck = initEncoder();
56
57    if (mInitCheck != OK) {
58        if (mEncoder != NULL) {
59            mEncoder->release();
60            mEncoder.clear();
61        }
62    }
63}
64
65Converter::~Converter() {
66    CHECK(mEncoder == NULL);
67}
68
69void Converter::shutdownAsync() {
70    ALOGV("shutdown");
71    (new AMessage(kWhatShutdown, id()))->post();
72}
73
74status_t Converter::initCheck() const {
75    return mInitCheck;
76}
77
78size_t Converter::getInputBufferCount() const {
79    return mEncoderInputBuffers.size();
80}
81
82sp<AMessage> Converter::getOutputFormat() const {
83    return mOutputFormat;
84}
85
86static int32_t getBitrate(const char *propName, int32_t defaultValue) {
87    char val[PROPERTY_VALUE_MAX];
88    if (property_get(propName, val, NULL)) {
89        char *end;
90        unsigned long x = strtoul(val, &end, 10);
91
92        if (*end == '\0' && end > val && x > 0) {
93            return x;
94        }
95    }
96
97    return defaultValue;
98}
99
100status_t Converter::initEncoder() {
101    AString inputMIME;
102    CHECK(mInputFormat->findString("mime", &inputMIME));
103
104    AString outputMIME;
105    bool isAudio = false;
106    if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_AUDIO_RAW)) {
107        outputMIME = MEDIA_MIMETYPE_AUDIO_AAC;
108        isAudio = true;
109    } else if (!strcasecmp(inputMIME.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
110        outputMIME = MEDIA_MIMETYPE_VIDEO_AVC;
111    } else {
112        TRESPASS();
113    }
114
115    mEncoder = MediaCodec::CreateByType(
116            mCodecLooper, outputMIME.c_str(), true /* encoder */);
117
118    if (mEncoder == NULL) {
119        return ERROR_UNSUPPORTED;
120    }
121
122    mOutputFormat = mInputFormat->dup();
123    mOutputFormat->setString("mime", outputMIME.c_str());
124
125    int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
126    int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
127
128    ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
129          audioBitrate, videoBitrate);
130
131    if (isAudio) {
132        mOutputFormat->setInt32("bitrate", audioBitrate);
133    } else {
134        mOutputFormat->setInt32("bitrate", videoBitrate);
135        mOutputFormat->setInt32("frame-rate", 30);
136        mOutputFormat->setInt32("i-frame-interval", 1);  // Iframes every 1 secs
137        mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1);
138    }
139
140    ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
141
142    status_t err = mEncoder->configure(
143            mOutputFormat,
144            NULL /* nativeWindow */,
145            NULL /* crypto */,
146            MediaCodec::CONFIGURE_FLAG_ENCODE);
147
148    if (err != OK) {
149        return err;
150    }
151
152    err = mEncoder->start();
153
154    if (err != OK) {
155        return err;
156    }
157
158    err = mEncoder->getInputBuffers(&mEncoderInputBuffers);
159
160    if (err != OK) {
161        return err;
162    }
163
164    return mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
165}
166
167void Converter::notifyError(status_t err) {
168    sp<AMessage> notify = mNotify->dup();
169    notify->setInt32("what", kWhatError);
170    notify->setInt32("err", err);
171    notify->post();
172}
173
174void Converter::onMessageReceived(const sp<AMessage> &msg) {
175    switch (msg->what()) {
176        case kWhatMediaPullerNotify:
177        {
178            int32_t what;
179            CHECK(msg->findInt32("what", &what));
180
181            if (mEncoder == NULL) {
182                ALOGV("got msg '%s' after encoder shutdown.",
183                      msg->debugString().c_str());
184
185                if (what == MediaPuller::kWhatAccessUnit) {
186                    sp<ABuffer> accessUnit;
187                    CHECK(msg->findBuffer("accessUnit", &accessUnit));
188
189                    void *mbuf;
190                    if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
191                            && mbuf != NULL) {
192                        ALOGV("releasing mbuf %p", mbuf);
193
194                        accessUnit->meta()->setPointer("mediaBuffer", NULL);
195
196                        static_cast<MediaBuffer *>(mbuf)->release();
197                        mbuf = NULL;
198                    }
199                }
200                break;
201            }
202
203            if (what == MediaPuller::kWhatEOS) {
204                mInputBufferQueue.push_back(NULL);
205
206                feedEncoderInputBuffers();
207
208                scheduleDoMoreWork();
209            } else {
210                CHECK_EQ(what, MediaPuller::kWhatAccessUnit);
211
212                sp<ABuffer> accessUnit;
213                CHECK(msg->findBuffer("accessUnit", &accessUnit));
214
215#if 0
216                void *mbuf;
217                if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
218                        && mbuf != NULL) {
219                    ALOGI("queueing mbuf %p", mbuf);
220                }
221#endif
222
223                mInputBufferQueue.push_back(accessUnit);
224
225                feedEncoderInputBuffers();
226
227                scheduleDoMoreWork();
228            }
229            break;
230        }
231
232        case kWhatDoMoreWork:
233        {
234            mDoMoreWorkPending = false;
235
236            if (mEncoder == NULL) {
237                break;
238            }
239
240            status_t err = doMoreWork();
241
242            if (err != OK) {
243                notifyError(err);
244            } else {
245                scheduleDoMoreWork();
246            }
247            break;
248        }
249
250        case kWhatRequestIDRFrame:
251        {
252            if (mEncoder == NULL) {
253                break;
254            }
255
256            if (mIsVideo) {
257                ALOGI("requesting IDR frame");
258                mEncoder->requestIDRFrame();
259            }
260            break;
261        }
262
263        case kWhatShutdown:
264        {
265            ALOGI("shutting down encoder");
266            mEncoder->release();
267            mEncoder.clear();
268
269            AString mime;
270            CHECK(mInputFormat->findString("mime", &mime));
271            ALOGI("encoder (%s) shut down.", mime.c_str());
272            break;
273        }
274
275        default:
276            TRESPASS();
277    }
278}
279
280void Converter::scheduleDoMoreWork() {
281    if (mDoMoreWorkPending) {
282        return;
283    }
284
285    mDoMoreWorkPending = true;
286    (new AMessage(kWhatDoMoreWork, id()))->post(10000ll);
287}
288
289status_t Converter::feedEncoderInputBuffers() {
290    while (!mInputBufferQueue.empty()
291            && !mAvailEncoderInputIndices.empty()) {
292        sp<ABuffer> buffer = *mInputBufferQueue.begin();
293        mInputBufferQueue.erase(mInputBufferQueue.begin());
294
295        size_t bufferIndex = *mAvailEncoderInputIndices.begin();
296        mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
297
298        int64_t timeUs = 0ll;
299        uint32_t flags = 0;
300
301        if (buffer != NULL) {
302            CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
303
304            memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
305                   buffer->data(),
306                   buffer->size());
307
308            void *mediaBuffer;
309            if (buffer->meta()->findPointer("mediaBuffer", &mediaBuffer)
310                    && mediaBuffer != NULL) {
311                mEncoderInputBuffers.itemAt(bufferIndex)->meta()
312                    ->setPointer("mediaBuffer", mediaBuffer);
313
314                buffer->meta()->setPointer("mediaBuffer", NULL);
315            }
316        } else {
317            flags = MediaCodec::BUFFER_FLAG_EOS;
318        }
319
320        status_t err = mEncoder->queueInputBuffer(
321                bufferIndex, 0, (buffer == NULL) ? 0 : buffer->size(),
322                timeUs, flags);
323
324        if (err != OK) {
325            return err;
326        }
327    }
328
329    return OK;
330}
331
332status_t Converter::doMoreWork() {
333    size_t bufferIndex;
334    status_t err = mEncoder->dequeueInputBuffer(&bufferIndex);
335
336    if (err == OK) {
337        mAvailEncoderInputIndices.push_back(bufferIndex);
338        feedEncoderInputBuffers();
339    }
340
341    size_t offset;
342    size_t size;
343    int64_t timeUs;
344    uint32_t flags;
345    err = mEncoder->dequeueOutputBuffer(
346            &bufferIndex, &offset, &size, &timeUs, &flags);
347
348    if (err == OK) {
349        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
350            sp<AMessage> notify = mNotify->dup();
351            notify->setInt32("what", kWhatEOS);
352            notify->post();
353        } else {
354            sp<ABuffer> buffer = new ABuffer(size);
355            buffer->meta()->setInt64("timeUs", timeUs);
356
357            memcpy(buffer->data(),
358                   mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset,
359                   size);
360
361            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
362                mOutputFormat->setBuffer("csd-0", buffer);
363            } else {
364                sp<AMessage> notify = mNotify->dup();
365                notify->setInt32("what", kWhatAccessUnit);
366                notify->setBuffer("accessUnit", buffer);
367                notify->post();
368            }
369        }
370
371        err = mEncoder->releaseOutputBuffer(bufferIndex);
372    } else if (err == -EAGAIN) {
373        err = OK;
374    }
375
376    return err;
377}
378
379void Converter::requestIDRFrame() {
380    (new AMessage(kWhatRequestIDRFrame, id()))->post();
381}
382
383}  // namespace android
384