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