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