MediaCodecSource.cpp revision e2a2dfcbf0c9d6bb7139263ecf0d8e53b4ca1049
1/*
2 * Copyright 2014, 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 "MediaCodecSource"
19#define DEBUG_DRIFT_TIME 0
20
21#include <inttypes.h>
22
23#include <gui/IGraphicBufferConsumer.h>
24#include <gui/IGraphicBufferProducer.h>
25#include <gui/Surface.h>
26#include <media/ICrypto.h>
27#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/ALooper.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/MediaBuffer.h>
32#include <media/stagefright/MediaCodec.h>
33#include <media/stagefright/MediaCodecSource.h>
34#include <media/stagefright/MediaErrors.h>
35#include <media/stagefright/MediaSource.h>
36#include <media/stagefright/MetaData.h>
37#include <media/stagefright/PersistentSurface.h>
38#include <media/stagefright/Utils.h>
39
40namespace android {
41
42struct MediaCodecSource::Puller : public AHandler {
43    Puller(const sp<MediaSource> &source);
44
45    status_t start(const sp<MetaData> &meta, const sp<AMessage> &notify);
46    void stop();
47
48    void pause();
49    void resume();
50
51protected:
52    virtual void onMessageReceived(const sp<AMessage> &msg);
53    virtual ~Puller();
54
55private:
56    enum {
57        kWhatStart = 'msta',
58        kWhatStop,
59        kWhatPull,
60        kWhatPause,
61        kWhatResume,
62    };
63
64    sp<MediaSource> mSource;
65    sp<AMessage> mNotify;
66    sp<ALooper> mLooper;
67    int32_t mPullGeneration;
68    bool mIsAudio;
69    bool mPaused;
70    bool mReachedEOS;
71
72    status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
73    void schedulePull();
74    void handleEOS();
75
76    DISALLOW_EVIL_CONSTRUCTORS(Puller);
77};
78
79MediaCodecSource::Puller::Puller(const sp<MediaSource> &source)
80    : mSource(source),
81      mLooper(new ALooper()),
82      mPullGeneration(0),
83      mIsAudio(false),
84      mPaused(false),
85      mReachedEOS(false) {
86    sp<MetaData> meta = source->getFormat();
87    const char *mime;
88    CHECK(meta->findCString(kKeyMIMEType, &mime));
89
90    mIsAudio = !strncasecmp(mime, "audio/", 6);
91
92    mLooper->setName("pull_looper");
93}
94
95MediaCodecSource::Puller::~Puller() {
96    mLooper->unregisterHandler(id());
97    mLooper->stop();
98}
99
100status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError(
101        const sp<AMessage> &msg) {
102    sp<AMessage> response;
103    status_t err = msg->postAndAwaitResponse(&response);
104
105    if (err != OK) {
106        return err;
107    }
108
109    if (!response->findInt32("err", &err)) {
110        err = OK;
111    }
112
113    return err;
114}
115
116status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta,
117        const sp<AMessage> &notify) {
118    ALOGV("puller (%s) start", mIsAudio ? "audio" : "video");
119    mLooper->start(
120            false /* runOnCallingThread */,
121            false /* canCallJava */,
122            PRIORITY_AUDIO);
123    mLooper->registerHandler(this);
124    mNotify = notify;
125
126    sp<AMessage> msg = new AMessage(kWhatStart, this);
127    msg->setObject("meta", meta);
128    return postSynchronouslyAndReturnError(msg);
129}
130
131void MediaCodecSource::Puller::stop() {
132    // Stop source from caller's thread instead of puller's looper.
133    // mSource->stop() is thread-safe, doing it outside the puller's
134    // looper allows us to at least stop if source gets stuck.
135    // If source gets stuck in read(), the looper would never
136    // be able to process the stop(), which could lead to ANR.
137
138    ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
139    mSource->stop();
140    ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
141
142    (new AMessage(kWhatStop, this))->post();
143}
144
145void MediaCodecSource::Puller::pause() {
146    (new AMessage(kWhatPause, this))->post();
147}
148
149void MediaCodecSource::Puller::resume() {
150    (new AMessage(kWhatResume, this))->post();
151}
152
153void MediaCodecSource::Puller::schedulePull() {
154    sp<AMessage> msg = new AMessage(kWhatPull, this);
155    msg->setInt32("generation", mPullGeneration);
156    msg->post();
157}
158
159void MediaCodecSource::Puller::handleEOS() {
160    if (!mReachedEOS) {
161        ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video");
162        mReachedEOS = true;
163        sp<AMessage> notify = mNotify->dup();
164        notify->setPointer("accessUnit", NULL);
165        notify->post();
166    }
167}
168
169void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) {
170    switch (msg->what()) {
171        case kWhatStart:
172        {
173            sp<RefBase> obj;
174            CHECK(msg->findObject("meta", &obj));
175
176            mReachedEOS = false;
177
178            status_t err = mSource->start(static_cast<MetaData *>(obj.get()));
179
180            if (err == OK) {
181                schedulePull();
182            }
183
184            sp<AMessage> response = new AMessage;
185            response->setInt32("err", err);
186
187            sp<AReplyToken> replyID;
188            CHECK(msg->senderAwaitsResponse(&replyID));
189            response->postReply(replyID);
190            break;
191        }
192
193        case kWhatStop:
194        {
195            ++mPullGeneration;
196
197            handleEOS();
198            break;
199        }
200
201        case kWhatPull:
202        {
203            int32_t generation;
204            CHECK(msg->findInt32("generation", &generation));
205
206            if (generation != mPullGeneration) {
207                break;
208            }
209
210            MediaBuffer *mbuf;
211            status_t err = mSource->read(&mbuf);
212
213            if (mPaused) {
214                if (err == OK) {
215                    mbuf->release();
216                    mbuf = NULL;
217                }
218
219                msg->post();
220                break;
221            }
222
223            if (err != OK) {
224                if (err == ERROR_END_OF_STREAM) {
225                    ALOGV("stream ended, mbuf %p", mbuf);
226                } else {
227                    ALOGE("error %d reading stream.", err);
228                }
229                handleEOS();
230            } else {
231                sp<AMessage> notify = mNotify->dup();
232
233                notify->setPointer("accessUnit", mbuf);
234                notify->post();
235
236                msg->post();
237            }
238            break;
239        }
240
241        case kWhatPause:
242        {
243            mPaused = true;
244            break;
245        }
246
247        case kWhatResume:
248        {
249            mPaused = false;
250            break;
251        }
252
253        default:
254            TRESPASS();
255    }
256}
257
258// static
259sp<MediaCodecSource> MediaCodecSource::Create(
260        const sp<ALooper> &looper,
261        const sp<AMessage> &format,
262        const sp<MediaSource> &source,
263        const sp<IGraphicBufferConsumer> &consumer,
264        uint32_t flags) {
265    sp<MediaCodecSource> mediaSource =
266            new MediaCodecSource(looper, format, source, consumer, flags);
267
268    if (mediaSource->init() == OK) {
269        return mediaSource;
270    }
271    return NULL;
272}
273
274status_t MediaCodecSource::start(MetaData* params) {
275    sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
276    msg->setObject("meta", params);
277    return postSynchronouslyAndReturnError(msg);
278}
279
280status_t MediaCodecSource::stop() {
281    sp<AMessage> msg = new AMessage(kWhatStop, mReflector);
282    status_t err = postSynchronouslyAndReturnError(msg);
283
284    // mPuller->stop() needs to be done outside MediaCodecSource's looper,
285    // as it contains a synchronous call to stop the underlying MediaSource,
286    // which often waits for all outstanding MediaBuffers to return, but
287    // MediaBuffers are only returned when MediaCodecSource looper gets
288    // to process them.
289
290    if (mPuller != NULL) {
291        ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio");
292        mPuller->stop();
293        ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio");
294    }
295
296    return err;
297}
298
299status_t MediaCodecSource::pause() {
300    (new AMessage(kWhatPause, mReflector))->post();
301    return OK;
302}
303
304sp<IGraphicBufferProducer> MediaCodecSource::getGraphicBufferProducer() {
305    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
306    return mGraphicBufferProducer;
307}
308
309status_t MediaCodecSource::read(
310        MediaBuffer** buffer, const ReadOptions* /* options */) {
311    Mutex::Autolock autolock(mOutputBufferLock);
312
313    *buffer = NULL;
314    while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) {
315        mOutputBufferCond.wait(mOutputBufferLock);
316    }
317    if (!mEncoderReachedEOS) {
318        *buffer = *mOutputBufferQueue.begin();
319        mOutputBufferQueue.erase(mOutputBufferQueue.begin());
320        return OK;
321    }
322    return mErrorCode;
323}
324
325void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) {
326    buffer->setObserver(0);
327    buffer->release();
328}
329
330MediaCodecSource::MediaCodecSource(
331        const sp<ALooper> &looper,
332        const sp<AMessage> &outputFormat,
333        const sp<MediaSource> &source,
334        const sp<IGraphicBufferConsumer> &consumer,
335        uint32_t flags)
336    : mLooper(looper),
337      mOutputFormat(outputFormat),
338      mMeta(new MetaData),
339      mFlags(flags),
340      mIsVideo(false),
341      mStarted(false),
342      mStopping(false),
343      mDoMoreWorkPending(false),
344      mGraphicBufferConsumer(consumer),
345      mFirstSampleTimeUs(-1ll),
346      mEncoderReachedEOS(false),
347      mErrorCode(OK) {
348    CHECK(mLooper != NULL);
349
350    AString mime;
351    CHECK(mOutputFormat->findString("mime", &mime));
352
353    if (!strncasecmp("video/", mime.c_str(), 6)) {
354        mIsVideo = true;
355    }
356
357    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
358        mPuller = new Puller(source);
359    }
360}
361
362MediaCodecSource::~MediaCodecSource() {
363    releaseEncoder();
364
365    mCodecLooper->stop();
366    mLooper->unregisterHandler(mReflector->id());
367}
368
369status_t MediaCodecSource::init() {
370    status_t err = initEncoder();
371
372    if (err != OK) {
373        releaseEncoder();
374    }
375
376    return err;
377}
378
379status_t MediaCodecSource::initEncoder() {
380    mReflector = new AHandlerReflector<MediaCodecSource>(this);
381    mLooper->registerHandler(mReflector);
382
383    mCodecLooper = new ALooper;
384    mCodecLooper->setName("codec_looper");
385    mCodecLooper->start();
386
387    if (mFlags & FLAG_USE_METADATA_INPUT) {
388        mOutputFormat->setInt32("store-metadata-in-buffers", 1);
389    }
390
391    if (mFlags & FLAG_USE_SURFACE_INPUT) {
392        mOutputFormat->setInt32("create-input-buffers-suspended", 1);
393    }
394
395    AString outputMIME;
396    CHECK(mOutputFormat->findString("mime", &outputMIME));
397
398    mEncoder = MediaCodec::CreateByType(
399            mCodecLooper, outputMIME.c_str(), true /* encoder */);
400
401    if (mEncoder == NULL) {
402        return NO_INIT;
403    }
404
405    ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
406
407    mEncoderActivityNotify = new AMessage(kWhatEncoderActivity, mReflector);
408    mEncoder->setCallback(mEncoderActivityNotify);
409
410    status_t err = mEncoder->configure(
411                mOutputFormat,
412                NULL /* nativeWindow */,
413                NULL /* crypto */,
414                MediaCodec::CONFIGURE_FLAG_ENCODE);
415
416    if (err != OK) {
417        return err;
418    }
419
420    mEncoder->getOutputFormat(&mOutputFormat);
421    convertMessageToMetaData(mOutputFormat, mMeta);
422
423    if (mFlags & FLAG_USE_SURFACE_INPUT) {
424        CHECK(mIsVideo);
425
426        if (mGraphicBufferConsumer != NULL) {
427            // When using persistent surface, we are only interested in the
428            // consumer, but have to use PersistentSurface as a wrapper to
429            // pass consumer over messages (similar to BufferProducerWrapper)
430            err = mEncoder->usePersistentInputSurface(
431                    new PersistentSurface(NULL, mGraphicBufferConsumer));
432        } else {
433            err = mEncoder->createInputSurface(&mGraphicBufferProducer);
434        }
435
436        if (err != OK) {
437            return err;
438        }
439    }
440
441    err = mEncoder->start();
442
443    if (err != OK) {
444        return err;
445    }
446
447    mEncoderReachedEOS = false;
448    mErrorCode = OK;
449
450    return OK;
451}
452
453void MediaCodecSource::releaseEncoder() {
454    if (mEncoder == NULL) {
455        return;
456    }
457
458    mEncoder->release();
459    mEncoder.clear();
460
461    while (!mInputBufferQueue.empty()) {
462        MediaBuffer *mbuf = *mInputBufferQueue.begin();
463        mInputBufferQueue.erase(mInputBufferQueue.begin());
464        if (mbuf != NULL) {
465            mbuf->release();
466        }
467    }
468}
469
470status_t MediaCodecSource::postSynchronouslyAndReturnError(
471        const sp<AMessage> &msg) {
472    sp<AMessage> response;
473    status_t err = msg->postAndAwaitResponse(&response);
474
475    if (err != OK) {
476        return err;
477    }
478
479    if (!response->findInt32("err", &err)) {
480        err = OK;
481    }
482
483    return err;
484}
485
486void MediaCodecSource::signalEOS(status_t err) {
487    if (!mEncoderReachedEOS) {
488        ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
489        {
490            Mutex::Autolock autoLock(mOutputBufferLock);
491            // release all unread media buffers
492            for (List<MediaBuffer*>::iterator it = mOutputBufferQueue.begin();
493                    it != mOutputBufferQueue.end(); it++) {
494                (*it)->release();
495            }
496            mOutputBufferQueue.clear();
497            mEncoderReachedEOS = true;
498            mErrorCode = err;
499            mOutputBufferCond.signal();
500        }
501
502        releaseEncoder();
503    }
504    if (mStopping && mEncoderReachedEOS) {
505        ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
506        // posting reply to everyone that's waiting
507        List<sp<AReplyToken>>::iterator it;
508        for (it = mStopReplyIDQueue.begin();
509                it != mStopReplyIDQueue.end(); it++) {
510            (new AMessage)->postReply(*it);
511        }
512        mStopReplyIDQueue.clear();
513        mStopping = false;
514    }
515}
516
517void MediaCodecSource::suspend() {
518    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
519    if (mEncoder != NULL) {
520        sp<AMessage> params = new AMessage;
521        params->setInt32("drop-input-frames", true);
522        mEncoder->setParameters(params);
523    }
524}
525
526void MediaCodecSource::resume(int64_t skipFramesBeforeUs) {
527    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
528    if (mEncoder != NULL) {
529        sp<AMessage> params = new AMessage;
530        params->setInt32("drop-input-frames", false);
531        if (skipFramesBeforeUs > 0) {
532            params->setInt64("skip-frames-before", skipFramesBeforeUs);
533        }
534        mEncoder->setParameters(params);
535    }
536}
537
538status_t MediaCodecSource::feedEncoderInputBuffers() {
539    while (!mInputBufferQueue.empty()
540            && !mAvailEncoderInputIndices.empty()) {
541        MediaBuffer* mbuf = *mInputBufferQueue.begin();
542        mInputBufferQueue.erase(mInputBufferQueue.begin());
543
544        size_t bufferIndex = *mAvailEncoderInputIndices.begin();
545        mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
546
547        int64_t timeUs = 0ll;
548        uint32_t flags = 0;
549        size_t size = 0;
550
551        if (mbuf != NULL) {
552            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
553
554            // push decoding time for video, or drift time for audio
555            if (mIsVideo) {
556                mDecodingTimeQueue.push_back(timeUs);
557            } else {
558#if DEBUG_DRIFT_TIME
559                if (mFirstSampleTimeUs < 0ll) {
560                    mFirstSampleTimeUs = timeUs;
561                }
562
563                int64_t driftTimeUs = 0;
564                if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs)
565                        && driftTimeUs) {
566                    driftTimeUs = timeUs - mFirstSampleTimeUs - driftTimeUs;
567                }
568                mDriftTimeQueue.push_back(driftTimeUs);
569#endif // DEBUG_DRIFT_TIME
570            }
571
572            sp<ABuffer> inbuf;
573            status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
574            if (err != OK || inbuf == NULL) {
575                mbuf->release();
576                signalEOS();
577                break;
578            }
579
580            size = mbuf->size();
581
582            memcpy(inbuf->data(), mbuf->data(), size);
583
584            if (mIsVideo) {
585                // video encoder will release MediaBuffer when done
586                // with underlying data.
587                inbuf->setMediaBufferBase(mbuf);
588            } else {
589                mbuf->release();
590            }
591        } else {
592            flags = MediaCodec::BUFFER_FLAG_EOS;
593        }
594
595        status_t err = mEncoder->queueInputBuffer(
596                bufferIndex, 0, size, timeUs, flags);
597
598        if (err != OK) {
599            return err;
600        }
601    }
602
603    return OK;
604}
605
606status_t MediaCodecSource::onStart(MetaData *params) {
607    if (mStopping) {
608        ALOGE("Failed to start while we're stopping");
609        return INVALID_OPERATION;
610    }
611
612    if (mStarted) {
613        ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
614        if (mFlags & FLAG_USE_SURFACE_INPUT) {
615            resume();
616        } else {
617            CHECK(mPuller != NULL);
618            mPuller->resume();
619        }
620        return OK;
621    }
622
623    ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio");
624
625    status_t err = OK;
626
627    if (mFlags & FLAG_USE_SURFACE_INPUT) {
628        int64_t startTimeUs;
629        if (!params || !params->findInt64(kKeyTime, &startTimeUs)) {
630            startTimeUs = -1ll;
631        }
632        resume(startTimeUs);
633    } else {
634        CHECK(mPuller != NULL);
635        sp<AMessage> notify = new AMessage(kWhatPullerNotify, mReflector);
636        err = mPuller->start(params, notify);
637        if (err != OK) {
638            return err;
639        }
640    }
641
642    ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio");
643
644    mStarted = true;
645    return OK;
646}
647
648void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
649    switch (msg->what()) {
650    case kWhatPullerNotify:
651    {
652        MediaBuffer *mbuf;
653        CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
654
655        if (mbuf == NULL) {
656            ALOGV("puller (%s) reached EOS",
657                    mIsVideo ? "video" : "audio");
658            signalEOS();
659        }
660
661        if (mEncoder == NULL) {
662            ALOGV("got msg '%s' after encoder shutdown.",
663                  msg->debugString().c_str());
664
665            if (mbuf != NULL) {
666                mbuf->release();
667            }
668
669            break;
670        }
671
672        mInputBufferQueue.push_back(mbuf);
673
674        feedEncoderInputBuffers();
675
676        break;
677    }
678    case kWhatEncoderActivity:
679    {
680        if (mEncoder == NULL) {
681            break;
682        }
683
684        int32_t cbID;
685        CHECK(msg->findInt32("callbackID", &cbID));
686        if (cbID == MediaCodec::CB_INPUT_AVAILABLE) {
687            int32_t index;
688            CHECK(msg->findInt32("index", &index));
689
690            mAvailEncoderInputIndices.push_back(index);
691            feedEncoderInputBuffers();
692        } else if (cbID == MediaCodec::CB_OUTPUT_AVAILABLE) {
693            int32_t index;
694            size_t offset;
695            size_t size;
696            int64_t timeUs;
697            int32_t flags;
698
699            CHECK(msg->findInt32("index", &index));
700            CHECK(msg->findSize("offset", &offset));
701            CHECK(msg->findSize("size", &size));
702            CHECK(msg->findInt64("timeUs", &timeUs));
703            CHECK(msg->findInt32("flags", &flags));
704
705            if (flags & MediaCodec::BUFFER_FLAG_EOS) {
706                mEncoder->releaseOutputBuffer(index);
707                signalEOS();
708                break;
709            }
710
711            sp<ABuffer> outbuf;
712            status_t err = mEncoder->getOutputBuffer(index, &outbuf);
713            if (err != OK || outbuf == NULL) {
714                signalEOS();
715                break;
716            }
717
718            MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
719            memcpy(mbuf->data(), outbuf->data(), outbuf->size());
720
721            if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
722                if (mIsVideo) {
723                    int64_t decodingTimeUs;
724                    if (mFlags & FLAG_USE_SURFACE_INPUT) {
725                        // GraphicBufferSource is supposed to discard samples
726                        // queued before start, and offset timeUs by start time
727                        CHECK_GE(timeUs, 0ll);
728                        // TODO:
729                        // Decoding time for surface source is unavailable,
730                        // use presentation time for now. May need to move
731                        // this logic into MediaCodec.
732                        decodingTimeUs = timeUs;
733                    } else {
734                        CHECK(!mDecodingTimeQueue.empty());
735                        decodingTimeUs = *(mDecodingTimeQueue.begin());
736                        mDecodingTimeQueue.erase(mDecodingTimeQueue.begin());
737                    }
738                    mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
739
740                    ALOGV("[video] time %" PRId64 " us (%.2f secs), dts/pts diff %" PRId64,
741                            timeUs, timeUs / 1E6, decodingTimeUs - timeUs);
742                } else {
743                    int64_t driftTimeUs = 0;
744#if DEBUG_DRIFT_TIME
745                    CHECK(!mDriftTimeQueue.empty());
746                    driftTimeUs = *(mDriftTimeQueue.begin());
747                    mDriftTimeQueue.erase(mDriftTimeQueue.begin());
748                    mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs);
749#endif // DEBUG_DRIFT_TIME
750                    ALOGV("[audio] time %" PRId64 " us (%.2f secs), drift %" PRId64,
751                            timeUs, timeUs / 1E6, driftTimeUs);
752                }
753                mbuf->meta_data()->setInt64(kKeyTime, timeUs);
754            } else {
755                mbuf->meta_data()->setInt32(kKeyIsCodecConfig, true);
756            }
757            if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
758                mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
759            }
760            mbuf->setObserver(this);
761            mbuf->add_ref();
762
763            {
764                Mutex::Autolock autoLock(mOutputBufferLock);
765                mOutputBufferQueue.push_back(mbuf);
766                mOutputBufferCond.signal();
767            }
768
769            mEncoder->releaseOutputBuffer(index);
770       } else if (cbID == MediaCodec::CB_ERROR) {
771            status_t err;
772            CHECK(msg->findInt32("err", &err));
773            ALOGE("Encoder (%s) reported error : 0x%x",
774                    mIsVideo ? "video" : "audio", err);
775            signalEOS();
776       }
777       break;
778    }
779    case kWhatStart:
780    {
781        sp<AReplyToken> replyID;
782        CHECK(msg->senderAwaitsResponse(&replyID));
783
784        sp<RefBase> obj;
785        CHECK(msg->findObject("meta", &obj));
786        MetaData *params = static_cast<MetaData *>(obj.get());
787
788        sp<AMessage> response = new AMessage;
789        response->setInt32("err", onStart(params));
790        response->postReply(replyID);
791        break;
792    }
793    case kWhatStop:
794    {
795        ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
796
797        sp<AReplyToken> replyID;
798        CHECK(msg->senderAwaitsResponse(&replyID));
799
800        if (mEncoderReachedEOS) {
801            // if we already reached EOS, reply and return now
802            ALOGI("encoder (%s) already stopped",
803                    mIsVideo ? "video" : "audio");
804            (new AMessage)->postReply(replyID);
805            break;
806        }
807
808        mStopReplyIDQueue.push_back(replyID);
809        if (mStopping) {
810            // nothing to do if we're already stopping, reply will be posted
811            // to all when we're stopped.
812            break;
813        }
814
815        mStopping = true;
816
817        // if using surface, signal source EOS and wait for EOS to come back.
818        // otherwise, release encoder and post EOS if haven't done already
819        if (mFlags & FLAG_USE_SURFACE_INPUT) {
820            mEncoder->signalEndOfInputStream();
821        } else {
822            signalEOS();
823        }
824        break;
825    }
826    case kWhatPause:
827    {
828        if (mFlags && FLAG_USE_SURFACE_INPUT) {
829            suspend();
830        } else {
831            CHECK(mPuller != NULL);
832            mPuller->pause();
833        }
834        break;
835    }
836    default:
837        TRESPASS();
838    }
839}
840
841} // namespace android
842