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