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