MediaCodec.cpp revision 251d4be8aa5ab80bc915a82a2420233bdc62018e
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 MediaCodecList *mcl = MediaCodecList::getInstance(); 202 ssize_t codecIdx = mcl->findCodecByName(tmp.c_str()); 203 if (codecIdx >= 0) { 204 Vector<AString> types; 205 if (mcl->getSupportedTypes(codecIdx, &types) == OK) { 206 for (size_t i = 0; i < types.size(); i++) { 207 if (types[i].startsWith("video/")) { 208 needDedicatedLooper = true; 209 break; 210 } 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> ¬ify) { 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", err, actionCode); 720 if (err == DEAD_OBJECT) { 721 mFlags |= kFlagSawMediaServerDie; 722 } 723 724 bool sendErrorReponse = true; 725 726 switch (mState) { 727 case INITIALIZING: 728 { 729 setState(UNINITIALIZED); 730 break; 731 } 732 733 case CONFIGURING: 734 { 735 setState(INITIALIZED); 736 break; 737 } 738 739 case STARTING: 740 { 741 setState(CONFIGURED); 742 break; 743 } 744 745 case STOPPING: 746 case RELEASING: 747 { 748 // Ignore the error, assuming we'll still get 749 // the shutdown complete notification. 750 751 sendErrorReponse = false; 752 753 if (mFlags & kFlagSawMediaServerDie) { 754 // MediaServer died, there definitely won't 755 // be a shutdown complete notification after 756 // all. 757 758 // note that we're directly going from 759 // STOPPING->UNINITIALIZED, instead of the 760 // usual STOPPING->INITIALIZED state. 761 setState(UNINITIALIZED); 762 763 (new AMessage)->postReply(mReplyID); 764 } 765 break; 766 } 767 768 case FLUSHING: 769 { 770 setState( 771 (mFlags & kFlagIsAsync) ? FLUSHED : STARTED); 772 break; 773 } 774 775 case FLUSHED: 776 case STARTED: 777 { 778 sendErrorReponse = false; 779 780 setStickyError(err); 781 postActivityNotificationIfPossible(); 782 783 cancelPendingDequeueOperations(); 784 785 if (mFlags & kFlagIsAsync) { 786 onError(err, actionCode); 787 } 788 switch (actionCode) { 789 case ACTION_CODE_TRANSIENT: 790 break; 791 case ACTION_CODE_RECOVERABLE: 792 setState(INITIALIZED); 793 break; 794 default: 795 setState(UNINITIALIZED); 796 break; 797 } 798 break; 799 } 800 801 default: 802 { 803 sendErrorReponse = false; 804 805 setStickyError(err); 806 postActivityNotificationIfPossible(); 807 808 // actionCode in an uninitialized state is always fatal. 809 if (mState == UNINITIALIZED) { 810 actionCode = ACTION_CODE_FATAL; 811 } 812 if (mFlags & kFlagIsAsync) { 813 onError(err, actionCode); 814 } 815 switch (actionCode) { 816 case ACTION_CODE_TRANSIENT: 817 break; 818 case ACTION_CODE_RECOVERABLE: 819 setState(INITIALIZED); 820 break; 821 default: 822 setState(UNINITIALIZED); 823 break; 824 } 825 break; 826 } 827 } 828 829 if (sendErrorReponse) { 830 PostReplyWithError(mReplyID, err); 831 } 832 break; 833 } 834 835 case CodecBase::kWhatComponentAllocated: 836 { 837 CHECK_EQ(mState, INITIALIZING); 838 setState(INITIALIZED); 839 840 CHECK(msg->findString("componentName", &mComponentName)); 841 842 if (mComponentName.startsWith("OMX.google.")) { 843 mFlags |= kFlagIsSoftwareCodec; 844 } else { 845 mFlags &= ~kFlagIsSoftwareCodec; 846 } 847 848 if (mComponentName.endsWith(".secure")) { 849 mFlags |= kFlagIsSecure; 850 } else { 851 mFlags &= ~kFlagIsSecure; 852 } 853 854 (new AMessage)->postReply(mReplyID); 855 break; 856 } 857 858 case CodecBase::kWhatComponentConfigured: 859 { 860 CHECK_EQ(mState, CONFIGURING); 861 862 // reset input surface flag 863 mHaveInputSurface = false; 864 865 CHECK(msg->findMessage("input-format", &mInputFormat)); 866 CHECK(msg->findMessage("output-format", &mOutputFormat)); 867 868 setState(CONFIGURED); 869 (new AMessage)->postReply(mReplyID); 870 break; 871 } 872 873 case CodecBase::kWhatInputSurfaceCreated: 874 { 875 // response to initiateCreateInputSurface() 876 status_t err = NO_ERROR; 877 sp<AMessage> response = new AMessage(); 878 if (!msg->findInt32("err", &err)) { 879 sp<RefBase> obj; 880 msg->findObject("input-surface", &obj); 881 CHECK(obj != NULL); 882 response->setObject("input-surface", obj); 883 mHaveInputSurface = true; 884 } else { 885 response->setInt32("err", err); 886 } 887 response->postReply(mReplyID); 888 break; 889 } 890 891 case CodecBase::kWhatSignaledInputEOS: 892 { 893 // response to signalEndOfInputStream() 894 sp<AMessage> response = new AMessage(); 895 status_t err; 896 if (msg->findInt32("err", &err)) { 897 response->setInt32("err", err); 898 } 899 response->postReply(mReplyID); 900 break; 901 } 902 903 904 case CodecBase::kWhatBuffersAllocated: 905 { 906 Mutex::Autolock al(mBufferLock); 907 int32_t portIndex; 908 CHECK(msg->findInt32("portIndex", &portIndex)); 909 910 ALOGV("%s buffers allocated", 911 portIndex == kPortIndexInput ? "input" : "output"); 912 913 CHECK(portIndex == kPortIndexInput 914 || portIndex == kPortIndexOutput); 915 916 mPortBuffers[portIndex].clear(); 917 918 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 919 920 sp<RefBase> obj; 921 CHECK(msg->findObject("portDesc", &obj)); 922 923 sp<CodecBase::PortDescription> portDesc = 924 static_cast<CodecBase::PortDescription *>(obj.get()); 925 926 size_t numBuffers = portDesc->countBuffers(); 927 928 for (size_t i = 0; i < numBuffers; ++i) { 929 BufferInfo info; 930 info.mBufferID = portDesc->bufferIDAt(i); 931 info.mOwnedByClient = false; 932 info.mData = portDesc->bufferAt(i); 933 934 if (portIndex == kPortIndexInput && mCrypto != NULL) { 935 info.mEncryptedData = 936 new ABuffer(info.mData->capacity()); 937 } 938 939 buffers->push_back(info); 940 } 941 942 if (portIndex == kPortIndexOutput) { 943 if (mState == STARTING) { 944 // We're always allocating output buffers after 945 // allocating input buffers, so this is a good 946 // indication that now all buffers are allocated. 947 setState(STARTED); 948 (new AMessage)->postReply(mReplyID); 949 } else { 950 mFlags |= kFlagOutputBuffersChanged; 951 postActivityNotificationIfPossible(); 952 } 953 } 954 break; 955 } 956 957 case CodecBase::kWhatOutputFormatChanged: 958 { 959 ALOGV("codec output format changed"); 960 961 if ((mFlags & kFlagIsSoftwareCodec) 962 && mNativeWindow != NULL) { 963 AString mime; 964 CHECK(msg->findString("mime", &mime)); 965 966 if (!strncasecmp("video/", mime.c_str(), 6)) { 967 delete mSoftRenderer; 968 mSoftRenderer = NULL; 969 970 int32_t width, height; 971 CHECK(msg->findInt32("width", &width)); 972 CHECK(msg->findInt32("height", &height)); 973 974 int32_t cropLeft, cropTop, cropRight, cropBottom; 975 CHECK(msg->findRect("crop", 976 &cropLeft, &cropTop, &cropRight, &cropBottom)); 977 978 int32_t colorFormat; 979 CHECK(msg->findInt32( 980 "color-format", &colorFormat)); 981 982 sp<MetaData> meta = new MetaData; 983 meta->setInt32(kKeyWidth, width); 984 meta->setInt32(kKeyHeight, height); 985 meta->setRect(kKeyCropRect, 986 cropLeft, cropTop, cropRight, cropBottom); 987 meta->setInt32(kKeyColorFormat, colorFormat); 988 989 mSoftRenderer = 990 new SoftwareRenderer(mNativeWindow, meta); 991 } 992 } 993 994 mOutputFormat = msg; 995 996 if (mFlags & kFlagIsEncoder) { 997 // Before we announce the format change we should 998 // collect codec specific data and amend the output 999 // format as necessary. 1000 mFlags |= kFlagGatherCodecSpecificData; 1001 } else if (mFlags & kFlagIsAsync) { 1002 onOutputFormatChanged(); 1003 } else { 1004 mFlags |= kFlagOutputFormatChanged; 1005 postActivityNotificationIfPossible(); 1006 } 1007 break; 1008 } 1009 1010 case CodecBase::kWhatFillThisBuffer: 1011 { 1012 /* size_t index = */updateBuffers(kPortIndexInput, msg); 1013 1014 if (mState == FLUSHING 1015 || mState == STOPPING 1016 || mState == RELEASING) { 1017 returnBuffersToCodecOnPort(kPortIndexInput); 1018 break; 1019 } 1020 1021 if (!mCSD.empty()) { 1022 ssize_t index = dequeuePortBuffer(kPortIndexInput); 1023 CHECK_GE(index, 0); 1024 1025 // If codec specific data had been specified as 1026 // part of the format in the call to configure and 1027 // if there's more csd left, we submit it here 1028 // clients only get access to input buffers once 1029 // this data has been exhausted. 1030 1031 status_t err = queueCSDInputBuffer(index); 1032 1033 if (err != OK) { 1034 ALOGE("queueCSDInputBuffer failed w/ error %d", 1035 err); 1036 1037 setStickyError(err); 1038 postActivityNotificationIfPossible(); 1039 1040 cancelPendingDequeueOperations(); 1041 } 1042 break; 1043 } 1044 1045 if (mFlags & kFlagIsAsync) { 1046 onInputBufferAvailable(); 1047 } else if (mFlags & kFlagDequeueInputPending) { 1048 CHECK(handleDequeueInputBuffer(mDequeueInputReplyID)); 1049 1050 ++mDequeueInputTimeoutGeneration; 1051 mFlags &= ~kFlagDequeueInputPending; 1052 mDequeueInputReplyID = 0; 1053 } else { 1054 postActivityNotificationIfPossible(); 1055 } 1056 break; 1057 } 1058 1059 case CodecBase::kWhatDrainThisBuffer: 1060 { 1061 /* size_t index = */updateBuffers(kPortIndexOutput, msg); 1062 1063 if (mState == FLUSHING 1064 || mState == STOPPING 1065 || mState == RELEASING) { 1066 returnBuffersToCodecOnPort(kPortIndexOutput); 1067 break; 1068 } 1069 1070 sp<ABuffer> buffer; 1071 CHECK(msg->findBuffer("buffer", &buffer)); 1072 1073 int32_t omxFlags; 1074 CHECK(msg->findInt32("flags", &omxFlags)); 1075 1076 buffer->meta()->setInt32("omxFlags", omxFlags); 1077 1078 if (mFlags & kFlagGatherCodecSpecificData) { 1079 // This is the very first output buffer after a 1080 // format change was signalled, it'll either contain 1081 // the one piece of codec specific data we can expect 1082 // or there won't be codec specific data. 1083 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 1084 status_t err = 1085 amendOutputFormatWithCodecSpecificData(buffer); 1086 1087 if (err != OK) { 1088 ALOGE("Codec spit out malformed codec " 1089 "specific data!"); 1090 } 1091 } 1092 1093 mFlags &= ~kFlagGatherCodecSpecificData; 1094 if (mFlags & kFlagIsAsync) { 1095 onOutputFormatChanged(); 1096 } else { 1097 mFlags |= kFlagOutputFormatChanged; 1098 } 1099 } 1100 1101 if (mFlags & kFlagIsAsync) { 1102 onOutputBufferAvailable(); 1103 } else if (mFlags & kFlagDequeueOutputPending) { 1104 CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID)); 1105 1106 ++mDequeueOutputTimeoutGeneration; 1107 mFlags &= ~kFlagDequeueOutputPending; 1108 mDequeueOutputReplyID = 0; 1109 } else { 1110 postActivityNotificationIfPossible(); 1111 } 1112 1113 break; 1114 } 1115 1116 case CodecBase::kWhatEOS: 1117 { 1118 // We already notify the client of this by using the 1119 // corresponding flag in "onOutputBufferReady". 1120 break; 1121 } 1122 1123 case CodecBase::kWhatShutdownCompleted: 1124 { 1125 if (mState == STOPPING) { 1126 setState(INITIALIZED); 1127 } else { 1128 CHECK_EQ(mState, RELEASING); 1129 setState(UNINITIALIZED); 1130 } 1131 1132 (new AMessage)->postReply(mReplyID); 1133 break; 1134 } 1135 1136 case CodecBase::kWhatFlushCompleted: 1137 { 1138 CHECK_EQ(mState, FLUSHING); 1139 1140 if (mFlags & kFlagIsAsync) { 1141 setState(FLUSHED); 1142 } else { 1143 setState(STARTED); 1144 mCodec->signalResume(); 1145 } 1146 1147 (new AMessage)->postReply(mReplyID); 1148 break; 1149 } 1150 1151 default: 1152 TRESPASS(); 1153 } 1154 break; 1155 } 1156 1157 case kWhatInit: 1158 { 1159 uint32_t replyID; 1160 CHECK(msg->senderAwaitsResponse(&replyID)); 1161 1162 if (mState != UNINITIALIZED) { 1163 PostReplyWithError(replyID, INVALID_OPERATION); 1164 break; 1165 } 1166 1167 mReplyID = replyID; 1168 setState(INITIALIZING); 1169 1170 AString name; 1171 CHECK(msg->findString("name", &name)); 1172 1173 int32_t nameIsType; 1174 int32_t encoder = false; 1175 CHECK(msg->findInt32("nameIsType", &nameIsType)); 1176 if (nameIsType) { 1177 CHECK(msg->findInt32("encoder", &encoder)); 1178 } 1179 1180 sp<AMessage> format = new AMessage; 1181 1182 if (nameIsType) { 1183 format->setString("mime", name.c_str()); 1184 format->setInt32("encoder", encoder); 1185 } else { 1186 format->setString("componentName", name.c_str()); 1187 } 1188 1189 mCodec->initiateAllocateComponent(format); 1190 break; 1191 } 1192 1193 case kWhatSetCallback: 1194 { 1195 uint32_t replyID; 1196 CHECK(msg->senderAwaitsResponse(&replyID)); 1197 1198 if (mState == UNINITIALIZED 1199 || mState == INITIALIZING 1200 || isExecuting()) { 1201 // callback can't be set after codec is executing, 1202 // or before it's initialized (as the callback 1203 // will be cleared when it goes to INITIALIZED) 1204 PostReplyWithError(replyID, INVALID_OPERATION); 1205 break; 1206 } 1207 1208 sp<AMessage> callback; 1209 CHECK(msg->findMessage("callback", &callback)); 1210 1211 mCallback = callback; 1212 1213 if (mCallback != NULL) { 1214 ALOGI("MediaCodec will operate in async mode"); 1215 mFlags |= kFlagIsAsync; 1216 } else { 1217 mFlags &= ~kFlagIsAsync; 1218 } 1219 1220 sp<AMessage> response = new AMessage; 1221 response->postReply(replyID); 1222 break; 1223 } 1224 1225 case kWhatConfigure: 1226 { 1227 uint32_t replyID; 1228 CHECK(msg->senderAwaitsResponse(&replyID)); 1229 1230 if (mState != INITIALIZED) { 1231 PostReplyWithError(replyID, INVALID_OPERATION); 1232 break; 1233 } 1234 1235 sp<RefBase> obj; 1236 if (!msg->findObject("native-window", &obj)) { 1237 obj.clear(); 1238 } 1239 1240 sp<AMessage> format; 1241 CHECK(msg->findMessage("format", &format)); 1242 1243 if (obj != NULL) { 1244 format->setObject("native-window", obj); 1245 1246 status_t err = setNativeWindow( 1247 static_cast<NativeWindowWrapper *>(obj.get()) 1248 ->getSurfaceTextureClient()); 1249 1250 if (err != OK) { 1251 PostReplyWithError(replyID, err); 1252 break; 1253 } 1254 } else { 1255 setNativeWindow(NULL); 1256 } 1257 1258 mReplyID = replyID; 1259 setState(CONFIGURING); 1260 1261 void *crypto; 1262 if (!msg->findPointer("crypto", &crypto)) { 1263 crypto = NULL; 1264 } 1265 1266 mCrypto = static_cast<ICrypto *>(crypto); 1267 1268 uint32_t flags; 1269 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1270 1271 if (flags & CONFIGURE_FLAG_ENCODE) { 1272 format->setInt32("encoder", true); 1273 mFlags |= kFlagIsEncoder; 1274 } 1275 1276 extractCSD(format); 1277 1278 mCodec->initiateConfigureComponent(format); 1279 break; 1280 } 1281 1282 case kWhatCreateInputSurface: 1283 { 1284 uint32_t replyID; 1285 CHECK(msg->senderAwaitsResponse(&replyID)); 1286 1287 // Must be configured, but can't have been started yet. 1288 if (mState != CONFIGURED) { 1289 PostReplyWithError(replyID, INVALID_OPERATION); 1290 break; 1291 } 1292 1293 mReplyID = replyID; 1294 mCodec->initiateCreateInputSurface(); 1295 break; 1296 } 1297 1298 case kWhatStart: 1299 { 1300 uint32_t replyID; 1301 CHECK(msg->senderAwaitsResponse(&replyID)); 1302 1303 if (mState == FLUSHED) { 1304 mCodec->signalResume(); 1305 PostReplyWithError(replyID, OK); 1306 } else if (mState != CONFIGURED) { 1307 PostReplyWithError(replyID, INVALID_OPERATION); 1308 break; 1309 } 1310 1311 mReplyID = replyID; 1312 setState(STARTING); 1313 1314 mCodec->initiateStart(); 1315 break; 1316 } 1317 1318 case kWhatStop: 1319 case kWhatRelease: 1320 { 1321 State targetState = 1322 (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED; 1323 1324 uint32_t replyID; 1325 CHECK(msg->senderAwaitsResponse(&replyID)); 1326 1327 if (mState != INITIALIZED 1328 && mState != CONFIGURED && !isExecuting()) { 1329 // We may be in "UNINITIALIZED" state already without the 1330 // client being aware of this if media server died while 1331 // we were being stopped. The client would assume that 1332 // after stop() returned, it would be safe to call release() 1333 // and it should be in this case, no harm to allow a release() 1334 // if we're already uninitialized. 1335 // Similarly stopping a stopped MediaCodec should be benign. 1336 sp<AMessage> response = new AMessage; 1337 response->setInt32( 1338 "err", 1339 mState == targetState ? OK : INVALID_OPERATION); 1340 1341 response->postReply(replyID); 1342 break; 1343 } 1344 1345 if (mFlags & kFlagSawMediaServerDie) { 1346 // It's dead, Jim. Don't expect initiateShutdown to yield 1347 // any useful results now... 1348 setState(UNINITIALIZED); 1349 (new AMessage)->postReply(replyID); 1350 break; 1351 } 1352 1353 mReplyID = replyID; 1354 setState(msg->what() == kWhatStop ? STOPPING : RELEASING); 1355 1356 mCodec->initiateShutdown( 1357 msg->what() == kWhatStop /* keepComponentAllocated */); 1358 1359 returnBuffersToCodec(); 1360 break; 1361 } 1362 1363 case kWhatDequeueInputBuffer: 1364 { 1365 uint32_t replyID; 1366 CHECK(msg->senderAwaitsResponse(&replyID)); 1367 1368 if (mFlags & kFlagIsAsync) { 1369 ALOGE("dequeueOutputBuffer can't be used in async mode"); 1370 PostReplyWithError(replyID, INVALID_OPERATION); 1371 break; 1372 } 1373 1374 if (mHaveInputSurface) { 1375 ALOGE("dequeueInputBuffer can't be used with input surface"); 1376 PostReplyWithError(replyID, INVALID_OPERATION); 1377 break; 1378 } 1379 1380 if (handleDequeueInputBuffer(replyID, true /* new request */)) { 1381 break; 1382 } 1383 1384 int64_t timeoutUs; 1385 CHECK(msg->findInt64("timeoutUs", &timeoutUs)); 1386 1387 if (timeoutUs == 0ll) { 1388 PostReplyWithError(replyID, -EAGAIN); 1389 break; 1390 } 1391 1392 mFlags |= kFlagDequeueInputPending; 1393 mDequeueInputReplyID = replyID; 1394 1395 if (timeoutUs > 0ll) { 1396 sp<AMessage> timeoutMsg = 1397 new AMessage(kWhatDequeueInputTimedOut, id()); 1398 timeoutMsg->setInt32( 1399 "generation", ++mDequeueInputTimeoutGeneration); 1400 timeoutMsg->post(timeoutUs); 1401 } 1402 break; 1403 } 1404 1405 case kWhatDequeueInputTimedOut: 1406 { 1407 int32_t generation; 1408 CHECK(msg->findInt32("generation", &generation)); 1409 1410 if (generation != mDequeueInputTimeoutGeneration) { 1411 // Obsolete 1412 break; 1413 } 1414 1415 CHECK(mFlags & kFlagDequeueInputPending); 1416 1417 PostReplyWithError(mDequeueInputReplyID, -EAGAIN); 1418 1419 mFlags &= ~kFlagDequeueInputPending; 1420 mDequeueInputReplyID = 0; 1421 break; 1422 } 1423 1424 case kWhatQueueInputBuffer: 1425 { 1426 uint32_t replyID; 1427 CHECK(msg->senderAwaitsResponse(&replyID)); 1428 1429 if (!isExecuting()) { 1430 PostReplyWithError(replyID, INVALID_OPERATION); 1431 break; 1432 } else if (mFlags & kFlagStickyError) { 1433 PostReplyWithError(replyID, getStickyError()); 1434 break; 1435 } 1436 1437 status_t err = onQueueInputBuffer(msg); 1438 1439 PostReplyWithError(replyID, err); 1440 break; 1441 } 1442 1443 case kWhatDequeueOutputBuffer: 1444 { 1445 uint32_t replyID; 1446 CHECK(msg->senderAwaitsResponse(&replyID)); 1447 1448 if (mFlags & kFlagIsAsync) { 1449 ALOGE("dequeueOutputBuffer can't be used in async mode"); 1450 PostReplyWithError(replyID, INVALID_OPERATION); 1451 break; 1452 } 1453 1454 if (handleDequeueOutputBuffer(replyID, true /* new request */)) { 1455 break; 1456 } 1457 1458 int64_t timeoutUs; 1459 CHECK(msg->findInt64("timeoutUs", &timeoutUs)); 1460 1461 if (timeoutUs == 0ll) { 1462 PostReplyWithError(replyID, -EAGAIN); 1463 break; 1464 } 1465 1466 mFlags |= kFlagDequeueOutputPending; 1467 mDequeueOutputReplyID = replyID; 1468 1469 if (timeoutUs > 0ll) { 1470 sp<AMessage> timeoutMsg = 1471 new AMessage(kWhatDequeueOutputTimedOut, id()); 1472 timeoutMsg->setInt32( 1473 "generation", ++mDequeueOutputTimeoutGeneration); 1474 timeoutMsg->post(timeoutUs); 1475 } 1476 break; 1477 } 1478 1479 case kWhatDequeueOutputTimedOut: 1480 { 1481 int32_t generation; 1482 CHECK(msg->findInt32("generation", &generation)); 1483 1484 if (generation != mDequeueOutputTimeoutGeneration) { 1485 // Obsolete 1486 break; 1487 } 1488 1489 CHECK(mFlags & kFlagDequeueOutputPending); 1490 1491 PostReplyWithError(mDequeueOutputReplyID, -EAGAIN); 1492 1493 mFlags &= ~kFlagDequeueOutputPending; 1494 mDequeueOutputReplyID = 0; 1495 break; 1496 } 1497 1498 case kWhatReleaseOutputBuffer: 1499 { 1500 uint32_t replyID; 1501 CHECK(msg->senderAwaitsResponse(&replyID)); 1502 1503 if (!isExecuting()) { 1504 PostReplyWithError(replyID, INVALID_OPERATION); 1505 break; 1506 } else if (mFlags & kFlagStickyError) { 1507 PostReplyWithError(replyID, getStickyError()); 1508 break; 1509 } 1510 1511 status_t err = onReleaseOutputBuffer(msg); 1512 1513 PostReplyWithError(replyID, err); 1514 break; 1515 } 1516 1517 case kWhatSignalEndOfInputStream: 1518 { 1519 uint32_t replyID; 1520 CHECK(msg->senderAwaitsResponse(&replyID)); 1521 1522 if (!isExecuting()) { 1523 PostReplyWithError(replyID, INVALID_OPERATION); 1524 break; 1525 } else if (mFlags & kFlagStickyError) { 1526 PostReplyWithError(replyID, getStickyError()); 1527 break; 1528 } 1529 1530 mReplyID = replyID; 1531 mCodec->signalEndOfInputStream(); 1532 break; 1533 } 1534 1535 case kWhatGetBuffers: 1536 { 1537 uint32_t replyID; 1538 CHECK(msg->senderAwaitsResponse(&replyID)); 1539 1540 if (!isExecuting() || (mFlags & kFlagIsAsync)) { 1541 PostReplyWithError(replyID, INVALID_OPERATION); 1542 break; 1543 } else if (mFlags & kFlagStickyError) { 1544 PostReplyWithError(replyID, getStickyError()); 1545 break; 1546 } 1547 1548 int32_t portIndex; 1549 CHECK(msg->findInt32("portIndex", &portIndex)); 1550 1551 Vector<sp<ABuffer> > *dstBuffers; 1552 CHECK(msg->findPointer("buffers", (void **)&dstBuffers)); 1553 1554 dstBuffers->clear(); 1555 const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex]; 1556 1557 for (size_t i = 0; i < srcBuffers.size(); ++i) { 1558 const BufferInfo &info = srcBuffers.itemAt(i); 1559 1560 dstBuffers->push_back( 1561 (portIndex == kPortIndexInput && mCrypto != NULL) 1562 ? info.mEncryptedData : info.mData); 1563 } 1564 1565 (new AMessage)->postReply(replyID); 1566 break; 1567 } 1568 1569 case kWhatFlush: 1570 { 1571 uint32_t replyID; 1572 CHECK(msg->senderAwaitsResponse(&replyID)); 1573 1574 if (!isExecuting()) { 1575 PostReplyWithError(replyID, INVALID_OPERATION); 1576 break; 1577 } else if (mFlags & kFlagStickyError) { 1578 PostReplyWithError(replyID, getStickyError()); 1579 break; 1580 } 1581 1582 mReplyID = replyID; 1583 // TODO: skip flushing if already FLUSHED 1584 setState(FLUSHING); 1585 1586 mCodec->signalFlush(); 1587 returnBuffersToCodec(); 1588 break; 1589 } 1590 1591 case kWhatGetInputFormat: 1592 case kWhatGetOutputFormat: 1593 { 1594 sp<AMessage> format = 1595 (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat); 1596 1597 uint32_t replyID; 1598 CHECK(msg->senderAwaitsResponse(&replyID)); 1599 1600 if ((mState != CONFIGURED && mState != STARTING && 1601 mState != STARTED && mState != FLUSHING && 1602 mState != FLUSHED) 1603 || format == NULL) { 1604 PostReplyWithError(replyID, INVALID_OPERATION); 1605 break; 1606 } else if (mFlags & kFlagStickyError) { 1607 PostReplyWithError(replyID, getStickyError()); 1608 break; 1609 } 1610 1611 sp<AMessage> response = new AMessage; 1612 response->setMessage("format", format); 1613 response->postReply(replyID); 1614 break; 1615 } 1616 1617 case kWhatRequestIDRFrame: 1618 { 1619 mCodec->signalRequestIDRFrame(); 1620 break; 1621 } 1622 1623 case kWhatRequestActivityNotification: 1624 { 1625 CHECK(mActivityNotify == NULL); 1626 CHECK(msg->findMessage("notify", &mActivityNotify)); 1627 1628 postActivityNotificationIfPossible(); 1629 break; 1630 } 1631 1632 case kWhatGetName: 1633 { 1634 uint32_t replyID; 1635 CHECK(msg->senderAwaitsResponse(&replyID)); 1636 1637 if (mComponentName.empty()) { 1638 PostReplyWithError(replyID, INVALID_OPERATION); 1639 break; 1640 } 1641 1642 sp<AMessage> response = new AMessage; 1643 response->setString("name", mComponentName.c_str()); 1644 response->postReply(replyID); 1645 break; 1646 } 1647 1648 case kWhatSetParameters: 1649 { 1650 uint32_t replyID; 1651 CHECK(msg->senderAwaitsResponse(&replyID)); 1652 1653 sp<AMessage> params; 1654 CHECK(msg->findMessage("params", ¶ms)); 1655 1656 status_t err = onSetParameters(params); 1657 1658 PostReplyWithError(replyID, err); 1659 break; 1660 } 1661 1662 default: 1663 TRESPASS(); 1664 } 1665} 1666 1667void MediaCodec::extractCSD(const sp<AMessage> &format) { 1668 mCSD.clear(); 1669 1670 size_t i = 0; 1671 for (;;) { 1672 sp<ABuffer> csd; 1673 if (!format->findBuffer(StringPrintf("csd-%u", i).c_str(), &csd)) { 1674 break; 1675 } 1676 1677 mCSD.push_back(csd); 1678 ++i; 1679 } 1680 1681 ALOGV("Found %zu pieces of codec specific data.", mCSD.size()); 1682} 1683 1684status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) { 1685 CHECK(!mCSD.empty()); 1686 1687 const BufferInfo *info = 1688 &mPortBuffers[kPortIndexInput].itemAt(bufferIndex); 1689 1690 sp<ABuffer> csd = *mCSD.begin(); 1691 mCSD.erase(mCSD.begin()); 1692 1693 const sp<ABuffer> &codecInputData = 1694 (mCrypto != NULL) ? info->mEncryptedData : info->mData; 1695 1696 if (csd->size() > codecInputData->capacity()) { 1697 return -EINVAL; 1698 } 1699 1700 memcpy(codecInputData->data(), csd->data(), csd->size()); 1701 1702 AString errorDetailMsg; 1703 1704 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id()); 1705 msg->setSize("index", bufferIndex); 1706 msg->setSize("offset", 0); 1707 msg->setSize("size", csd->size()); 1708 msg->setInt64("timeUs", 0ll); 1709 msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG); 1710 msg->setPointer("errorDetailMsg", &errorDetailMsg); 1711 1712 return onQueueInputBuffer(msg); 1713} 1714 1715void MediaCodec::setState(State newState) { 1716 if (newState == INITIALIZED || newState == UNINITIALIZED) { 1717 delete mSoftRenderer; 1718 mSoftRenderer = NULL; 1719 1720 mCrypto.clear(); 1721 setNativeWindow(NULL); 1722 1723 mInputFormat.clear(); 1724 mOutputFormat.clear(); 1725 mFlags &= ~kFlagOutputFormatChanged; 1726 mFlags &= ~kFlagOutputBuffersChanged; 1727 mFlags &= ~kFlagStickyError; 1728 mFlags &= ~kFlagIsEncoder; 1729 mFlags &= ~kFlagGatherCodecSpecificData; 1730 mFlags &= ~kFlagIsAsync; 1731 mStickyError = OK; 1732 1733 mActivityNotify.clear(); 1734 mCallback.clear(); 1735 } 1736 1737 if (newState == UNINITIALIZED) { 1738 // return any straggling buffers, e.g. if we got here on an error 1739 returnBuffersToCodec(); 1740 1741 mComponentName.clear(); 1742 1743 // The component is gone, mediaserver's probably back up already 1744 // but should definitely be back up should we try to instantiate 1745 // another component.. and the cycle continues. 1746 mFlags &= ~kFlagSawMediaServerDie; 1747 } 1748 1749 mState = newState; 1750 1751 cancelPendingDequeueOperations(); 1752 1753 updateBatteryStat(); 1754} 1755 1756void MediaCodec::returnBuffersToCodec() { 1757 returnBuffersToCodecOnPort(kPortIndexInput); 1758 returnBuffersToCodecOnPort(kPortIndexOutput); 1759} 1760 1761void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) { 1762 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 1763 Mutex::Autolock al(mBufferLock); 1764 1765 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 1766 1767 for (size_t i = 0; i < buffers->size(); ++i) { 1768 BufferInfo *info = &buffers->editItemAt(i); 1769 1770 if (info->mNotify != NULL) { 1771 sp<AMessage> msg = info->mNotify; 1772 info->mNotify = NULL; 1773 info->mOwnedByClient = false; 1774 1775 if (portIndex == kPortIndexInput) { 1776 /* no error, just returning buffers */ 1777 msg->setInt32("err", OK); 1778 } 1779 msg->post(); 1780 } 1781 } 1782 1783 mAvailPortBuffers[portIndex].clear(); 1784} 1785 1786size_t MediaCodec::updateBuffers( 1787 int32_t portIndex, const sp<AMessage> &msg) { 1788 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 1789 1790 uint32_t bufferID; 1791 CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); 1792 1793 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 1794 1795 for (size_t i = 0; i < buffers->size(); ++i) { 1796 BufferInfo *info = &buffers->editItemAt(i); 1797 1798 if (info->mBufferID == bufferID) { 1799 CHECK(info->mNotify == NULL); 1800 CHECK(msg->findMessage("reply", &info->mNotify)); 1801 1802 mAvailPortBuffers[portIndex].push_back(i); 1803 1804 return i; 1805 } 1806 } 1807 1808 TRESPASS(); 1809 1810 return 0; 1811} 1812 1813status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) { 1814 size_t index; 1815 size_t offset; 1816 size_t size; 1817 int64_t timeUs; 1818 uint32_t flags; 1819 CHECK(msg->findSize("index", &index)); 1820 CHECK(msg->findSize("offset", &offset)); 1821 CHECK(msg->findInt64("timeUs", &timeUs)); 1822 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1823 1824 const CryptoPlugin::SubSample *subSamples; 1825 size_t numSubSamples; 1826 const uint8_t *key; 1827 const uint8_t *iv; 1828 CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted; 1829 1830 // We allow the simpler queueInputBuffer API to be used even in 1831 // secure mode, by fabricating a single unencrypted subSample. 1832 CryptoPlugin::SubSample ss; 1833 1834 if (msg->findSize("size", &size)) { 1835 if (mCrypto != NULL) { 1836 ss.mNumBytesOfClearData = size; 1837 ss.mNumBytesOfEncryptedData = 0; 1838 1839 subSamples = &ss; 1840 numSubSamples = 1; 1841 key = NULL; 1842 iv = NULL; 1843 } 1844 } else { 1845 if (mCrypto == NULL) { 1846 return -EINVAL; 1847 } 1848 1849 CHECK(msg->findPointer("subSamples", (void **)&subSamples)); 1850 CHECK(msg->findSize("numSubSamples", &numSubSamples)); 1851 CHECK(msg->findPointer("key", (void **)&key)); 1852 CHECK(msg->findPointer("iv", (void **)&iv)); 1853 1854 int32_t tmp; 1855 CHECK(msg->findInt32("mode", &tmp)); 1856 1857 mode = (CryptoPlugin::Mode)tmp; 1858 1859 size = 0; 1860 for (size_t i = 0; i < numSubSamples; ++i) { 1861 size += subSamples[i].mNumBytesOfClearData; 1862 size += subSamples[i].mNumBytesOfEncryptedData; 1863 } 1864 } 1865 1866 if (index >= mPortBuffers[kPortIndexInput].size()) { 1867 return -ERANGE; 1868 } 1869 1870 BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index); 1871 1872 if (info->mNotify == NULL || !info->mOwnedByClient) { 1873 return -EACCES; 1874 } 1875 1876 if (offset + size > info->mData->capacity()) { 1877 return -EINVAL; 1878 } 1879 1880 sp<AMessage> reply = info->mNotify; 1881 info->mData->setRange(offset, size); 1882 info->mData->meta()->setInt64("timeUs", timeUs); 1883 1884 if (flags & BUFFER_FLAG_EOS) { 1885 info->mData->meta()->setInt32("eos", true); 1886 } 1887 1888 if (flags & BUFFER_FLAG_CODECCONFIG) { 1889 info->mData->meta()->setInt32("csd", true); 1890 } 1891 1892 if (mCrypto != NULL) { 1893 if (size > info->mEncryptedData->capacity()) { 1894 return -ERANGE; 1895 } 1896 1897 AString *errorDetailMsg; 1898 CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg)); 1899 1900 ssize_t result = mCrypto->decrypt( 1901 (mFlags & kFlagIsSecure) != 0, 1902 key, 1903 iv, 1904 mode, 1905 info->mEncryptedData->base() + offset, 1906 subSamples, 1907 numSubSamples, 1908 info->mData->base(), 1909 errorDetailMsg); 1910 1911 if (result < 0) { 1912 return result; 1913 } 1914 1915 info->mData->setRange(0, result); 1916 } 1917 1918 // synchronization boundary for getBufferAndFormat 1919 { 1920 Mutex::Autolock al(mBufferLock); 1921 info->mOwnedByClient = false; 1922 } 1923 reply->setBuffer("buffer", info->mData); 1924 reply->post(); 1925 1926 info->mNotify = NULL; 1927 1928 return OK; 1929} 1930 1931status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { 1932 size_t index; 1933 CHECK(msg->findSize("index", &index)); 1934 1935 int32_t render; 1936 if (!msg->findInt32("render", &render)) { 1937 render = 0; 1938 } 1939 1940 if (!isExecuting()) { 1941 return -EINVAL; 1942 } 1943 1944 if (index >= mPortBuffers[kPortIndexOutput].size()) { 1945 return -ERANGE; 1946 } 1947 1948 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index); 1949 1950 if (info->mNotify == NULL || !info->mOwnedByClient) { 1951 return -EACCES; 1952 } 1953 1954 // synchronization boundary for getBufferAndFormat 1955 { 1956 Mutex::Autolock al(mBufferLock); 1957 info->mOwnedByClient = false; 1958 } 1959 1960 if (render && info->mData != NULL && info->mData->size() != 0) { 1961 info->mNotify->setInt32("render", true); 1962 1963 int64_t timestampNs = 0; 1964 if (msg->findInt64("timestampNs", ×tampNs)) { 1965 info->mNotify->setInt64("timestampNs", timestampNs); 1966 } else { 1967 // TODO: it seems like we should use the timestamp 1968 // in the (media)buffer as it potentially came from 1969 // an input surface, but we did not propagate it prior to 1970 // API 20. Perhaps check for target SDK version. 1971#if 0 1972 if (info->mData->meta()->findInt64("timeUs", ×tampNs)) { 1973 ALOGV("using buffer PTS of %" PRId64, timestampNs); 1974 timestampNs *= 1000; 1975 } 1976#endif 1977 } 1978 1979 if (mSoftRenderer != NULL) { 1980 mSoftRenderer->render( 1981 info->mData->data(), info->mData->size(), timestampNs, NULL); 1982 } 1983 } 1984 1985 info->mNotify->post(); 1986 info->mNotify = NULL; 1987 1988 return OK; 1989} 1990 1991ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { 1992 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 1993 1994 List<size_t> *availBuffers = &mAvailPortBuffers[portIndex]; 1995 1996 if (availBuffers->empty()) { 1997 return -EAGAIN; 1998 } 1999 2000 size_t index = *availBuffers->begin(); 2001 availBuffers->erase(availBuffers->begin()); 2002 2003 BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index); 2004 CHECK(!info->mOwnedByClient); 2005 { 2006 Mutex::Autolock al(mBufferLock); 2007 info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat; 2008 info->mOwnedByClient = true; 2009 2010 // set image-data 2011 if (info->mFormat != NULL) { 2012 sp<ABuffer> imageData; 2013 if (info->mFormat->findBuffer("image-data", &imageData)) { 2014 info->mData->meta()->setBuffer("image-data", imageData); 2015 } 2016 int32_t left, top, right, bottom; 2017 if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) { 2018 info->mData->meta()->setRect("crop-rect", left, top, right, bottom); 2019 } 2020 } 2021 } 2022 2023 return index; 2024} 2025 2026status_t MediaCodec::setNativeWindow( 2027 const sp<Surface> &surfaceTextureClient) { 2028 status_t err; 2029 2030 if (mNativeWindow != NULL) { 2031 err = native_window_api_disconnect( 2032 mNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); 2033 2034 if (err != OK) { 2035 ALOGW("native_window_api_disconnect returned an error: %s (%d)", 2036 strerror(-err), err); 2037 } 2038 2039 mNativeWindow.clear(); 2040 } 2041 2042 if (surfaceTextureClient != NULL) { 2043 err = native_window_api_connect( 2044 surfaceTextureClient.get(), NATIVE_WINDOW_API_MEDIA); 2045 2046 if (err != OK) { 2047 ALOGE("native_window_api_connect returned an error: %s (%d)", 2048 strerror(-err), err); 2049 2050 return err; 2051 } 2052 2053 mNativeWindow = surfaceTextureClient; 2054 } 2055 2056 return OK; 2057} 2058 2059void MediaCodec::onInputBufferAvailable() { 2060 int32_t index; 2061 while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) { 2062 sp<AMessage> msg = mCallback->dup(); 2063 msg->setInt32("callbackID", CB_INPUT_AVAILABLE); 2064 msg->setInt32("index", index); 2065 msg->post(); 2066 } 2067} 2068 2069void MediaCodec::onOutputBufferAvailable() { 2070 int32_t index; 2071 while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) { 2072 const sp<ABuffer> &buffer = 2073 mPortBuffers[kPortIndexOutput].itemAt(index).mData; 2074 sp<AMessage> msg = mCallback->dup(); 2075 msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE); 2076 msg->setInt32("index", index); 2077 msg->setSize("offset", buffer->offset()); 2078 msg->setSize("size", buffer->size()); 2079 2080 int64_t timeUs; 2081 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2082 2083 msg->setInt64("timeUs", timeUs); 2084 2085 int32_t omxFlags; 2086 CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags)); 2087 2088 uint32_t flags = 0; 2089 if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) { 2090 flags |= BUFFER_FLAG_SYNCFRAME; 2091 } 2092 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 2093 flags |= BUFFER_FLAG_CODECCONFIG; 2094 } 2095 if (omxFlags & OMX_BUFFERFLAG_EOS) { 2096 flags |= BUFFER_FLAG_EOS; 2097 } 2098 2099 msg->setInt32("flags", flags); 2100 2101 msg->post(); 2102 } 2103} 2104 2105void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) { 2106 if (mCallback != NULL) { 2107 sp<AMessage> msg = mCallback->dup(); 2108 msg->setInt32("callbackID", CB_ERROR); 2109 msg->setInt32("err", err); 2110 msg->setInt32("actionCode", actionCode); 2111 2112 if (detail != NULL) { 2113 msg->setString("detail", detail); 2114 } 2115 2116 msg->post(); 2117 } 2118} 2119 2120void MediaCodec::onOutputFormatChanged() { 2121 if (mCallback != NULL) { 2122 sp<AMessage> msg = mCallback->dup(); 2123 msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED); 2124 msg->setMessage("format", mOutputFormat); 2125 msg->post(); 2126 } 2127} 2128 2129 2130void MediaCodec::postActivityNotificationIfPossible() { 2131 if (mActivityNotify == NULL) { 2132 return; 2133 } 2134 2135 if ((mFlags & (kFlagStickyError 2136 | kFlagOutputBuffersChanged 2137 | kFlagOutputFormatChanged)) 2138 || !mAvailPortBuffers[kPortIndexInput].empty() 2139 || !mAvailPortBuffers[kPortIndexOutput].empty()) { 2140 mActivityNotify->post(); 2141 mActivityNotify.clear(); 2142 } 2143} 2144 2145status_t MediaCodec::setParameters(const sp<AMessage> ¶ms) { 2146 sp<AMessage> msg = new AMessage(kWhatSetParameters, id()); 2147 msg->setMessage("params", params); 2148 2149 sp<AMessage> response; 2150 return PostAndAwaitResponse(msg, &response); 2151} 2152 2153status_t MediaCodec::onSetParameters(const sp<AMessage> ¶ms) { 2154 mCodec->signalSetParameters(params); 2155 2156 return OK; 2157} 2158 2159status_t MediaCodec::amendOutputFormatWithCodecSpecificData( 2160 const sp<ABuffer> &buffer) { 2161 AString mime; 2162 CHECK(mOutputFormat->findString("mime", &mime)); 2163 2164 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) { 2165 // Codec specific data should be SPS and PPS in a single buffer, 2166 // each prefixed by a startcode (0x00 0x00 0x00 0x01). 2167 // We separate the two and put them into the output format 2168 // under the keys "csd-0" and "csd-1". 2169 2170 unsigned csdIndex = 0; 2171 2172 const uint8_t *data = buffer->data(); 2173 size_t size = buffer->size(); 2174 2175 const uint8_t *nalStart; 2176 size_t nalSize; 2177 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { 2178 sp<ABuffer> csd = new ABuffer(nalSize + 4); 2179 memcpy(csd->data(), "\x00\x00\x00\x01", 4); 2180 memcpy(csd->data() + 4, nalStart, nalSize); 2181 2182 mOutputFormat->setBuffer( 2183 StringPrintf("csd-%u", csdIndex).c_str(), csd); 2184 2185 ++csdIndex; 2186 } 2187 2188 if (csdIndex != 2) { 2189 return ERROR_MALFORMED; 2190 } 2191 } else { 2192 // For everything else we just stash the codec specific data into 2193 // the output format as a single piece of csd under "csd-0". 2194 mOutputFormat->setBuffer("csd-0", buffer); 2195 } 2196 2197 return OK; 2198} 2199 2200void MediaCodec::updateBatteryStat() { 2201 if (mState == CONFIGURED && !mBatteryStatNotified) { 2202 AString mime; 2203 CHECK(mOutputFormat != NULL && 2204 mOutputFormat->findString("mime", &mime)); 2205 2206 mIsVideo = mime.startsWithIgnoreCase("video/"); 2207 2208 BatteryNotifier& notifier(BatteryNotifier::getInstance()); 2209 2210 if (mIsVideo) { 2211 notifier.noteStartVideo(); 2212 } else { 2213 notifier.noteStartAudio(); 2214 } 2215 2216 mBatteryStatNotified = true; 2217 } else if (mState == UNINITIALIZED && mBatteryStatNotified) { 2218 BatteryNotifier& notifier(BatteryNotifier::getInstance()); 2219 2220 if (mIsVideo) { 2221 notifier.noteStopVideo(); 2222 } else { 2223 notifier.noteStopAudio(); 2224 } 2225 2226 mBatteryStatNotified = false; 2227 } 2228} 2229 2230} // namespace android 2231