MediaCodec.cpp revision 9e2b7918eb5621b24bd54c922f630da45339de77
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 "MediaCodec"
19#include <inttypes.h>
20
21#include "include/avc_utils.h"
22#include "include/SoftwareRenderer.h"
23
24#include <binder/IBatteryStats.h>
25#include <binder/IServiceManager.h>
26#include <gui/Surface.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/foundation/AString.h>
32#include <media/stagefright/foundation/hexdump.h>
33#include <media/stagefright/ACodec.h>
34#include <media/stagefright/BufferProducerWrapper.h>
35#include <media/stagefright/MediaCodec.h>
36#include <media/stagefright/MediaCodecList.h>
37#include <media/stagefright/MediaDefs.h>
38#include <media/stagefright/MediaErrors.h>
39#include <media/stagefright/MetaData.h>
40#include <media/stagefright/NativeWindowWrapper.h>
41#include <private/android_filesystem_config.h>
42#include <utils/Log.h>
43#include <utils/Singleton.h>
44
45namespace android {
46
47struct MediaCodec::BatteryNotifier : public Singleton<BatteryNotifier> {
48    BatteryNotifier();
49
50    void noteStartVideo();
51    void noteStopVideo();
52    void noteStartAudio();
53    void noteStopAudio();
54
55private:
56    int32_t mVideoRefCount;
57    int32_t mAudioRefCount;
58    sp<IBatteryStats> mBatteryStatService;
59};
60
61ANDROID_SINGLETON_STATIC_INSTANCE(MediaCodec::BatteryNotifier)
62
63MediaCodec::BatteryNotifier::BatteryNotifier() :
64    mVideoRefCount(0),
65    mAudioRefCount(0) {
66    // get battery service
67    const sp<IServiceManager> sm(defaultServiceManager());
68    if (sm != NULL) {
69        const String16 name("batterystats");
70        mBatteryStatService = interface_cast<IBatteryStats>(sm->getService(name));
71        if (mBatteryStatService == NULL) {
72            ALOGE("batterystats service unavailable!");
73        }
74    }
75}
76
77void MediaCodec::BatteryNotifier::noteStartVideo() {
78    if (mVideoRefCount == 0 && mBatteryStatService != NULL) {
79        mBatteryStatService->noteStartVideo(AID_MEDIA);
80    }
81    mVideoRefCount++;
82}
83
84void MediaCodec::BatteryNotifier::noteStopVideo() {
85    if (mVideoRefCount == 0) {
86        ALOGW("BatteryNotifier::noteStop(): video refcount is broken!");
87        return;
88    }
89
90    mVideoRefCount--;
91    if (mVideoRefCount == 0 && mBatteryStatService != NULL) {
92        mBatteryStatService->noteStopVideo(AID_MEDIA);
93    }
94}
95
96void MediaCodec::BatteryNotifier::noteStartAudio() {
97    if (mAudioRefCount == 0 && mBatteryStatService != NULL) {
98        mBatteryStatService->noteStartAudio(AID_MEDIA);
99    }
100    mAudioRefCount++;
101}
102
103void MediaCodec::BatteryNotifier::noteStopAudio() {
104    if (mAudioRefCount == 0) {
105        ALOGW("BatteryNotifier::noteStop(): audio refcount is broken!");
106        return;
107    }
108
109    mAudioRefCount--;
110    if (mAudioRefCount == 0 && mBatteryStatService != NULL) {
111        mBatteryStatService->noteStopAudio(AID_MEDIA);
112    }
113}
114// static
115sp<MediaCodec> MediaCodec::CreateByType(
116        const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err) {
117    sp<MediaCodec> codec = new MediaCodec(looper);
118
119    const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
120    if (err != NULL) {
121        *err = ret;
122    }
123    return ret == OK ? codec : NULL; // NULL deallocates codec.
124}
125
126// static
127sp<MediaCodec> MediaCodec::CreateByComponentName(
128        const sp<ALooper> &looper, const char *name, status_t *err) {
129    sp<MediaCodec> codec = new MediaCodec(looper);
130
131    const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */);
132    if (err != NULL) {
133        *err = ret;
134    }
135    return ret == OK ? codec : NULL; // NULL deallocates codec.
136}
137
138MediaCodec::MediaCodec(const sp<ALooper> &looper)
139    : mState(UNINITIALIZED),
140      mLooper(looper),
141      mCodec(NULL),
142      mReplyID(0),
143      mFlags(0),
144      mStickyError(OK),
145      mSoftRenderer(NULL),
146      mBatteryStatNotified(false),
147      mIsVideo(false),
148      mDequeueInputTimeoutGeneration(0),
149      mDequeueInputReplyID(0),
150      mDequeueOutputTimeoutGeneration(0),
151      mDequeueOutputReplyID(0),
152      mHaveInputSurface(false) {
153}
154
155MediaCodec::~MediaCodec() {
156    CHECK_EQ(mState, UNINITIALIZED);
157}
158
159// static
160status_t MediaCodec::PostAndAwaitResponse(
161        const sp<AMessage> &msg, sp<AMessage> *response) {
162    status_t err = msg->postAndAwaitResponse(response);
163
164    if (err != OK) {
165        return err;
166    }
167
168    if (!(*response)->findInt32("err", &err)) {
169        err = OK;
170    }
171
172    return err;
173}
174
175// static
176void MediaCodec::PostReplyWithError(int32_t replyID, int32_t err) {
177    sp<AMessage> response = new AMessage;
178    response->setInt32("err", err);
179    response->postReply(replyID);
180}
181
182status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) {
183    // save init parameters for reset
184    mInitName = name;
185    mInitNameIsType = nameIsType;
186    mInitIsEncoder = encoder;
187
188    // Current video decoders do not return from OMX_FillThisBuffer
189    // quickly, violating the OpenMAX specs, until that is remedied
190    // we need to invest in an extra looper to free the main event
191    // queue.
192    mCodec = new ACodec;
193    bool needDedicatedLooper = false;
194    if (nameIsType && !strncasecmp(name, "video/", 6)) {
195        needDedicatedLooper = true;
196    } else {
197        AString tmp = name;
198        if (tmp.endsWith(".secure")) {
199            tmp.erase(tmp.size() - 7, 7);
200        }
201        const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
202        ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
203        if (codecIdx >= 0) {
204            const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
205            Vector<AString> mimes;
206            info->getSupportedMimes(&mimes);
207            for (size_t i = 0; i < mimes.size(); i++) {
208                if (mimes[i].startsWith("video/")) {
209                    needDedicatedLooper = true;
210                    break;
211                }
212            }
213        }
214    }
215
216    if (needDedicatedLooper) {
217        if (mCodecLooper == NULL) {
218            mCodecLooper = new ALooper;
219            mCodecLooper->setName("CodecLooper");
220            mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
221        }
222
223        mCodecLooper->registerHandler(mCodec);
224    } else {
225        mLooper->registerHandler(mCodec);
226    }
227
228    mLooper->registerHandler(this);
229
230    mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));
231
232    sp<AMessage> msg = new AMessage(kWhatInit, id());
233    msg->setString("name", name);
234    msg->setInt32("nameIsType", nameIsType);
235
236    if (nameIsType) {
237        msg->setInt32("encoder", encoder);
238    }
239
240    sp<AMessage> response;
241    return PostAndAwaitResponse(msg, &response);
242}
243
244status_t MediaCodec::setCallback(const sp<AMessage> &callback) {
245    sp<AMessage> msg = new AMessage(kWhatSetCallback, id());
246    msg->setMessage("callback", callback);
247
248    sp<AMessage> response;
249    return PostAndAwaitResponse(msg, &response);
250}
251
252status_t MediaCodec::configure(
253        const sp<AMessage> &format,
254        const sp<Surface> &nativeWindow,
255        const sp<ICrypto> &crypto,
256        uint32_t flags) {
257    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
258
259    msg->setMessage("format", format);
260    msg->setInt32("flags", flags);
261
262    if (nativeWindow != NULL) {
263        msg->setObject(
264                "native-window",
265                new NativeWindowWrapper(nativeWindow));
266    }
267
268    if (crypto != NULL) {
269        msg->setPointer("crypto", crypto.get());
270    }
271
272    sp<AMessage> response;
273    return PostAndAwaitResponse(msg, &response);
274}
275
276status_t MediaCodec::createInputSurface(
277        sp<IGraphicBufferProducer>* bufferProducer) {
278    sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, id());
279
280    sp<AMessage> response;
281    status_t err = PostAndAwaitResponse(msg, &response);
282    if (err == NO_ERROR) {
283        // unwrap the sp<IGraphicBufferProducer>
284        sp<RefBase> obj;
285        bool found = response->findObject("input-surface", &obj);
286        CHECK(found);
287        sp<BufferProducerWrapper> wrapper(
288                static_cast<BufferProducerWrapper*>(obj.get()));
289        *bufferProducer = wrapper->getBufferProducer();
290    } else {
291        ALOGW("createInputSurface failed, err=%d", err);
292    }
293    return err;
294}
295
296status_t MediaCodec::start() {
297    sp<AMessage> msg = new AMessage(kWhatStart, id());
298
299    sp<AMessage> response;
300    return PostAndAwaitResponse(msg, &response);
301}
302
303status_t MediaCodec::stop() {
304    sp<AMessage> msg = new AMessage(kWhatStop, id());
305
306    sp<AMessage> response;
307    return PostAndAwaitResponse(msg, &response);
308}
309
310status_t MediaCodec::release() {
311    sp<AMessage> msg = new AMessage(kWhatRelease, id());
312
313    sp<AMessage> response;
314    return PostAndAwaitResponse(msg, &response);
315}
316
317status_t MediaCodec::reset() {
318    /* When external-facing MediaCodec object is created,
319       it is already initialized.  Thus, reset is essentially
320       release() followed by init(), plus clearing the state */
321
322    status_t err = release();
323
324    // unregister handlers
325    if (mCodec != NULL) {
326        if (mCodecLooper != NULL) {
327            mCodecLooper->unregisterHandler(mCodec->id());
328        } else {
329            mLooper->unregisterHandler(mCodec->id());
330        }
331        mCodec = NULL;
332    }
333    mLooper->unregisterHandler(id());
334
335    mFlags = 0;    // clear all flags
336    mStickyError = OK;
337
338    // reset state not reset by setState(UNINITIALIZED)
339    mReplyID = 0;
340    mDequeueInputReplyID = 0;
341    mDequeueOutputReplyID = 0;
342    mDequeueInputTimeoutGeneration = 0;
343    mDequeueOutputTimeoutGeneration = 0;
344    mHaveInputSurface = false;
345
346    if (err == OK) {
347        err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder);
348    }
349    return err;
350}
351
352status_t MediaCodec::queueInputBuffer(
353        size_t index,
354        size_t offset,
355        size_t size,
356        int64_t presentationTimeUs,
357        uint32_t flags,
358        AString *errorDetailMsg) {
359    if (errorDetailMsg != NULL) {
360        errorDetailMsg->clear();
361    }
362
363    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
364    msg->setSize("index", index);
365    msg->setSize("offset", offset);
366    msg->setSize("size", size);
367    msg->setInt64("timeUs", presentationTimeUs);
368    msg->setInt32("flags", flags);
369    msg->setPointer("errorDetailMsg", errorDetailMsg);
370
371    sp<AMessage> response;
372    return PostAndAwaitResponse(msg, &response);
373}
374
375status_t MediaCodec::queueSecureInputBuffer(
376        size_t index,
377        size_t offset,
378        const CryptoPlugin::SubSample *subSamples,
379        size_t numSubSamples,
380        const uint8_t key[16],
381        const uint8_t iv[16],
382        CryptoPlugin::Mode mode,
383        int64_t presentationTimeUs,
384        uint32_t flags,
385        AString *errorDetailMsg) {
386    if (errorDetailMsg != NULL) {
387        errorDetailMsg->clear();
388    }
389
390    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
391    msg->setSize("index", index);
392    msg->setSize("offset", offset);
393    msg->setPointer("subSamples", (void *)subSamples);
394    msg->setSize("numSubSamples", numSubSamples);
395    msg->setPointer("key", (void *)key);
396    msg->setPointer("iv", (void *)iv);
397    msg->setInt32("mode", mode);
398    msg->setInt64("timeUs", presentationTimeUs);
399    msg->setInt32("flags", flags);
400    msg->setPointer("errorDetailMsg", errorDetailMsg);
401
402    sp<AMessage> response;
403    status_t err = PostAndAwaitResponse(msg, &response);
404
405    return err;
406}
407
408status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
409    sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, id());
410    msg->setInt64("timeoutUs", timeoutUs);
411
412    sp<AMessage> response;
413    status_t err;
414    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
415        return err;
416    }
417
418    CHECK(response->findSize("index", index));
419
420    return OK;
421}
422
423status_t MediaCodec::dequeueOutputBuffer(
424        size_t *index,
425        size_t *offset,
426        size_t *size,
427        int64_t *presentationTimeUs,
428        uint32_t *flags,
429        int64_t timeoutUs) {
430    sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, id());
431    msg->setInt64("timeoutUs", timeoutUs);
432
433    sp<AMessage> response;
434    status_t err;
435    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
436        return err;
437    }
438
439    CHECK(response->findSize("index", index));
440    CHECK(response->findSize("offset", offset));
441    CHECK(response->findSize("size", size));
442    CHECK(response->findInt64("timeUs", presentationTimeUs));
443    CHECK(response->findInt32("flags", (int32_t *)flags));
444
445    return OK;
446}
447
448status_t MediaCodec::renderOutputBufferAndRelease(size_t index) {
449    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
450    msg->setSize("index", index);
451    msg->setInt32("render", true);
452
453    sp<AMessage> response;
454    return PostAndAwaitResponse(msg, &response);
455}
456
457status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) {
458    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
459    msg->setSize("index", index);
460    msg->setInt32("render", true);
461    msg->setInt64("timestampNs", timestampNs);
462
463    sp<AMessage> response;
464    return PostAndAwaitResponse(msg, &response);
465}
466
467status_t MediaCodec::releaseOutputBuffer(size_t index) {
468    sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, id());
469    msg->setSize("index", index);
470
471    sp<AMessage> response;
472    return PostAndAwaitResponse(msg, &response);
473}
474
475status_t MediaCodec::signalEndOfInputStream() {
476    sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, id());
477
478    sp<AMessage> response;
479    return PostAndAwaitResponse(msg, &response);
480}
481
482status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const {
483    sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, id());
484
485    sp<AMessage> response;
486    status_t err;
487    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
488        return err;
489    }
490
491    CHECK(response->findMessage("format", format));
492
493    return OK;
494}
495
496status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
497    sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id());
498
499    sp<AMessage> response;
500    status_t err;
501    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
502        return err;
503    }
504
505    CHECK(response->findMessage("format", format));
506
507    return OK;
508}
509
510status_t MediaCodec::getName(AString *name) const {
511    sp<AMessage> msg = new AMessage(kWhatGetName, id());
512
513    sp<AMessage> response;
514    status_t err;
515    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
516        return err;
517    }
518
519    CHECK(response->findString("name", name));
520
521    return OK;
522}
523
524status_t MediaCodec::getInputBuffers(Vector<sp<ABuffer> > *buffers) const {
525    sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
526    msg->setInt32("portIndex", kPortIndexInput);
527    msg->setPointer("buffers", buffers);
528
529    sp<AMessage> response;
530    return PostAndAwaitResponse(msg, &response);
531}
532
533status_t MediaCodec::getOutputBuffers(Vector<sp<ABuffer> > *buffers) const {
534    sp<AMessage> msg = new AMessage(kWhatGetBuffers, id());
535    msg->setInt32("portIndex", kPortIndexOutput);
536    msg->setPointer("buffers", buffers);
537
538    sp<AMessage> response;
539    return PostAndAwaitResponse(msg, &response);
540}
541
542status_t MediaCodec::getOutputBuffer(size_t index, sp<ABuffer> *buffer) {
543    sp<AMessage> format;
544    return getBufferAndFormat(kPortIndexOutput, index, buffer, &format);
545}
546
547status_t MediaCodec::getOutputFormat(size_t index, sp<AMessage> *format) {
548    sp<ABuffer> buffer;
549    return getBufferAndFormat(kPortIndexOutput, index, &buffer, format);
550}
551
552status_t MediaCodec::getInputBuffer(size_t index, sp<ABuffer> *buffer) {
553    sp<AMessage> format;
554    return getBufferAndFormat(kPortIndexInput, index, buffer, &format);
555}
556
557bool MediaCodec::isExecuting() const {
558    return mState == STARTED || mState == FLUSHED;
559}
560
561status_t MediaCodec::getBufferAndFormat(
562        size_t portIndex, size_t index,
563        sp<ABuffer> *buffer, sp<AMessage> *format) {
564    // use mutex instead of a context switch
565
566    buffer->clear();
567    format->clear();
568    if (!isExecuting()) {
569        return INVALID_OPERATION;
570    }
571
572    // we do not want mPortBuffers to change during this section
573    // we also don't want mOwnedByClient to change during this
574    Mutex::Autolock al(mBufferLock);
575    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
576    if (index < buffers->size()) {
577        const BufferInfo &info = buffers->itemAt(index);
578        if (info.mOwnedByClient) {
579            *buffer = info.mData;
580            *format = info.mFormat;
581        }
582    }
583    return OK;
584}
585
586status_t MediaCodec::flush() {
587    sp<AMessage> msg = new AMessage(kWhatFlush, id());
588
589    sp<AMessage> response;
590    return PostAndAwaitResponse(msg, &response);
591}
592
593status_t MediaCodec::requestIDRFrame() {
594    (new AMessage(kWhatRequestIDRFrame, id()))->post();
595
596    return OK;
597}
598
599void MediaCodec::requestActivityNotification(const sp<AMessage> &notify) {
600    sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, id());
601    msg->setMessage("notify", notify);
602    msg->post();
603}
604
605////////////////////////////////////////////////////////////////////////////////
606
607void MediaCodec::cancelPendingDequeueOperations() {
608    if (mFlags & kFlagDequeueInputPending) {
609        PostReplyWithError(mDequeueInputReplyID, INVALID_OPERATION);
610
611        ++mDequeueInputTimeoutGeneration;
612        mDequeueInputReplyID = 0;
613        mFlags &= ~kFlagDequeueInputPending;
614    }
615
616    if (mFlags & kFlagDequeueOutputPending) {
617        PostReplyWithError(mDequeueOutputReplyID, INVALID_OPERATION);
618
619        ++mDequeueOutputTimeoutGeneration;
620        mDequeueOutputReplyID = 0;
621        mFlags &= ~kFlagDequeueOutputPending;
622    }
623}
624
625bool MediaCodec::handleDequeueInputBuffer(uint32_t replyID, bool newRequest) {
626    if (!isExecuting() || (mFlags & kFlagIsAsync)
627            || (newRequest && (mFlags & kFlagDequeueInputPending))) {
628        PostReplyWithError(replyID, INVALID_OPERATION);
629        return true;
630    } else if (mFlags & kFlagStickyError) {
631        PostReplyWithError(replyID, getStickyError());
632        return true;
633    }
634
635    ssize_t index = dequeuePortBuffer(kPortIndexInput);
636
637    if (index < 0) {
638        CHECK_EQ(index, -EAGAIN);
639        return false;
640    }
641
642    sp<AMessage> response = new AMessage;
643    response->setSize("index", index);
644    response->postReply(replyID);
645
646    return true;
647}
648
649bool MediaCodec::handleDequeueOutputBuffer(uint32_t replyID, bool newRequest) {
650    sp<AMessage> response = new AMessage;
651
652    if (!isExecuting() || (mFlags & kFlagIsAsync)
653            || (newRequest && (mFlags & kFlagDequeueOutputPending))) {
654        response->setInt32("err", INVALID_OPERATION);
655    } else if (mFlags & kFlagStickyError) {
656        response->setInt32("err", getStickyError());
657    } else if (mFlags & kFlagOutputBuffersChanged) {
658        response->setInt32("err", INFO_OUTPUT_BUFFERS_CHANGED);
659        mFlags &= ~kFlagOutputBuffersChanged;
660    } else if (mFlags & kFlagOutputFormatChanged) {
661        response->setInt32("err", INFO_FORMAT_CHANGED);
662        mFlags &= ~kFlagOutputFormatChanged;
663    } else {
664        ssize_t index = dequeuePortBuffer(kPortIndexOutput);
665
666        if (index < 0) {
667            CHECK_EQ(index, -EAGAIN);
668            return false;
669        }
670
671        const sp<ABuffer> &buffer =
672            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
673
674        response->setSize("index", index);
675        response->setSize("offset", buffer->offset());
676        response->setSize("size", buffer->size());
677
678        int64_t timeUs;
679        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
680
681        response->setInt64("timeUs", timeUs);
682
683        int32_t omxFlags;
684        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
685
686        uint32_t flags = 0;
687        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
688            flags |= BUFFER_FLAG_SYNCFRAME;
689        }
690        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
691            flags |= BUFFER_FLAG_CODECCONFIG;
692        }
693        if (omxFlags & OMX_BUFFERFLAG_EOS) {
694            flags |= BUFFER_FLAG_EOS;
695        }
696
697        response->setInt32("flags", flags);
698    }
699
700    response->postReply(replyID);
701
702    return true;
703}
704
705void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
706    switch (msg->what()) {
707        case kWhatCodecNotify:
708        {
709            int32_t what;
710            CHECK(msg->findInt32("what", &what));
711
712            switch (what) {
713                case CodecBase::kWhatError:
714                {
715                    int32_t err, actionCode;
716                    CHECK(msg->findInt32("err", &err));
717                    CHECK(msg->findInt32("actionCode", &actionCode));
718
719                    ALOGE("Codec reported err %#x, actionCode %d, while in state %d",
720                            err, actionCode, mState);
721                    if (err == DEAD_OBJECT) {
722                        mFlags |= kFlagSawMediaServerDie;
723                    }
724
725                    bool sendErrorReponse = true;
726
727                    switch (mState) {
728                        case INITIALIZING:
729                        {
730                            setState(UNINITIALIZED);
731                            break;
732                        }
733
734                        case CONFIGURING:
735                        {
736                            setState(INITIALIZED);
737                            break;
738                        }
739
740                        case STARTING:
741                        {
742                            setState(CONFIGURED);
743                            break;
744                        }
745
746                        case STOPPING:
747                        case RELEASING:
748                        {
749                            // Ignore the error, assuming we'll still get
750                            // the shutdown complete notification.
751
752                            sendErrorReponse = false;
753
754                            if (mFlags & kFlagSawMediaServerDie) {
755                                // MediaServer died, there definitely won't
756                                // be a shutdown complete notification after
757                                // all.
758
759                                // note that we're directly going from
760                                // STOPPING->UNINITIALIZED, instead of the
761                                // usual STOPPING->INITIALIZED state.
762                                setState(UNINITIALIZED);
763
764                                (new AMessage)->postReply(mReplyID);
765                            }
766                            break;
767                        }
768
769                        case FLUSHING:
770                        {
771                            if (actionCode == ACTION_CODE_FATAL) {
772                                setState(UNINITIALIZED);
773                            } else {
774                                setState(
775                                        (mFlags & kFlagIsAsync) ? FLUSHED : STARTED);
776                            }
777                            break;
778                        }
779
780                        case FLUSHED:
781                        case STARTED:
782                        {
783                            sendErrorReponse = false;
784
785                            setStickyError(err);
786                            postActivityNotificationIfPossible();
787
788                            cancelPendingDequeueOperations();
789
790                            if (mFlags & kFlagIsAsync) {
791                                onError(err, actionCode);
792                            }
793                            switch (actionCode) {
794                            case ACTION_CODE_TRANSIENT:
795                                break;
796                            case ACTION_CODE_RECOVERABLE:
797                                setState(INITIALIZED);
798                                break;
799                            default:
800                                setState(UNINITIALIZED);
801                                break;
802                            }
803                            break;
804                        }
805
806                        default:
807                        {
808                            sendErrorReponse = false;
809
810                            setStickyError(err);
811                            postActivityNotificationIfPossible();
812
813                            // actionCode in an uninitialized state is always fatal.
814                            if (mState == UNINITIALIZED) {
815                                actionCode = ACTION_CODE_FATAL;
816                            }
817                            if (mFlags & kFlagIsAsync) {
818                                onError(err, actionCode);
819                            }
820                            switch (actionCode) {
821                            case ACTION_CODE_TRANSIENT:
822                                break;
823                            case ACTION_CODE_RECOVERABLE:
824                                setState(INITIALIZED);
825                                break;
826                            default:
827                                setState(UNINITIALIZED);
828                                break;
829                            }
830                            break;
831                        }
832                    }
833
834                    if (sendErrorReponse) {
835                        PostReplyWithError(mReplyID, err);
836                    }
837                    break;
838                }
839
840                case CodecBase::kWhatComponentAllocated:
841                {
842                    CHECK_EQ(mState, INITIALIZING);
843                    setState(INITIALIZED);
844
845                    CHECK(msg->findString("componentName", &mComponentName));
846
847                    if (mComponentName.startsWith("OMX.google.")) {
848                        mFlags |= kFlagIsSoftwareCodec;
849                    } else {
850                        mFlags &= ~kFlagIsSoftwareCodec;
851                    }
852
853                    if (mComponentName.endsWith(".secure")) {
854                        mFlags |= kFlagIsSecure;
855                    } else {
856                        mFlags &= ~kFlagIsSecure;
857                    }
858
859                    (new AMessage)->postReply(mReplyID);
860                    break;
861                }
862
863                case CodecBase::kWhatComponentConfigured:
864                {
865                    CHECK_EQ(mState, CONFIGURING);
866
867                    // reset input surface flag
868                    mHaveInputSurface = false;
869
870                    CHECK(msg->findMessage("input-format", &mInputFormat));
871                    CHECK(msg->findMessage("output-format", &mOutputFormat));
872
873                    setState(CONFIGURED);
874                    (new AMessage)->postReply(mReplyID);
875                    break;
876                }
877
878                case CodecBase::kWhatInputSurfaceCreated:
879                {
880                    // response to initiateCreateInputSurface()
881                    status_t err = NO_ERROR;
882                    sp<AMessage> response = new AMessage();
883                    if (!msg->findInt32("err", &err)) {
884                        sp<RefBase> obj;
885                        msg->findObject("input-surface", &obj);
886                        CHECK(obj != NULL);
887                        response->setObject("input-surface", obj);
888                        mHaveInputSurface = true;
889                    } else {
890                        response->setInt32("err", err);
891                    }
892                    response->postReply(mReplyID);
893                    break;
894                }
895
896                case CodecBase::kWhatSignaledInputEOS:
897                {
898                    // response to signalEndOfInputStream()
899                    sp<AMessage> response = new AMessage();
900                    status_t err;
901                    if (msg->findInt32("err", &err)) {
902                        response->setInt32("err", err);
903                    }
904                    response->postReply(mReplyID);
905                    break;
906                }
907
908
909                case CodecBase::kWhatBuffersAllocated:
910                {
911                    Mutex::Autolock al(mBufferLock);
912                    int32_t portIndex;
913                    CHECK(msg->findInt32("portIndex", &portIndex));
914
915                    ALOGV("%s buffers allocated",
916                          portIndex == kPortIndexInput ? "input" : "output");
917
918                    CHECK(portIndex == kPortIndexInput
919                            || portIndex == kPortIndexOutput);
920
921                    mPortBuffers[portIndex].clear();
922
923                    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
924
925                    sp<RefBase> obj;
926                    CHECK(msg->findObject("portDesc", &obj));
927
928                    sp<CodecBase::PortDescription> portDesc =
929                        static_cast<CodecBase::PortDescription *>(obj.get());
930
931                    size_t numBuffers = portDesc->countBuffers();
932
933                    for (size_t i = 0; i < numBuffers; ++i) {
934                        BufferInfo info;
935                        info.mBufferID = portDesc->bufferIDAt(i);
936                        info.mOwnedByClient = false;
937                        info.mData = portDesc->bufferAt(i);
938
939                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
940                            info.mEncryptedData =
941                                new ABuffer(info.mData->capacity());
942                        }
943
944                        buffers->push_back(info);
945                    }
946
947                    if (portIndex == kPortIndexOutput) {
948                        if (mState == STARTING) {
949                            // We're always allocating output buffers after
950                            // allocating input buffers, so this is a good
951                            // indication that now all buffers are allocated.
952                            setState(STARTED);
953                            (new AMessage)->postReply(mReplyID);
954                        } else {
955                            mFlags |= kFlagOutputBuffersChanged;
956                            postActivityNotificationIfPossible();
957                        }
958                    }
959                    break;
960                }
961
962                case CodecBase::kWhatOutputFormatChanged:
963                {
964                    ALOGV("codec output format changed");
965
966                    if ((mFlags & kFlagIsSoftwareCodec)
967                            && mNativeWindow != NULL) {
968                        AString mime;
969                        CHECK(msg->findString("mime", &mime));
970
971                        if (!strncasecmp("video/", mime.c_str(), 6)) {
972                            delete mSoftRenderer;
973                            mSoftRenderer = NULL;
974
975                            int32_t width, height;
976                            CHECK(msg->findInt32("width", &width));
977                            CHECK(msg->findInt32("height", &height));
978
979                            int32_t cropLeft, cropTop, cropRight, cropBottom;
980                            CHECK(msg->findRect("crop",
981                                &cropLeft, &cropTop, &cropRight, &cropBottom));
982
983                            int32_t colorFormat;
984                            CHECK(msg->findInt32(
985                                        "color-format", &colorFormat));
986
987                            sp<MetaData> meta = new MetaData;
988                            meta->setInt32(kKeyWidth, width);
989                            meta->setInt32(kKeyHeight, height);
990                            meta->setRect(kKeyCropRect,
991                                cropLeft, cropTop, cropRight, cropBottom);
992                            meta->setInt32(kKeyColorFormat, colorFormat);
993
994                            mSoftRenderer =
995                                new SoftwareRenderer(mNativeWindow, meta);
996                        }
997                    }
998
999                    mOutputFormat = msg;
1000
1001                    if (mFlags & kFlagIsEncoder) {
1002                        // Before we announce the format change we should
1003                        // collect codec specific data and amend the output
1004                        // format as necessary.
1005                        mFlags |= kFlagGatherCodecSpecificData;
1006                    } else if (mFlags & kFlagIsAsync) {
1007                        onOutputFormatChanged();
1008                    } else {
1009                        mFlags |= kFlagOutputFormatChanged;
1010                        postActivityNotificationIfPossible();
1011                    }
1012                    break;
1013                }
1014
1015                case CodecBase::kWhatFillThisBuffer:
1016                {
1017                    /* size_t index = */updateBuffers(kPortIndexInput, msg);
1018
1019                    if (mState == FLUSHING
1020                            || mState == STOPPING
1021                            || mState == RELEASING) {
1022                        returnBuffersToCodecOnPort(kPortIndexInput);
1023                        break;
1024                    }
1025
1026                    if (!mCSD.empty()) {
1027                        ssize_t index = dequeuePortBuffer(kPortIndexInput);
1028                        CHECK_GE(index, 0);
1029
1030                        // If codec specific data had been specified as
1031                        // part of the format in the call to configure and
1032                        // if there's more csd left, we submit it here
1033                        // clients only get access to input buffers once
1034                        // this data has been exhausted.
1035
1036                        status_t err = queueCSDInputBuffer(index);
1037
1038                        if (err != OK) {
1039                            ALOGE("queueCSDInputBuffer failed w/ error %d",
1040                                  err);
1041
1042                            setStickyError(err);
1043                            postActivityNotificationIfPossible();
1044
1045                            cancelPendingDequeueOperations();
1046                        }
1047                        break;
1048                    }
1049
1050                    if (mFlags & kFlagIsAsync) {
1051                        onInputBufferAvailable();
1052                    } else if (mFlags & kFlagDequeueInputPending) {
1053                        CHECK(handleDequeueInputBuffer(mDequeueInputReplyID));
1054
1055                        ++mDequeueInputTimeoutGeneration;
1056                        mFlags &= ~kFlagDequeueInputPending;
1057                        mDequeueInputReplyID = 0;
1058                    } else {
1059                        postActivityNotificationIfPossible();
1060                    }
1061                    break;
1062                }
1063
1064                case CodecBase::kWhatDrainThisBuffer:
1065                {
1066                    /* size_t index = */updateBuffers(kPortIndexOutput, msg);
1067
1068                    if (mState == FLUSHING
1069                            || mState == STOPPING
1070                            || mState == RELEASING) {
1071                        returnBuffersToCodecOnPort(kPortIndexOutput);
1072                        break;
1073                    }
1074
1075                    sp<ABuffer> buffer;
1076                    CHECK(msg->findBuffer("buffer", &buffer));
1077
1078                    int32_t omxFlags;
1079                    CHECK(msg->findInt32("flags", &omxFlags));
1080
1081                    buffer->meta()->setInt32("omxFlags", omxFlags);
1082
1083                    if (mFlags & kFlagGatherCodecSpecificData) {
1084                        // This is the very first output buffer after a
1085                        // format change was signalled, it'll either contain
1086                        // the one piece of codec specific data we can expect
1087                        // or there won't be codec specific data.
1088                        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
1089                            status_t err =
1090                                amendOutputFormatWithCodecSpecificData(buffer);
1091
1092                            if (err != OK) {
1093                                ALOGE("Codec spit out malformed codec "
1094                                      "specific data!");
1095                            }
1096                        }
1097
1098                        mFlags &= ~kFlagGatherCodecSpecificData;
1099                        if (mFlags & kFlagIsAsync) {
1100                            onOutputFormatChanged();
1101                        } else {
1102                            mFlags |= kFlagOutputFormatChanged;
1103                        }
1104                    }
1105
1106                    if (mFlags & kFlagIsAsync) {
1107                        onOutputBufferAvailable();
1108                    } else if (mFlags & kFlagDequeueOutputPending) {
1109                        CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
1110
1111                        ++mDequeueOutputTimeoutGeneration;
1112                        mFlags &= ~kFlagDequeueOutputPending;
1113                        mDequeueOutputReplyID = 0;
1114                    } else {
1115                        postActivityNotificationIfPossible();
1116                    }
1117
1118                    break;
1119                }
1120
1121                case CodecBase::kWhatEOS:
1122                {
1123                    // We already notify the client of this by using the
1124                    // corresponding flag in "onOutputBufferReady".
1125                    break;
1126                }
1127
1128                case CodecBase::kWhatShutdownCompleted:
1129                {
1130                    if (mState == STOPPING) {
1131                        setState(INITIALIZED);
1132                    } else {
1133                        CHECK_EQ(mState, RELEASING);
1134                        setState(UNINITIALIZED);
1135                    }
1136
1137                    (new AMessage)->postReply(mReplyID);
1138                    break;
1139                }
1140
1141                case CodecBase::kWhatFlushCompleted:
1142                {
1143                    CHECK_EQ(mState, FLUSHING);
1144
1145                    if (mFlags & kFlagIsAsync) {
1146                        setState(FLUSHED);
1147                    } else {
1148                        setState(STARTED);
1149                        mCodec->signalResume();
1150                    }
1151
1152                    (new AMessage)->postReply(mReplyID);
1153                    break;
1154                }
1155
1156                default:
1157                    TRESPASS();
1158            }
1159            break;
1160        }
1161
1162        case kWhatInit:
1163        {
1164            uint32_t replyID;
1165            CHECK(msg->senderAwaitsResponse(&replyID));
1166
1167            if (mState != UNINITIALIZED) {
1168                PostReplyWithError(replyID, INVALID_OPERATION);
1169                break;
1170            }
1171
1172            mReplyID = replyID;
1173            setState(INITIALIZING);
1174
1175            AString name;
1176            CHECK(msg->findString("name", &name));
1177
1178            int32_t nameIsType;
1179            int32_t encoder = false;
1180            CHECK(msg->findInt32("nameIsType", &nameIsType));
1181            if (nameIsType) {
1182                CHECK(msg->findInt32("encoder", &encoder));
1183            }
1184
1185            sp<AMessage> format = new AMessage;
1186
1187            if (nameIsType) {
1188                format->setString("mime", name.c_str());
1189                format->setInt32("encoder", encoder);
1190            } else {
1191                format->setString("componentName", name.c_str());
1192            }
1193
1194            mCodec->initiateAllocateComponent(format);
1195            break;
1196        }
1197
1198        case kWhatSetCallback:
1199        {
1200            uint32_t replyID;
1201            CHECK(msg->senderAwaitsResponse(&replyID));
1202
1203            if (mState == UNINITIALIZED
1204                    || mState == INITIALIZING
1205                    || isExecuting()) {
1206                // callback can't be set after codec is executing,
1207                // or before it's initialized (as the callback
1208                // will be cleared when it goes to INITIALIZED)
1209                PostReplyWithError(replyID, INVALID_OPERATION);
1210                break;
1211            }
1212
1213            sp<AMessage> callback;
1214            CHECK(msg->findMessage("callback", &callback));
1215
1216            mCallback = callback;
1217
1218            if (mCallback != NULL) {
1219                ALOGI("MediaCodec will operate in async mode");
1220                mFlags |= kFlagIsAsync;
1221            } else {
1222                mFlags &= ~kFlagIsAsync;
1223            }
1224
1225            sp<AMessage> response = new AMessage;
1226            response->postReply(replyID);
1227            break;
1228        }
1229
1230        case kWhatConfigure:
1231        {
1232            uint32_t replyID;
1233            CHECK(msg->senderAwaitsResponse(&replyID));
1234
1235            if (mState != INITIALIZED) {
1236                PostReplyWithError(replyID, INVALID_OPERATION);
1237                break;
1238            }
1239
1240            sp<RefBase> obj;
1241            if (!msg->findObject("native-window", &obj)) {
1242                obj.clear();
1243            }
1244
1245            sp<AMessage> format;
1246            CHECK(msg->findMessage("format", &format));
1247
1248            if (obj != NULL) {
1249                format->setObject("native-window", obj);
1250
1251                status_t err = setNativeWindow(
1252                    static_cast<NativeWindowWrapper *>(obj.get())
1253                        ->getSurfaceTextureClient());
1254
1255                if (err != OK) {
1256                    PostReplyWithError(replyID, err);
1257                    break;
1258                }
1259            } else {
1260                setNativeWindow(NULL);
1261            }
1262
1263            mReplyID = replyID;
1264            setState(CONFIGURING);
1265
1266            void *crypto;
1267            if (!msg->findPointer("crypto", &crypto)) {
1268                crypto = NULL;
1269            }
1270
1271            mCrypto = static_cast<ICrypto *>(crypto);
1272
1273            uint32_t flags;
1274            CHECK(msg->findInt32("flags", (int32_t *)&flags));
1275
1276            if (flags & CONFIGURE_FLAG_ENCODE) {
1277                format->setInt32("encoder", true);
1278                mFlags |= kFlagIsEncoder;
1279            }
1280
1281            extractCSD(format);
1282
1283            mCodec->initiateConfigureComponent(format);
1284            break;
1285        }
1286
1287        case kWhatCreateInputSurface:
1288        {
1289            uint32_t replyID;
1290            CHECK(msg->senderAwaitsResponse(&replyID));
1291
1292            // Must be configured, but can't have been started yet.
1293            if (mState != CONFIGURED) {
1294                PostReplyWithError(replyID, INVALID_OPERATION);
1295                break;
1296            }
1297
1298            mReplyID = replyID;
1299            mCodec->initiateCreateInputSurface();
1300            break;
1301        }
1302
1303        case kWhatStart:
1304        {
1305            uint32_t replyID;
1306            CHECK(msg->senderAwaitsResponse(&replyID));
1307
1308            if (mState == FLUSHED) {
1309                mCodec->signalResume();
1310                PostReplyWithError(replyID, OK);
1311            } else if (mState != CONFIGURED) {
1312                PostReplyWithError(replyID, INVALID_OPERATION);
1313                break;
1314            }
1315
1316            mReplyID = replyID;
1317            setState(STARTING);
1318
1319            mCodec->initiateStart();
1320            break;
1321        }
1322
1323        case kWhatStop:
1324        case kWhatRelease:
1325        {
1326            State targetState =
1327                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
1328
1329            uint32_t replyID;
1330            CHECK(msg->senderAwaitsResponse(&replyID));
1331
1332            if (mState != INITIALIZED
1333                    && mState != CONFIGURED && !isExecuting()) {
1334                // We may be in "UNINITIALIZED" state already without the
1335                // client being aware of this if media server died while
1336                // we were being stopped. The client would assume that
1337                // after stop() returned, it would be safe to call release()
1338                // and it should be in this case, no harm to allow a release()
1339                // if we're already uninitialized.
1340                // Similarly stopping a stopped MediaCodec should be benign.
1341                sp<AMessage> response = new AMessage;
1342                response->setInt32(
1343                        "err",
1344                        mState == targetState ? OK : INVALID_OPERATION);
1345
1346                response->postReply(replyID);
1347                break;
1348            }
1349
1350            if (mFlags & kFlagSawMediaServerDie) {
1351                // It's dead, Jim. Don't expect initiateShutdown to yield
1352                // any useful results now...
1353                setState(UNINITIALIZED);
1354                (new AMessage)->postReply(replyID);
1355                break;
1356            }
1357
1358            mReplyID = replyID;
1359            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
1360
1361            mCodec->initiateShutdown(
1362                    msg->what() == kWhatStop /* keepComponentAllocated */);
1363
1364            returnBuffersToCodec();
1365            break;
1366        }
1367
1368        case kWhatDequeueInputBuffer:
1369        {
1370            uint32_t replyID;
1371            CHECK(msg->senderAwaitsResponse(&replyID));
1372
1373            if (mFlags & kFlagIsAsync) {
1374                ALOGE("dequeueOutputBuffer can't be used in async mode");
1375                PostReplyWithError(replyID, INVALID_OPERATION);
1376                break;
1377            }
1378
1379            if (mHaveInputSurface) {
1380                ALOGE("dequeueInputBuffer can't be used with input surface");
1381                PostReplyWithError(replyID, INVALID_OPERATION);
1382                break;
1383            }
1384
1385            if (handleDequeueInputBuffer(replyID, true /* new request */)) {
1386                break;
1387            }
1388
1389            int64_t timeoutUs;
1390            CHECK(msg->findInt64("timeoutUs", &timeoutUs));
1391
1392            if (timeoutUs == 0ll) {
1393                PostReplyWithError(replyID, -EAGAIN);
1394                break;
1395            }
1396
1397            mFlags |= kFlagDequeueInputPending;
1398            mDequeueInputReplyID = replyID;
1399
1400            if (timeoutUs > 0ll) {
1401                sp<AMessage> timeoutMsg =
1402                    new AMessage(kWhatDequeueInputTimedOut, id());
1403                timeoutMsg->setInt32(
1404                        "generation", ++mDequeueInputTimeoutGeneration);
1405                timeoutMsg->post(timeoutUs);
1406            }
1407            break;
1408        }
1409
1410        case kWhatDequeueInputTimedOut:
1411        {
1412            int32_t generation;
1413            CHECK(msg->findInt32("generation", &generation));
1414
1415            if (generation != mDequeueInputTimeoutGeneration) {
1416                // Obsolete
1417                break;
1418            }
1419
1420            CHECK(mFlags & kFlagDequeueInputPending);
1421
1422            PostReplyWithError(mDequeueInputReplyID, -EAGAIN);
1423
1424            mFlags &= ~kFlagDequeueInputPending;
1425            mDequeueInputReplyID = 0;
1426            break;
1427        }
1428
1429        case kWhatQueueInputBuffer:
1430        {
1431            uint32_t replyID;
1432            CHECK(msg->senderAwaitsResponse(&replyID));
1433
1434            if (!isExecuting()) {
1435                PostReplyWithError(replyID, INVALID_OPERATION);
1436                break;
1437            } else if (mFlags & kFlagStickyError) {
1438                PostReplyWithError(replyID, getStickyError());
1439                break;
1440            }
1441
1442            status_t err = onQueueInputBuffer(msg);
1443
1444            PostReplyWithError(replyID, err);
1445            break;
1446        }
1447
1448        case kWhatDequeueOutputBuffer:
1449        {
1450            uint32_t replyID;
1451            CHECK(msg->senderAwaitsResponse(&replyID));
1452
1453            if (mFlags & kFlagIsAsync) {
1454                ALOGE("dequeueOutputBuffer can't be used in async mode");
1455                PostReplyWithError(replyID, INVALID_OPERATION);
1456                break;
1457            }
1458
1459            if (handleDequeueOutputBuffer(replyID, true /* new request */)) {
1460                break;
1461            }
1462
1463            int64_t timeoutUs;
1464            CHECK(msg->findInt64("timeoutUs", &timeoutUs));
1465
1466            if (timeoutUs == 0ll) {
1467                PostReplyWithError(replyID, -EAGAIN);
1468                break;
1469            }
1470
1471            mFlags |= kFlagDequeueOutputPending;
1472            mDequeueOutputReplyID = replyID;
1473
1474            if (timeoutUs > 0ll) {
1475                sp<AMessage> timeoutMsg =
1476                    new AMessage(kWhatDequeueOutputTimedOut, id());
1477                timeoutMsg->setInt32(
1478                        "generation", ++mDequeueOutputTimeoutGeneration);
1479                timeoutMsg->post(timeoutUs);
1480            }
1481            break;
1482        }
1483
1484        case kWhatDequeueOutputTimedOut:
1485        {
1486            int32_t generation;
1487            CHECK(msg->findInt32("generation", &generation));
1488
1489            if (generation != mDequeueOutputTimeoutGeneration) {
1490                // Obsolete
1491                break;
1492            }
1493
1494            CHECK(mFlags & kFlagDequeueOutputPending);
1495
1496            PostReplyWithError(mDequeueOutputReplyID, -EAGAIN);
1497
1498            mFlags &= ~kFlagDequeueOutputPending;
1499            mDequeueOutputReplyID = 0;
1500            break;
1501        }
1502
1503        case kWhatReleaseOutputBuffer:
1504        {
1505            uint32_t replyID;
1506            CHECK(msg->senderAwaitsResponse(&replyID));
1507
1508            if (!isExecuting()) {
1509                PostReplyWithError(replyID, INVALID_OPERATION);
1510                break;
1511            } else if (mFlags & kFlagStickyError) {
1512                PostReplyWithError(replyID, getStickyError());
1513                break;
1514            }
1515
1516            status_t err = onReleaseOutputBuffer(msg);
1517
1518            PostReplyWithError(replyID, err);
1519            break;
1520        }
1521
1522        case kWhatSignalEndOfInputStream:
1523        {
1524            uint32_t replyID;
1525            CHECK(msg->senderAwaitsResponse(&replyID));
1526
1527            if (!isExecuting()) {
1528                PostReplyWithError(replyID, INVALID_OPERATION);
1529                break;
1530            } else if (mFlags & kFlagStickyError) {
1531                PostReplyWithError(replyID, getStickyError());
1532                break;
1533            }
1534
1535            mReplyID = replyID;
1536            mCodec->signalEndOfInputStream();
1537            break;
1538        }
1539
1540        case kWhatGetBuffers:
1541        {
1542            uint32_t replyID;
1543            CHECK(msg->senderAwaitsResponse(&replyID));
1544
1545            if (!isExecuting() || (mFlags & kFlagIsAsync)) {
1546                PostReplyWithError(replyID, INVALID_OPERATION);
1547                break;
1548            } else if (mFlags & kFlagStickyError) {
1549                PostReplyWithError(replyID, getStickyError());
1550                break;
1551            }
1552
1553            int32_t portIndex;
1554            CHECK(msg->findInt32("portIndex", &portIndex));
1555
1556            Vector<sp<ABuffer> > *dstBuffers;
1557            CHECK(msg->findPointer("buffers", (void **)&dstBuffers));
1558
1559            dstBuffers->clear();
1560            const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex];
1561
1562            for (size_t i = 0; i < srcBuffers.size(); ++i) {
1563                const BufferInfo &info = srcBuffers.itemAt(i);
1564
1565                dstBuffers->push_back(
1566                        (portIndex == kPortIndexInput && mCrypto != NULL)
1567                                ? info.mEncryptedData : info.mData);
1568            }
1569
1570            (new AMessage)->postReply(replyID);
1571            break;
1572        }
1573
1574        case kWhatFlush:
1575        {
1576            uint32_t replyID;
1577            CHECK(msg->senderAwaitsResponse(&replyID));
1578
1579            if (!isExecuting()) {
1580                PostReplyWithError(replyID, INVALID_OPERATION);
1581                break;
1582            } else if (mFlags & kFlagStickyError) {
1583                PostReplyWithError(replyID, getStickyError());
1584                break;
1585            }
1586
1587            mReplyID = replyID;
1588            // TODO: skip flushing if already FLUSHED
1589            setState(FLUSHING);
1590
1591            mCodec->signalFlush();
1592            returnBuffersToCodec();
1593            break;
1594        }
1595
1596        case kWhatGetInputFormat:
1597        case kWhatGetOutputFormat:
1598        {
1599            sp<AMessage> format =
1600                (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
1601
1602            uint32_t replyID;
1603            CHECK(msg->senderAwaitsResponse(&replyID));
1604
1605            if ((mState != CONFIGURED && mState != STARTING &&
1606                 mState != STARTED && mState != FLUSHING &&
1607                 mState != FLUSHED)
1608                    || format == NULL) {
1609                PostReplyWithError(replyID, INVALID_OPERATION);
1610                break;
1611            } else if (mFlags & kFlagStickyError) {
1612                PostReplyWithError(replyID, getStickyError());
1613                break;
1614            }
1615
1616            sp<AMessage> response = new AMessage;
1617            response->setMessage("format", format);
1618            response->postReply(replyID);
1619            break;
1620        }
1621
1622        case kWhatRequestIDRFrame:
1623        {
1624            mCodec->signalRequestIDRFrame();
1625            break;
1626        }
1627
1628        case kWhatRequestActivityNotification:
1629        {
1630            CHECK(mActivityNotify == NULL);
1631            CHECK(msg->findMessage("notify", &mActivityNotify));
1632
1633            postActivityNotificationIfPossible();
1634            break;
1635        }
1636
1637        case kWhatGetName:
1638        {
1639            uint32_t replyID;
1640            CHECK(msg->senderAwaitsResponse(&replyID));
1641
1642            if (mComponentName.empty()) {
1643                PostReplyWithError(replyID, INVALID_OPERATION);
1644                break;
1645            }
1646
1647            sp<AMessage> response = new AMessage;
1648            response->setString("name", mComponentName.c_str());
1649            response->postReply(replyID);
1650            break;
1651        }
1652
1653        case kWhatSetParameters:
1654        {
1655            uint32_t replyID;
1656            CHECK(msg->senderAwaitsResponse(&replyID));
1657
1658            sp<AMessage> params;
1659            CHECK(msg->findMessage("params", &params));
1660
1661            status_t err = onSetParameters(params);
1662
1663            PostReplyWithError(replyID, err);
1664            break;
1665        }
1666
1667        default:
1668            TRESPASS();
1669    }
1670}
1671
1672void MediaCodec::extractCSD(const sp<AMessage> &format) {
1673    mCSD.clear();
1674
1675    size_t i = 0;
1676    for (;;) {
1677        sp<ABuffer> csd;
1678        if (!format->findBuffer(StringPrintf("csd-%u", i).c_str(), &csd)) {
1679            break;
1680        }
1681
1682        mCSD.push_back(csd);
1683        ++i;
1684    }
1685
1686    ALOGV("Found %zu pieces of codec specific data.", mCSD.size());
1687}
1688
1689status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
1690    CHECK(!mCSD.empty());
1691
1692    const BufferInfo *info =
1693        &mPortBuffers[kPortIndexInput].itemAt(bufferIndex);
1694
1695    sp<ABuffer> csd = *mCSD.begin();
1696    mCSD.erase(mCSD.begin());
1697
1698    const sp<ABuffer> &codecInputData =
1699        (mCrypto != NULL) ? info->mEncryptedData : info->mData;
1700
1701    if (csd->size() > codecInputData->capacity()) {
1702        return -EINVAL;
1703    }
1704
1705    memcpy(codecInputData->data(), csd->data(), csd->size());
1706
1707    AString errorDetailMsg;
1708
1709    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
1710    msg->setSize("index", bufferIndex);
1711    msg->setSize("offset", 0);
1712    msg->setSize("size", csd->size());
1713    msg->setInt64("timeUs", 0ll);
1714    msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG);
1715    msg->setPointer("errorDetailMsg", &errorDetailMsg);
1716
1717    return onQueueInputBuffer(msg);
1718}
1719
1720void MediaCodec::setState(State newState) {
1721    if (newState == INITIALIZED || newState == UNINITIALIZED) {
1722        delete mSoftRenderer;
1723        mSoftRenderer = NULL;
1724
1725        mCrypto.clear();
1726        setNativeWindow(NULL);
1727
1728        mInputFormat.clear();
1729        mOutputFormat.clear();
1730        mFlags &= ~kFlagOutputFormatChanged;
1731        mFlags &= ~kFlagOutputBuffersChanged;
1732        mFlags &= ~kFlagStickyError;
1733        mFlags &= ~kFlagIsEncoder;
1734        mFlags &= ~kFlagGatherCodecSpecificData;
1735        mFlags &= ~kFlagIsAsync;
1736        mStickyError = OK;
1737
1738        mActivityNotify.clear();
1739        mCallback.clear();
1740    }
1741
1742    if (newState == UNINITIALIZED) {
1743        // return any straggling buffers, e.g. if we got here on an error
1744        returnBuffersToCodec();
1745
1746        mComponentName.clear();
1747
1748        // The component is gone, mediaserver's probably back up already
1749        // but should definitely be back up should we try to instantiate
1750        // another component.. and the cycle continues.
1751        mFlags &= ~kFlagSawMediaServerDie;
1752    }
1753
1754    mState = newState;
1755
1756    cancelPendingDequeueOperations();
1757
1758    updateBatteryStat();
1759}
1760
1761void MediaCodec::returnBuffersToCodec() {
1762    returnBuffersToCodecOnPort(kPortIndexInput);
1763    returnBuffersToCodecOnPort(kPortIndexOutput);
1764}
1765
1766void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
1767    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1768    Mutex::Autolock al(mBufferLock);
1769
1770    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1771
1772    for (size_t i = 0; i < buffers->size(); ++i) {
1773        BufferInfo *info = &buffers->editItemAt(i);
1774
1775        if (info->mNotify != NULL) {
1776            sp<AMessage> msg = info->mNotify;
1777            info->mNotify = NULL;
1778            info->mOwnedByClient = false;
1779
1780            if (portIndex == kPortIndexInput) {
1781                /* no error, just returning buffers */
1782                msg->setInt32("err", OK);
1783            }
1784            msg->post();
1785        }
1786    }
1787
1788    mAvailPortBuffers[portIndex].clear();
1789}
1790
1791size_t MediaCodec::updateBuffers(
1792        int32_t portIndex, const sp<AMessage> &msg) {
1793    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1794
1795    uint32_t bufferID;
1796    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
1797
1798    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
1799
1800    for (size_t i = 0; i < buffers->size(); ++i) {
1801        BufferInfo *info = &buffers->editItemAt(i);
1802
1803        if (info->mBufferID == bufferID) {
1804            CHECK(info->mNotify == NULL);
1805            CHECK(msg->findMessage("reply", &info->mNotify));
1806
1807            mAvailPortBuffers[portIndex].push_back(i);
1808
1809            return i;
1810        }
1811    }
1812
1813    TRESPASS();
1814
1815    return 0;
1816}
1817
1818status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
1819    size_t index;
1820    size_t offset;
1821    size_t size;
1822    int64_t timeUs;
1823    uint32_t flags;
1824    CHECK(msg->findSize("index", &index));
1825    CHECK(msg->findSize("offset", &offset));
1826    CHECK(msg->findInt64("timeUs", &timeUs));
1827    CHECK(msg->findInt32("flags", (int32_t *)&flags));
1828
1829    const CryptoPlugin::SubSample *subSamples;
1830    size_t numSubSamples;
1831    const uint8_t *key;
1832    const uint8_t *iv;
1833    CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted;
1834
1835    // We allow the simpler queueInputBuffer API to be used even in
1836    // secure mode, by fabricating a single unencrypted subSample.
1837    CryptoPlugin::SubSample ss;
1838
1839    if (msg->findSize("size", &size)) {
1840        if (mCrypto != NULL) {
1841            ss.mNumBytesOfClearData = size;
1842            ss.mNumBytesOfEncryptedData = 0;
1843
1844            subSamples = &ss;
1845            numSubSamples = 1;
1846            key = NULL;
1847            iv = NULL;
1848        }
1849    } else {
1850        if (mCrypto == NULL) {
1851            return -EINVAL;
1852        }
1853
1854        CHECK(msg->findPointer("subSamples", (void **)&subSamples));
1855        CHECK(msg->findSize("numSubSamples", &numSubSamples));
1856        CHECK(msg->findPointer("key", (void **)&key));
1857        CHECK(msg->findPointer("iv", (void **)&iv));
1858
1859        int32_t tmp;
1860        CHECK(msg->findInt32("mode", &tmp));
1861
1862        mode = (CryptoPlugin::Mode)tmp;
1863
1864        size = 0;
1865        for (size_t i = 0; i < numSubSamples; ++i) {
1866            size += subSamples[i].mNumBytesOfClearData;
1867            size += subSamples[i].mNumBytesOfEncryptedData;
1868        }
1869    }
1870
1871    if (index >= mPortBuffers[kPortIndexInput].size()) {
1872        return -ERANGE;
1873    }
1874
1875    BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index);
1876
1877    if (info->mNotify == NULL || !info->mOwnedByClient) {
1878        return -EACCES;
1879    }
1880
1881    if (offset + size > info->mData->capacity()) {
1882        return -EINVAL;
1883    }
1884
1885    sp<AMessage> reply = info->mNotify;
1886    info->mData->setRange(offset, size);
1887    info->mData->meta()->setInt64("timeUs", timeUs);
1888
1889    if (flags & BUFFER_FLAG_EOS) {
1890        info->mData->meta()->setInt32("eos", true);
1891    }
1892
1893    if (flags & BUFFER_FLAG_CODECCONFIG) {
1894        info->mData->meta()->setInt32("csd", true);
1895    }
1896
1897    if (mCrypto != NULL) {
1898        if (size > info->mEncryptedData->capacity()) {
1899            return -ERANGE;
1900        }
1901
1902        AString *errorDetailMsg;
1903        CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
1904
1905        ssize_t result = mCrypto->decrypt(
1906                (mFlags & kFlagIsSecure) != 0,
1907                key,
1908                iv,
1909                mode,
1910                info->mEncryptedData->base() + offset,
1911                subSamples,
1912                numSubSamples,
1913                info->mData->base(),
1914                errorDetailMsg);
1915
1916        if (result < 0) {
1917            return result;
1918        }
1919
1920        info->mData->setRange(0, result);
1921    }
1922
1923    // synchronization boundary for getBufferAndFormat
1924    {
1925        Mutex::Autolock al(mBufferLock);
1926        info->mOwnedByClient = false;
1927    }
1928    reply->setBuffer("buffer", info->mData);
1929    reply->post();
1930
1931    info->mNotify = NULL;
1932
1933    return OK;
1934}
1935
1936status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) {
1937    size_t index;
1938    CHECK(msg->findSize("index", &index));
1939
1940    int32_t render;
1941    if (!msg->findInt32("render", &render)) {
1942        render = 0;
1943    }
1944
1945    if (!isExecuting()) {
1946        return -EINVAL;
1947    }
1948
1949    if (index >= mPortBuffers[kPortIndexOutput].size()) {
1950        return -ERANGE;
1951    }
1952
1953    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
1954
1955    if (info->mNotify == NULL || !info->mOwnedByClient) {
1956        return -EACCES;
1957    }
1958
1959    // synchronization boundary for getBufferAndFormat
1960    {
1961        Mutex::Autolock al(mBufferLock);
1962        info->mOwnedByClient = false;
1963    }
1964
1965    if (render && info->mData != NULL && info->mData->size() != 0) {
1966        info->mNotify->setInt32("render", true);
1967
1968        int64_t timestampNs = 0;
1969        if (msg->findInt64("timestampNs", &timestampNs)) {
1970            info->mNotify->setInt64("timestampNs", timestampNs);
1971        } else {
1972            // TODO: it seems like we should use the timestamp
1973            // in the (media)buffer as it potentially came from
1974            // an input surface, but we did not propagate it prior to
1975            // API 20.  Perhaps check for target SDK version.
1976#if 0
1977            if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
1978                ALOGV("using buffer PTS of %" PRId64, timestampNs);
1979                timestampNs *= 1000;
1980            }
1981#endif
1982        }
1983
1984        if (mSoftRenderer != NULL) {
1985            mSoftRenderer->render(
1986                    info->mData->data(), info->mData->size(), timestampNs, NULL);
1987        }
1988    }
1989
1990    info->mNotify->post();
1991    info->mNotify = NULL;
1992
1993    return OK;
1994}
1995
1996ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) {
1997    CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
1998
1999    List<size_t> *availBuffers = &mAvailPortBuffers[portIndex];
2000
2001    if (availBuffers->empty()) {
2002        return -EAGAIN;
2003    }
2004
2005    size_t index = *availBuffers->begin();
2006    availBuffers->erase(availBuffers->begin());
2007
2008    BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index);
2009    CHECK(!info->mOwnedByClient);
2010    {
2011        Mutex::Autolock al(mBufferLock);
2012        info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
2013        info->mOwnedByClient = true;
2014
2015        // set image-data
2016        if (info->mFormat != NULL) {
2017            sp<ABuffer> imageData;
2018            if (info->mFormat->findBuffer("image-data", &imageData)) {
2019                info->mData->meta()->setBuffer("image-data", imageData);
2020            }
2021            int32_t left, top, right, bottom;
2022            if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) {
2023                info->mData->meta()->setRect("crop-rect", left, top, right, bottom);
2024            }
2025        }
2026    }
2027
2028    return index;
2029}
2030
2031status_t MediaCodec::setNativeWindow(
2032        const sp<Surface> &surfaceTextureClient) {
2033    status_t err;
2034
2035    if (mNativeWindow != NULL) {
2036        err = native_window_api_disconnect(
2037                mNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
2038
2039        if (err != OK) {
2040            ALOGW("native_window_api_disconnect returned an error: %s (%d)",
2041                    strerror(-err), err);
2042        }
2043
2044        mNativeWindow.clear();
2045    }
2046
2047    if (surfaceTextureClient != NULL) {
2048        err = native_window_api_connect(
2049                surfaceTextureClient.get(), NATIVE_WINDOW_API_MEDIA);
2050
2051        if (err != OK) {
2052            ALOGE("native_window_api_connect returned an error: %s (%d)",
2053                    strerror(-err), err);
2054
2055            return err;
2056        }
2057
2058        mNativeWindow = surfaceTextureClient;
2059    }
2060
2061    return OK;
2062}
2063
2064void MediaCodec::onInputBufferAvailable() {
2065    int32_t index;
2066    while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) {
2067        sp<AMessage> msg = mCallback->dup();
2068        msg->setInt32("callbackID", CB_INPUT_AVAILABLE);
2069        msg->setInt32("index", index);
2070        msg->post();
2071    }
2072}
2073
2074void MediaCodec::onOutputBufferAvailable() {
2075    int32_t index;
2076    while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
2077        const sp<ABuffer> &buffer =
2078            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
2079        sp<AMessage> msg = mCallback->dup();
2080        msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
2081        msg->setInt32("index", index);
2082        msg->setSize("offset", buffer->offset());
2083        msg->setSize("size", buffer->size());
2084
2085        int64_t timeUs;
2086        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
2087
2088        msg->setInt64("timeUs", timeUs);
2089
2090        int32_t omxFlags;
2091        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
2092
2093        uint32_t flags = 0;
2094        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
2095            flags |= BUFFER_FLAG_SYNCFRAME;
2096        }
2097        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
2098            flags |= BUFFER_FLAG_CODECCONFIG;
2099        }
2100        if (omxFlags & OMX_BUFFERFLAG_EOS) {
2101            flags |= BUFFER_FLAG_EOS;
2102        }
2103
2104        msg->setInt32("flags", flags);
2105
2106        msg->post();
2107    }
2108}
2109
2110void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) {
2111    if (mCallback != NULL) {
2112        sp<AMessage> msg = mCallback->dup();
2113        msg->setInt32("callbackID", CB_ERROR);
2114        msg->setInt32("err", err);
2115        msg->setInt32("actionCode", actionCode);
2116
2117        if (detail != NULL) {
2118            msg->setString("detail", detail);
2119        }
2120
2121        msg->post();
2122    }
2123}
2124
2125void MediaCodec::onOutputFormatChanged() {
2126    if (mCallback != NULL) {
2127        sp<AMessage> msg = mCallback->dup();
2128        msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED);
2129        msg->setMessage("format", mOutputFormat);
2130        msg->post();
2131    }
2132}
2133
2134
2135void MediaCodec::postActivityNotificationIfPossible() {
2136    if (mActivityNotify == NULL) {
2137        return;
2138    }
2139
2140    if ((mFlags & (kFlagStickyError
2141                    | kFlagOutputBuffersChanged
2142                    | kFlagOutputFormatChanged))
2143            || !mAvailPortBuffers[kPortIndexInput].empty()
2144            || !mAvailPortBuffers[kPortIndexOutput].empty()) {
2145        mActivityNotify->post();
2146        mActivityNotify.clear();
2147    }
2148}
2149
2150status_t MediaCodec::setParameters(const sp<AMessage> &params) {
2151    sp<AMessage> msg = new AMessage(kWhatSetParameters, id());
2152    msg->setMessage("params", params);
2153
2154    sp<AMessage> response;
2155    return PostAndAwaitResponse(msg, &response);
2156}
2157
2158status_t MediaCodec::onSetParameters(const sp<AMessage> &params) {
2159    mCodec->signalSetParameters(params);
2160
2161    return OK;
2162}
2163
2164status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
2165        const sp<ABuffer> &buffer) {
2166    AString mime;
2167    CHECK(mOutputFormat->findString("mime", &mime));
2168
2169    if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
2170        // Codec specific data should be SPS and PPS in a single buffer,
2171        // each prefixed by a startcode (0x00 0x00 0x00 0x01).
2172        // We separate the two and put them into the output format
2173        // under the keys "csd-0" and "csd-1".
2174
2175        unsigned csdIndex = 0;
2176
2177        const uint8_t *data = buffer->data();
2178        size_t size = buffer->size();
2179
2180        const uint8_t *nalStart;
2181        size_t nalSize;
2182        while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
2183            sp<ABuffer> csd = new ABuffer(nalSize + 4);
2184            memcpy(csd->data(), "\x00\x00\x00\x01", 4);
2185            memcpy(csd->data() + 4, nalStart, nalSize);
2186
2187            mOutputFormat->setBuffer(
2188                    StringPrintf("csd-%u", csdIndex).c_str(), csd);
2189
2190            ++csdIndex;
2191        }
2192
2193        if (csdIndex != 2) {
2194            return ERROR_MALFORMED;
2195        }
2196    } else {
2197        // For everything else we just stash the codec specific data into
2198        // the output format as a single piece of csd under "csd-0".
2199        mOutputFormat->setBuffer("csd-0", buffer);
2200    }
2201
2202    return OK;
2203}
2204
2205void MediaCodec::updateBatteryStat() {
2206    if (mState == CONFIGURED && !mBatteryStatNotified) {
2207        AString mime;
2208        CHECK(mOutputFormat != NULL &&
2209                mOutputFormat->findString("mime", &mime));
2210
2211        mIsVideo = mime.startsWithIgnoreCase("video/");
2212
2213        BatteryNotifier& notifier(BatteryNotifier::getInstance());
2214
2215        if (mIsVideo) {
2216            notifier.noteStartVideo();
2217        } else {
2218            notifier.noteStartAudio();
2219        }
2220
2221        mBatteryStatNotified = true;
2222    } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
2223        BatteryNotifier& notifier(BatteryNotifier::getInstance());
2224
2225        if (mIsVideo) {
2226            notifier.noteStopVideo();
2227        } else {
2228            notifier.noteStopAudio();
2229        }
2230
2231        mBatteryStatNotified = false;
2232    }
2233}
2234
2235}  // namespace android
2236