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