MediaCodec.cpp revision 0d1ed381fde5dac12dd84fcf3da66dac46699378
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/IMemory.h> 25#include <binder/IPCThreadState.h> 26#include <binder/IServiceManager.h> 27#include <binder/MemoryDealer.h> 28#include <gui/BufferQueue.h> 29#include <gui/Surface.h> 30#include <media/ICrypto.h> 31#include <media/IOMX.h> 32#include <media/IResourceManagerService.h> 33#include <media/stagefright/foundation/ABuffer.h> 34#include <media/stagefright/foundation/ADebug.h> 35#include <media/stagefright/foundation/AMessage.h> 36#include <media/stagefright/foundation/AString.h> 37#include <media/stagefright/foundation/hexdump.h> 38#include <media/stagefright/ACodec.h> 39#include <media/stagefright/BufferProducerWrapper.h> 40#include <media/stagefright/MediaCodec.h> 41#include <media/stagefright/MediaCodecList.h> 42#include <media/stagefright/MediaDefs.h> 43#include <media/stagefright/MediaErrors.h> 44#include <media/stagefright/MediaFilter.h> 45#include <media/stagefright/MetaData.h> 46#include <media/stagefright/OMXClient.h> 47#include <media/stagefright/PersistentSurface.h> 48#include <media/stagefright/SurfaceUtils.h> 49#include <mediautils/BatteryNotifier.h> 50#include <private/android_filesystem_config.h> 51#include <utils/Log.h> 52#include <utils/Singleton.h> 53 54namespace android { 55 56static int64_t getId(const sp<IResourceManagerClient> &client) { 57 return (int64_t) client.get(); 58} 59 60static bool isResourceError(status_t err) { 61 return (err == NO_MEMORY); 62} 63 64static const int kMaxRetry = 2; 65static const int kMaxReclaimWaitTimeInUs = 500000; // 0.5s 66 67struct ResourceManagerClient : public BnResourceManagerClient { 68 explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {} 69 70 virtual bool reclaimResource() { 71 sp<MediaCodec> codec = mMediaCodec.promote(); 72 if (codec == NULL) { 73 // codec is already gone. 74 return true; 75 } 76 status_t err = codec->reclaim(); 77 if (err == WOULD_BLOCK) { 78 ALOGD("Wait for the client to release codec."); 79 usleep(kMaxReclaimWaitTimeInUs); 80 ALOGD("Try to reclaim again."); 81 err = codec->reclaim(true /* force */); 82 } 83 if (err != OK) { 84 ALOGW("ResourceManagerClient failed to release codec with err %d", err); 85 } 86 return (err == OK); 87 } 88 89 virtual String8 getName() { 90 String8 ret; 91 sp<MediaCodec> codec = mMediaCodec.promote(); 92 if (codec == NULL) { 93 // codec is already gone. 94 return ret; 95 } 96 97 AString name; 98 if (codec->getName(&name) == OK) { 99 ret.setTo(name.c_str()); 100 } 101 return ret; 102 } 103 104protected: 105 virtual ~ResourceManagerClient() {} 106 107private: 108 wp<MediaCodec> mMediaCodec; 109 110 DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient); 111}; 112 113MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(pid_t pid) 114 : mPid(pid) { 115 if (mPid == MediaCodec::kNoPid) { 116 mPid = IPCThreadState::self()->getCallingPid(); 117 } 118} 119 120MediaCodec::ResourceManagerServiceProxy::~ResourceManagerServiceProxy() { 121 if (mService != NULL) { 122 IInterface::asBinder(mService)->unlinkToDeath(this); 123 } 124} 125 126void MediaCodec::ResourceManagerServiceProxy::init() { 127 sp<IServiceManager> sm = defaultServiceManager(); 128 sp<IBinder> binder = sm->getService(String16("media.resource_manager")); 129 mService = interface_cast<IResourceManagerService>(binder); 130 if (mService == NULL) { 131 ALOGE("Failed to get ResourceManagerService"); 132 return; 133 } 134 IInterface::asBinder(mService)->linkToDeath(this); 135} 136 137void MediaCodec::ResourceManagerServiceProxy::binderDied(const wp<IBinder>& /*who*/) { 138 ALOGW("ResourceManagerService died."); 139 Mutex::Autolock _l(mLock); 140 mService.clear(); 141} 142 143void MediaCodec::ResourceManagerServiceProxy::addResource( 144 int64_t clientId, 145 const sp<IResourceManagerClient> &client, 146 const Vector<MediaResource> &resources) { 147 Mutex::Autolock _l(mLock); 148 if (mService == NULL) { 149 return; 150 } 151 mService->addResource(mPid, clientId, client, resources); 152} 153 154void MediaCodec::ResourceManagerServiceProxy::removeResource(int64_t clientId) { 155 Mutex::Autolock _l(mLock); 156 if (mService == NULL) { 157 return; 158 } 159 mService->removeResource(mPid, clientId); 160} 161 162bool MediaCodec::ResourceManagerServiceProxy::reclaimResource( 163 const Vector<MediaResource> &resources) { 164 Mutex::Autolock _l(mLock); 165 if (mService == NULL) { 166 return false; 167 } 168 return mService->reclaimResource(mPid, resources); 169} 170 171// static 172sp<MediaCodec> MediaCodec::CreateByType( 173 const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid) { 174 sp<MediaCodec> codec = new MediaCodec(looper, pid); 175 176 const status_t ret = codec->init(mime, true /* nameIsType */, encoder); 177 if (err != NULL) { 178 *err = ret; 179 } 180 return ret == OK ? codec : NULL; // NULL deallocates codec. 181} 182 183// static 184sp<MediaCodec> MediaCodec::CreateByComponentName( 185 const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid) { 186 sp<MediaCodec> codec = new MediaCodec(looper, pid); 187 188 const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */); 189 if (err != NULL) { 190 *err = ret; 191 } 192 return ret == OK ? codec : NULL; // NULL deallocates codec. 193} 194 195// static 196status_t MediaCodec::QueryCapabilities( 197 const AString &name, const AString &mime, bool isEncoder, 198 sp<MediaCodecInfo::Capabilities> *caps /* nonnull */) { 199 // TRICKY: this method is used by MediaCodecList/Info during its 200 // initialization. As such, we cannot create a MediaCodec instance 201 // because that requires an initialized MediaCodecList. 202 203 sp<CodecBase> codec = GetCodecBase(name); 204 if (codec == NULL) { 205 return NAME_NOT_FOUND; 206 } 207 208 return codec->queryCapabilities(name, mime, isEncoder, caps); 209} 210 211// static 212sp<PersistentSurface> MediaCodec::CreatePersistentInputSurface() { 213 OMXClient client; 214 CHECK_EQ(client.connect(), (status_t)OK); 215 sp<IOMX> omx = client.interface(); 216 217 const sp<IMediaCodecList> mediaCodecList = MediaCodecList::getInstance(); 218 if (mediaCodecList == NULL) { 219 ALOGE("Failed to obtain MediaCodecList!"); 220 return NULL; // if called from Java should raise IOException 221 } 222 223 AString tmp; 224 sp<AMessage> globalSettings = mediaCodecList->getGlobalSettings(); 225 if (globalSettings == NULL || !globalSettings->findString( 226 kMaxEncoderInputBuffers, &tmp)) { 227 ALOGE("Failed to get encoder input buffer count!"); 228 return NULL; 229 } 230 231 int32_t bufferCount = strtol(tmp.c_str(), NULL, 10); 232 if (bufferCount <= 0 233 || bufferCount > BufferQueue::MAX_MAX_ACQUIRED_BUFFERS) { 234 ALOGE("Encoder input buffer count is invalid!"); 235 return NULL; 236 } 237 238 sp<IGraphicBufferProducer> bufferProducer; 239 sp<IGraphicBufferConsumer> bufferConsumer; 240 241 status_t err = omx->createPersistentInputSurface( 242 &bufferProducer, &bufferConsumer); 243 244 if (err != OK) { 245 ALOGE("Failed to create persistent input surface."); 246 return NULL; 247 } 248 249 err = bufferConsumer->setMaxAcquiredBufferCount(bufferCount); 250 251 if (err != NO_ERROR) { 252 ALOGE("Unable to set BQ max acquired buffer count to %u: %d", 253 bufferCount, err); 254 return NULL; 255 } 256 257 return new PersistentSurface(bufferProducer, bufferConsumer); 258} 259 260MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid) 261 : mState(UNINITIALIZED), 262 mReleasedByResourceManager(false), 263 mLooper(looper), 264 mCodec(NULL), 265 mReplyID(0), 266 mFlags(0), 267 mStickyError(OK), 268 mSoftRenderer(NULL), 269 mResourceManagerClient(new ResourceManagerClient(this)), 270 mResourceManagerService(new ResourceManagerServiceProxy(pid)), 271 mBatteryStatNotified(false), 272 mIsVideo(false), 273 mVideoWidth(0), 274 mVideoHeight(0), 275 mRotationDegrees(0), 276 mDequeueInputTimeoutGeneration(0), 277 mDequeueInputReplyID(0), 278 mDequeueOutputTimeoutGeneration(0), 279 mDequeueOutputReplyID(0), 280 mHaveInputSurface(false), 281 mHavePendingInputBuffers(false) { 282} 283 284MediaCodec::~MediaCodec() { 285 CHECK_EQ(mState, UNINITIALIZED); 286 mResourceManagerService->removeResource(getId(mResourceManagerClient)); 287} 288 289// static 290status_t MediaCodec::PostAndAwaitResponse( 291 const sp<AMessage> &msg, sp<AMessage> *response) { 292 status_t err = msg->postAndAwaitResponse(response); 293 294 if (err != OK) { 295 return err; 296 } 297 298 if (!(*response)->findInt32("err", &err)) { 299 err = OK; 300 } 301 302 return err; 303} 304 305void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) { 306 int32_t finalErr = err; 307 if (mReleasedByResourceManager) { 308 // override the err code if MediaCodec has been released by ResourceManager. 309 finalErr = DEAD_OBJECT; 310 } 311 312 sp<AMessage> response = new AMessage; 313 response->setInt32("err", finalErr); 314 response->postReply(replyID); 315} 316 317//static 318sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, bool nameIsType) { 319 // at this time only ACodec specifies a mime type. 320 if (nameIsType || name.startsWithIgnoreCase("omx.")) { 321 return new ACodec; 322 } else if (name.startsWithIgnoreCase("android.filter.")) { 323 return new MediaFilter; 324 } else { 325 return NULL; 326 } 327} 328 329status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) { 330 mResourceManagerService->init(); 331 332 // save init parameters for reset 333 mInitName = name; 334 mInitNameIsType = nameIsType; 335 mInitIsEncoder = encoder; 336 337 // Current video decoders do not return from OMX_FillThisBuffer 338 // quickly, violating the OpenMAX specs, until that is remedied 339 // we need to invest in an extra looper to free the main event 340 // queue. 341 342 mCodec = GetCodecBase(name, nameIsType); 343 if (mCodec == NULL) { 344 return NAME_NOT_FOUND; 345 } 346 347 bool secureCodec = false; 348 if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) { 349 mIsVideo = true; 350 } else { 351 AString tmp = name; 352 if (tmp.endsWith(".secure")) { 353 secureCodec = true; 354 tmp.erase(tmp.size() - 7, 7); 355 } 356 const sp<IMediaCodecList> mcl = MediaCodecList::getInstance(); 357 if (mcl == NULL) { 358 mCodec = NULL; // remove the codec. 359 return NO_INIT; // if called from Java should raise IOException 360 } 361 ssize_t codecIdx = mcl->findCodecByName(tmp.c_str()); 362 if (codecIdx >= 0) { 363 const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx); 364 Vector<AString> mimes; 365 info->getSupportedMimes(&mimes); 366 for (size_t i = 0; i < mimes.size(); i++) { 367 if (mimes[i].startsWith("video/")) { 368 mIsVideo = true; 369 break; 370 } 371 } 372 } 373 } 374 375 if (mIsVideo) { 376 // video codec needs dedicated looper 377 if (mCodecLooper == NULL) { 378 mCodecLooper = new ALooper; 379 mCodecLooper->setName("CodecLooper"); 380 mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 381 } 382 383 mCodecLooper->registerHandler(mCodec); 384 } else { 385 mLooper->registerHandler(mCodec); 386 } 387 388 mLooper->registerHandler(this); 389 390 mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this)); 391 392 sp<AMessage> msg = new AMessage(kWhatInit, this); 393 msg->setString("name", name); 394 msg->setInt32("nameIsType", nameIsType); 395 396 if (nameIsType) { 397 msg->setInt32("encoder", encoder); 398 } 399 400 status_t err; 401 Vector<MediaResource> resources; 402 const char *type = secureCodec ? kResourceSecureCodec : kResourceNonSecureCodec; 403 const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec; 404 resources.push_back(MediaResource(String8(type), String8(subtype), 1)); 405 for (int i = 0; i <= kMaxRetry; ++i) { 406 if (i > 0) { 407 // Don't try to reclaim resource for the first time. 408 if (!mResourceManagerService->reclaimResource(resources)) { 409 break; 410 } 411 } 412 413 sp<AMessage> response; 414 err = PostAndAwaitResponse(msg, &response); 415 if (!isResourceError(err)) { 416 break; 417 } 418 } 419 return err; 420} 421 422status_t MediaCodec::setCallback(const sp<AMessage> &callback) { 423 sp<AMessage> msg = new AMessage(kWhatSetCallback, this); 424 msg->setMessage("callback", callback); 425 426 sp<AMessage> response; 427 return PostAndAwaitResponse(msg, &response); 428} 429 430status_t MediaCodec::setOnFrameRenderedNotification(const sp<AMessage> ¬ify) { 431 sp<AMessage> msg = new AMessage(kWhatSetNotification, this); 432 msg->setMessage("on-frame-rendered", notify); 433 return msg->post(); 434} 435 436status_t MediaCodec::configure( 437 const sp<AMessage> &format, 438 const sp<Surface> &surface, 439 const sp<ICrypto> &crypto, 440 uint32_t flags) { 441 sp<AMessage> msg = new AMessage(kWhatConfigure, this); 442 443 if (mIsVideo) { 444 format->findInt32("width", &mVideoWidth); 445 format->findInt32("height", &mVideoHeight); 446 if (!format->findInt32("rotation-degrees", &mRotationDegrees)) { 447 mRotationDegrees = 0; 448 } 449 } 450 451 msg->setMessage("format", format); 452 msg->setInt32("flags", flags); 453 msg->setObject("surface", surface); 454 455 if (crypto != NULL) { 456 msg->setPointer("crypto", crypto.get()); 457 } 458 459 // save msg for reset 460 mConfigureMsg = msg; 461 462 status_t err; 463 Vector<MediaResource> resources; 464 const char *type = (mFlags & kFlagIsSecure) ? 465 kResourceSecureCodec : kResourceNonSecureCodec; 466 const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec; 467 resources.push_back(MediaResource(String8(type), String8(subtype), 1)); 468 // Don't know the buffer size at this point, but it's fine to use 1 because 469 // the reclaimResource call doesn't consider the requester's buffer size for now. 470 resources.push_back(MediaResource(String8(kResourceGraphicMemory), 1)); 471 for (int i = 0; i <= kMaxRetry; ++i) { 472 if (i > 0) { 473 // Don't try to reclaim resource for the first time. 474 if (!mResourceManagerService->reclaimResource(resources)) { 475 break; 476 } 477 } 478 479 sp<AMessage> response; 480 err = PostAndAwaitResponse(msg, &response); 481 if (err != OK && err != INVALID_OPERATION) { 482 // MediaCodec now set state to UNINITIALIZED upon any fatal error. 483 // To maintain backward-compatibility, do a reset() to put codec 484 // back into INITIALIZED state. 485 // But don't reset if the err is INVALID_OPERATION, which means 486 // the configure failure is due to wrong state. 487 488 ALOGE("configure failed with err 0x%08x, resetting...", err); 489 reset(); 490 } 491 if (!isResourceError(err)) { 492 break; 493 } 494 } 495 return err; 496} 497 498status_t MediaCodec::setInputSurface( 499 const sp<PersistentSurface> &surface) { 500 sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this); 501 msg->setObject("input-surface", surface.get()); 502 503 sp<AMessage> response; 504 return PostAndAwaitResponse(msg, &response); 505} 506 507status_t MediaCodec::setSurface(const sp<Surface> &surface) { 508 sp<AMessage> msg = new AMessage(kWhatSetSurface, this); 509 msg->setObject("surface", surface); 510 511 sp<AMessage> response; 512 return PostAndAwaitResponse(msg, &response); 513} 514 515status_t MediaCodec::createInputSurface( 516 sp<IGraphicBufferProducer>* bufferProducer) { 517 sp<AMessage> msg = new AMessage(kWhatCreateInputSurface, this); 518 519 sp<AMessage> response; 520 status_t err = PostAndAwaitResponse(msg, &response); 521 if (err == NO_ERROR) { 522 // unwrap the sp<IGraphicBufferProducer> 523 sp<RefBase> obj; 524 bool found = response->findObject("input-surface", &obj); 525 CHECK(found); 526 sp<BufferProducerWrapper> wrapper( 527 static_cast<BufferProducerWrapper*>(obj.get())); 528 *bufferProducer = wrapper->getBufferProducer(); 529 } else { 530 ALOGW("createInputSurface failed, err=%d", err); 531 } 532 return err; 533} 534 535uint64_t MediaCodec::getGraphicBufferSize() { 536 if (!mIsVideo) { 537 return 0; 538 } 539 540 uint64_t size = 0; 541 size_t portNum = sizeof(mPortBuffers) / sizeof((mPortBuffers)[0]); 542 for (size_t i = 0; i < portNum; ++i) { 543 // TODO: this is just an estimation, we should get the real buffer size from ACodec. 544 size += mPortBuffers[i].size() * mVideoWidth * mVideoHeight * 3 / 2; 545 } 546 return size; 547} 548 549void MediaCodec::addResource(const String8 &type, const String8 &subtype, uint64_t value) { 550 Vector<MediaResource> resources; 551 resources.push_back(MediaResource(type, subtype, value)); 552 mResourceManagerService->addResource( 553 getId(mResourceManagerClient), mResourceManagerClient, resources); 554} 555 556status_t MediaCodec::start() { 557 sp<AMessage> msg = new AMessage(kWhatStart, this); 558 559 status_t err; 560 Vector<MediaResource> resources; 561 const char *type = (mFlags & kFlagIsSecure) ? 562 kResourceSecureCodec : kResourceNonSecureCodec; 563 const char *subtype = mIsVideo ? kResourceVideoCodec : kResourceAudioCodec; 564 resources.push_back(MediaResource(String8(type), String8(subtype), 1)); 565 // Don't know the buffer size at this point, but it's fine to use 1 because 566 // the reclaimResource call doesn't consider the requester's buffer size for now. 567 resources.push_back(MediaResource(String8(kResourceGraphicMemory), 1)); 568 for (int i = 0; i <= kMaxRetry; ++i) { 569 if (i > 0) { 570 // Don't try to reclaim resource for the first time. 571 if (!mResourceManagerService->reclaimResource(resources)) { 572 break; 573 } 574 // Recover codec from previous error before retry start. 575 err = reset(); 576 if (err != OK) { 577 ALOGE("retrying start: failed to reset codec"); 578 break; 579 } 580 sp<AMessage> response; 581 err = PostAndAwaitResponse(mConfigureMsg, &response); 582 if (err != OK) { 583 ALOGE("retrying start: failed to configure codec"); 584 break; 585 } 586 } 587 588 sp<AMessage> response; 589 err = PostAndAwaitResponse(msg, &response); 590 if (!isResourceError(err)) { 591 break; 592 } 593 } 594 return err; 595} 596 597status_t MediaCodec::stop() { 598 sp<AMessage> msg = new AMessage(kWhatStop, this); 599 600 sp<AMessage> response; 601 return PostAndAwaitResponse(msg, &response); 602} 603 604bool MediaCodec::hasPendingBuffer(int portIndex) { 605 const Vector<BufferInfo> &buffers = mPortBuffers[portIndex]; 606 for (size_t i = 0; i < buffers.size(); ++i) { 607 const BufferInfo &info = buffers.itemAt(i); 608 if (info.mOwnedByClient) { 609 return true; 610 } 611 } 612 return false; 613} 614 615bool MediaCodec::hasPendingBuffer() { 616 return hasPendingBuffer(kPortIndexInput) || hasPendingBuffer(kPortIndexOutput); 617} 618 619status_t MediaCodec::reclaim(bool force) { 620 ALOGD("MediaCodec::reclaim(%p) %s", this, mInitName.c_str()); 621 sp<AMessage> msg = new AMessage(kWhatRelease, this); 622 msg->setInt32("reclaimed", 1); 623 msg->setInt32("force", force ? 1 : 0); 624 625 sp<AMessage> response; 626 status_t ret = PostAndAwaitResponse(msg, &response); 627 if (ret == -ENOENT) { 628 ALOGD("MediaCodec looper is gone, skip reclaim"); 629 ret = OK; 630 } 631 return ret; 632} 633 634status_t MediaCodec::release() { 635 sp<AMessage> msg = new AMessage(kWhatRelease, this); 636 637 sp<AMessage> response; 638 return PostAndAwaitResponse(msg, &response); 639} 640 641status_t MediaCodec::reset() { 642 /* When external-facing MediaCodec object is created, 643 it is already initialized. Thus, reset is essentially 644 release() followed by init(), plus clearing the state */ 645 646 status_t err = release(); 647 648 // unregister handlers 649 if (mCodec != NULL) { 650 if (mCodecLooper != NULL) { 651 mCodecLooper->unregisterHandler(mCodec->id()); 652 } else { 653 mLooper->unregisterHandler(mCodec->id()); 654 } 655 mCodec = NULL; 656 } 657 mLooper->unregisterHandler(id()); 658 659 mFlags = 0; // clear all flags 660 mStickyError = OK; 661 662 // reset state not reset by setState(UNINITIALIZED) 663 mReplyID = 0; 664 mDequeueInputReplyID = 0; 665 mDequeueOutputReplyID = 0; 666 mDequeueInputTimeoutGeneration = 0; 667 mDequeueOutputTimeoutGeneration = 0; 668 mHaveInputSurface = false; 669 670 if (err == OK) { 671 err = init(mInitName, mInitNameIsType, mInitIsEncoder); 672 } 673 return err; 674} 675 676status_t MediaCodec::queueInputBuffer( 677 size_t index, 678 size_t offset, 679 size_t size, 680 int64_t presentationTimeUs, 681 uint32_t flags, 682 AString *errorDetailMsg) { 683 if (errorDetailMsg != NULL) { 684 errorDetailMsg->clear(); 685 } 686 687 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this); 688 msg->setSize("index", index); 689 msg->setSize("offset", offset); 690 msg->setSize("size", size); 691 msg->setInt64("timeUs", presentationTimeUs); 692 msg->setInt32("flags", flags); 693 msg->setPointer("errorDetailMsg", errorDetailMsg); 694 695 sp<AMessage> response; 696 return PostAndAwaitResponse(msg, &response); 697} 698 699status_t MediaCodec::queueSecureInputBuffer( 700 size_t index, 701 size_t offset, 702 const CryptoPlugin::SubSample *subSamples, 703 size_t numSubSamples, 704 const uint8_t key[16], 705 const uint8_t iv[16], 706 CryptoPlugin::Mode mode, 707 int64_t presentationTimeUs, 708 uint32_t flags, 709 AString *errorDetailMsg) { 710 if (errorDetailMsg != NULL) { 711 errorDetailMsg->clear(); 712 } 713 714 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this); 715 msg->setSize("index", index); 716 msg->setSize("offset", offset); 717 msg->setPointer("subSamples", (void *)subSamples); 718 msg->setSize("numSubSamples", numSubSamples); 719 msg->setPointer("key", (void *)key); 720 msg->setPointer("iv", (void *)iv); 721 msg->setInt32("mode", mode); 722 msg->setInt64("timeUs", presentationTimeUs); 723 msg->setInt32("flags", flags); 724 msg->setPointer("errorDetailMsg", errorDetailMsg); 725 726 sp<AMessage> response; 727 status_t err = PostAndAwaitResponse(msg, &response); 728 729 return err; 730} 731 732status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { 733 sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, this); 734 msg->setInt64("timeoutUs", timeoutUs); 735 736 sp<AMessage> response; 737 status_t err; 738 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { 739 return err; 740 } 741 742 CHECK(response->findSize("index", index)); 743 744 return OK; 745} 746 747status_t MediaCodec::dequeueOutputBuffer( 748 size_t *index, 749 size_t *offset, 750 size_t *size, 751 int64_t *presentationTimeUs, 752 uint32_t *flags, 753 int64_t timeoutUs) { 754 sp<AMessage> msg = new AMessage(kWhatDequeueOutputBuffer, this); 755 msg->setInt64("timeoutUs", timeoutUs); 756 757 sp<AMessage> response; 758 status_t err; 759 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { 760 return err; 761 } 762 763 CHECK(response->findSize("index", index)); 764 CHECK(response->findSize("offset", offset)); 765 CHECK(response->findSize("size", size)); 766 CHECK(response->findInt64("timeUs", presentationTimeUs)); 767 CHECK(response->findInt32("flags", (int32_t *)flags)); 768 769 return OK; 770} 771 772status_t MediaCodec::renderOutputBufferAndRelease(size_t index) { 773 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this); 774 msg->setSize("index", index); 775 msg->setInt32("render", true); 776 777 sp<AMessage> response; 778 return PostAndAwaitResponse(msg, &response); 779} 780 781status_t MediaCodec::renderOutputBufferAndRelease(size_t index, int64_t timestampNs) { 782 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this); 783 msg->setSize("index", index); 784 msg->setInt32("render", true); 785 msg->setInt64("timestampNs", timestampNs); 786 787 sp<AMessage> response; 788 return PostAndAwaitResponse(msg, &response); 789} 790 791status_t MediaCodec::releaseOutputBuffer(size_t index) { 792 sp<AMessage> msg = new AMessage(kWhatReleaseOutputBuffer, this); 793 msg->setSize("index", index); 794 795 sp<AMessage> response; 796 return PostAndAwaitResponse(msg, &response); 797} 798 799status_t MediaCodec::signalEndOfInputStream() { 800 sp<AMessage> msg = new AMessage(kWhatSignalEndOfInputStream, this); 801 802 sp<AMessage> response; 803 return PostAndAwaitResponse(msg, &response); 804} 805 806status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const { 807 sp<AMessage> msg = new AMessage(kWhatGetOutputFormat, this); 808 809 sp<AMessage> response; 810 status_t err; 811 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { 812 return err; 813 } 814 815 CHECK(response->findMessage("format", format)); 816 817 return OK; 818} 819 820status_t MediaCodec::getInputFormat(sp<AMessage> *format) const { 821 sp<AMessage> msg = new AMessage(kWhatGetInputFormat, this); 822 823 sp<AMessage> response; 824 status_t err; 825 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { 826 return err; 827 } 828 829 CHECK(response->findMessage("format", format)); 830 831 return OK; 832} 833 834status_t MediaCodec::getName(AString *name) const { 835 sp<AMessage> msg = new AMessage(kWhatGetName, this); 836 837 sp<AMessage> response; 838 status_t err; 839 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { 840 return err; 841 } 842 843 CHECK(response->findString("name", name)); 844 845 return OK; 846} 847 848status_t MediaCodec::getWidevineLegacyBuffers(Vector<sp<ABuffer> > *buffers) const { 849 sp<AMessage> msg = new AMessage(kWhatGetBuffers, this); 850 msg->setInt32("portIndex", kPortIndexInput); 851 msg->setPointer("buffers", buffers); 852 msg->setInt32("widevine", true); 853 854 sp<AMessage> response; 855 return PostAndAwaitResponse(msg, &response); 856} 857 858status_t MediaCodec::getInputBuffers(Vector<sp<ABuffer> > *buffers) const { 859 sp<AMessage> msg = new AMessage(kWhatGetBuffers, this); 860 msg->setInt32("portIndex", kPortIndexInput); 861 msg->setPointer("buffers", buffers); 862 863 sp<AMessage> response; 864 return PostAndAwaitResponse(msg, &response); 865} 866 867status_t MediaCodec::getOutputBuffers(Vector<sp<ABuffer> > *buffers) const { 868 sp<AMessage> msg = new AMessage(kWhatGetBuffers, this); 869 msg->setInt32("portIndex", kPortIndexOutput); 870 msg->setPointer("buffers", buffers); 871 872 sp<AMessage> response; 873 return PostAndAwaitResponse(msg, &response); 874} 875 876status_t MediaCodec::getOutputBuffer(size_t index, sp<ABuffer> *buffer) { 877 sp<AMessage> format; 878 return getBufferAndFormat(kPortIndexOutput, index, buffer, &format); 879} 880 881status_t MediaCodec::getOutputFormat(size_t index, sp<AMessage> *format) { 882 sp<ABuffer> buffer; 883 return getBufferAndFormat(kPortIndexOutput, index, &buffer, format); 884} 885 886status_t MediaCodec::getInputBuffer(size_t index, sp<ABuffer> *buffer) { 887 sp<AMessage> format; 888 return getBufferAndFormat(kPortIndexInput, index, buffer, &format); 889} 890 891bool MediaCodec::isExecuting() const { 892 return mState == STARTED || mState == FLUSHED; 893} 894 895status_t MediaCodec::getBufferAndFormat( 896 size_t portIndex, size_t index, 897 sp<ABuffer> *buffer, sp<AMessage> *format) { 898 // use mutex instead of a context switch 899 900 if (mReleasedByResourceManager) { 901 return DEAD_OBJECT; 902 } 903 904 buffer->clear(); 905 format->clear(); 906 if (!isExecuting()) { 907 return INVALID_OPERATION; 908 } 909 910 // we do not want mPortBuffers to change during this section 911 // we also don't want mOwnedByClient to change during this 912 Mutex::Autolock al(mBufferLock); 913 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 914 if (index < buffers->size()) { 915 const BufferInfo &info = buffers->itemAt(index); 916 if (info.mOwnedByClient) { 917 // by the time buffers array is initialized, crypto is set 918 if (portIndex == kPortIndexInput && mCrypto != NULL) { 919 *buffer = info.mEncryptedData; 920 } else { 921 *buffer = info.mData; 922 } 923 *format = info.mFormat; 924 } 925 } 926 return OK; 927} 928 929status_t MediaCodec::flush() { 930 sp<AMessage> msg = new AMessage(kWhatFlush, this); 931 932 sp<AMessage> response; 933 return PostAndAwaitResponse(msg, &response); 934} 935 936status_t MediaCodec::requestIDRFrame() { 937 (new AMessage(kWhatRequestIDRFrame, this))->post(); 938 939 return OK; 940} 941 942void MediaCodec::requestActivityNotification(const sp<AMessage> ¬ify) { 943 sp<AMessage> msg = new AMessage(kWhatRequestActivityNotification, this); 944 msg->setMessage("notify", notify); 945 msg->post(); 946} 947 948//////////////////////////////////////////////////////////////////////////////// 949 950void MediaCodec::cancelPendingDequeueOperations() { 951 if (mFlags & kFlagDequeueInputPending) { 952 PostReplyWithError(mDequeueInputReplyID, INVALID_OPERATION); 953 954 ++mDequeueInputTimeoutGeneration; 955 mDequeueInputReplyID = 0; 956 mFlags &= ~kFlagDequeueInputPending; 957 } 958 959 if (mFlags & kFlagDequeueOutputPending) { 960 PostReplyWithError(mDequeueOutputReplyID, INVALID_OPERATION); 961 962 ++mDequeueOutputTimeoutGeneration; 963 mDequeueOutputReplyID = 0; 964 mFlags &= ~kFlagDequeueOutputPending; 965 } 966} 967 968bool MediaCodec::handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest) { 969 if (!isExecuting() || (mFlags & kFlagIsAsync) 970 || (newRequest && (mFlags & kFlagDequeueInputPending))) { 971 PostReplyWithError(replyID, INVALID_OPERATION); 972 return true; 973 } else if (mFlags & kFlagStickyError) { 974 PostReplyWithError(replyID, getStickyError()); 975 return true; 976 } 977 978 ssize_t index = dequeuePortBuffer(kPortIndexInput); 979 980 if (index < 0) { 981 CHECK_EQ(index, -EAGAIN); 982 return false; 983 } 984 985 sp<AMessage> response = new AMessage; 986 response->setSize("index", index); 987 response->postReply(replyID); 988 989 return true; 990} 991 992bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) { 993 if (!isExecuting() || (mFlags & kFlagIsAsync) 994 || (newRequest && (mFlags & kFlagDequeueOutputPending))) { 995 PostReplyWithError(replyID, INVALID_OPERATION); 996 } else if (mFlags & kFlagStickyError) { 997 PostReplyWithError(replyID, getStickyError()); 998 } else if (mFlags & kFlagOutputBuffersChanged) { 999 PostReplyWithError(replyID, INFO_OUTPUT_BUFFERS_CHANGED); 1000 mFlags &= ~kFlagOutputBuffersChanged; 1001 } else if (mFlags & kFlagOutputFormatChanged) { 1002 PostReplyWithError(replyID, INFO_FORMAT_CHANGED); 1003 mFlags &= ~kFlagOutputFormatChanged; 1004 } else { 1005 sp<AMessage> response = new AMessage; 1006 ssize_t index = dequeuePortBuffer(kPortIndexOutput); 1007 1008 if (index < 0) { 1009 CHECK_EQ(index, -EAGAIN); 1010 return false; 1011 } 1012 1013 const sp<ABuffer> &buffer = 1014 mPortBuffers[kPortIndexOutput].itemAt(index).mData; 1015 1016 response->setSize("index", index); 1017 response->setSize("offset", buffer->offset()); 1018 response->setSize("size", buffer->size()); 1019 1020 int64_t timeUs; 1021 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 1022 1023 response->setInt64("timeUs", timeUs); 1024 1025 int32_t omxFlags; 1026 CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags)); 1027 1028 uint32_t flags = 0; 1029 if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) { 1030 flags |= BUFFER_FLAG_SYNCFRAME; 1031 } 1032 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 1033 flags |= BUFFER_FLAG_CODECCONFIG; 1034 } 1035 if (omxFlags & OMX_BUFFERFLAG_EOS) { 1036 flags |= BUFFER_FLAG_EOS; 1037 } 1038 1039 response->setInt32("flags", flags); 1040 response->postReply(replyID); 1041 } 1042 1043 return true; 1044} 1045 1046void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { 1047 switch (msg->what()) { 1048 case kWhatCodecNotify: 1049 { 1050 int32_t what; 1051 CHECK(msg->findInt32("what", &what)); 1052 1053 switch (what) { 1054 case CodecBase::kWhatError: 1055 { 1056 int32_t err, actionCode; 1057 CHECK(msg->findInt32("err", &err)); 1058 CHECK(msg->findInt32("actionCode", &actionCode)); 1059 1060 ALOGE("Codec reported err %#x, actionCode %d, while in state %d", 1061 err, actionCode, mState); 1062 if (err == DEAD_OBJECT) { 1063 mFlags |= kFlagSawMediaServerDie; 1064 mFlags &= ~kFlagIsComponentAllocated; 1065 } 1066 1067 bool sendErrorResponse = true; 1068 1069 switch (mState) { 1070 case INITIALIZING: 1071 { 1072 setState(UNINITIALIZED); 1073 break; 1074 } 1075 1076 case CONFIGURING: 1077 { 1078 setState(actionCode == ACTION_CODE_FATAL ? 1079 UNINITIALIZED : INITIALIZED); 1080 break; 1081 } 1082 1083 case STARTING: 1084 { 1085 setState(actionCode == ACTION_CODE_FATAL ? 1086 UNINITIALIZED : CONFIGURED); 1087 break; 1088 } 1089 1090 case STOPPING: 1091 case RELEASING: 1092 { 1093 // Ignore the error, assuming we'll still get 1094 // the shutdown complete notification. 1095 1096 sendErrorResponse = false; 1097 1098 if (mFlags & kFlagSawMediaServerDie) { 1099 // MediaServer died, there definitely won't 1100 // be a shutdown complete notification after 1101 // all. 1102 1103 // note that we're directly going from 1104 // STOPPING->UNINITIALIZED, instead of the 1105 // usual STOPPING->INITIALIZED state. 1106 setState(UNINITIALIZED); 1107 if (mState == RELEASING) { 1108 mComponentName.clear(); 1109 } 1110 (new AMessage)->postReply(mReplyID); 1111 } 1112 break; 1113 } 1114 1115 case FLUSHING: 1116 { 1117 if (actionCode == ACTION_CODE_FATAL) { 1118 setState(UNINITIALIZED); 1119 } else { 1120 setState( 1121 (mFlags & kFlagIsAsync) ? FLUSHED : STARTED); 1122 } 1123 break; 1124 } 1125 1126 case FLUSHED: 1127 case STARTED: 1128 { 1129 sendErrorResponse = false; 1130 1131 setStickyError(err); 1132 postActivityNotificationIfPossible(); 1133 1134 cancelPendingDequeueOperations(); 1135 1136 if (mFlags & kFlagIsAsync) { 1137 onError(err, actionCode); 1138 } 1139 switch (actionCode) { 1140 case ACTION_CODE_TRANSIENT: 1141 break; 1142 case ACTION_CODE_RECOVERABLE: 1143 setState(INITIALIZED); 1144 break; 1145 default: 1146 setState(UNINITIALIZED); 1147 break; 1148 } 1149 break; 1150 } 1151 1152 default: 1153 { 1154 sendErrorResponse = false; 1155 1156 setStickyError(err); 1157 postActivityNotificationIfPossible(); 1158 1159 // actionCode in an uninitialized state is always fatal. 1160 if (mState == UNINITIALIZED) { 1161 actionCode = ACTION_CODE_FATAL; 1162 } 1163 if (mFlags & kFlagIsAsync) { 1164 onError(err, actionCode); 1165 } 1166 switch (actionCode) { 1167 case ACTION_CODE_TRANSIENT: 1168 break; 1169 case ACTION_CODE_RECOVERABLE: 1170 setState(INITIALIZED); 1171 break; 1172 default: 1173 setState(UNINITIALIZED); 1174 break; 1175 } 1176 break; 1177 } 1178 } 1179 1180 if (sendErrorResponse) { 1181 PostReplyWithError(mReplyID, err); 1182 } 1183 break; 1184 } 1185 1186 case CodecBase::kWhatComponentAllocated: 1187 { 1188 CHECK_EQ(mState, INITIALIZING); 1189 setState(INITIALIZED); 1190 mFlags |= kFlagIsComponentAllocated; 1191 1192 CHECK(msg->findString("componentName", &mComponentName)); 1193 1194 if (mComponentName.startsWith("OMX.google.")) { 1195 mFlags |= kFlagUsesSoftwareRenderer; 1196 } else { 1197 mFlags &= ~kFlagUsesSoftwareRenderer; 1198 } 1199 1200 String8 resourceType; 1201 if (mComponentName.endsWith(".secure")) { 1202 mFlags |= kFlagIsSecure; 1203 resourceType = String8(kResourceSecureCodec); 1204 } else { 1205 mFlags &= ~kFlagIsSecure; 1206 resourceType = String8(kResourceNonSecureCodec); 1207 } 1208 1209 if (mIsVideo) { 1210 // audio codec is currently ignored. 1211 addResource(resourceType, String8(kResourceVideoCodec), 1); 1212 } 1213 1214 (new AMessage)->postReply(mReplyID); 1215 break; 1216 } 1217 1218 case CodecBase::kWhatComponentConfigured: 1219 { 1220 if (mState == UNINITIALIZED || mState == INITIALIZED) { 1221 // In case a kWhatError message came in and replied with error, 1222 // we log a warning and ignore. 1223 ALOGW("configure interrupted by error, current state %d", mState); 1224 break; 1225 } 1226 CHECK_EQ(mState, CONFIGURING); 1227 1228 // reset input surface flag 1229 mHaveInputSurface = false; 1230 1231 CHECK(msg->findMessage("input-format", &mInputFormat)); 1232 CHECK(msg->findMessage("output-format", &mOutputFormat)); 1233 1234 int32_t usingSwRenderer; 1235 if (mOutputFormat->findInt32("using-sw-renderer", &usingSwRenderer) 1236 && usingSwRenderer) { 1237 mFlags |= kFlagUsesSoftwareRenderer; 1238 } 1239 setState(CONFIGURED); 1240 (new AMessage)->postReply(mReplyID); 1241 break; 1242 } 1243 1244 case CodecBase::kWhatInputSurfaceCreated: 1245 { 1246 // response to initiateCreateInputSurface() 1247 status_t err = NO_ERROR; 1248 sp<AMessage> response = new AMessage; 1249 if (!msg->findInt32("err", &err)) { 1250 sp<RefBase> obj; 1251 msg->findObject("input-surface", &obj); 1252 CHECK(obj != NULL); 1253 response->setObject("input-surface", obj); 1254 mHaveInputSurface = true; 1255 } else { 1256 response->setInt32("err", err); 1257 } 1258 response->postReply(mReplyID); 1259 break; 1260 } 1261 1262 case CodecBase::kWhatInputSurfaceAccepted: 1263 { 1264 // response to initiateSetInputSurface() 1265 status_t err = NO_ERROR; 1266 sp<AMessage> response = new AMessage(); 1267 if (!msg->findInt32("err", &err)) { 1268 mHaveInputSurface = true; 1269 } else { 1270 response->setInt32("err", err); 1271 } 1272 response->postReply(mReplyID); 1273 break; 1274 } 1275 1276 case CodecBase::kWhatSignaledInputEOS: 1277 { 1278 // response to signalEndOfInputStream() 1279 sp<AMessage> response = new AMessage; 1280 status_t err; 1281 if (msg->findInt32("err", &err)) { 1282 response->setInt32("err", err); 1283 } 1284 response->postReply(mReplyID); 1285 break; 1286 } 1287 1288 1289 case CodecBase::kWhatBuffersAllocated: 1290 { 1291 Mutex::Autolock al(mBufferLock); 1292 int32_t portIndex; 1293 CHECK(msg->findInt32("portIndex", &portIndex)); 1294 1295 ALOGV("%s buffers allocated", 1296 portIndex == kPortIndexInput ? "input" : "output"); 1297 1298 CHECK(portIndex == kPortIndexInput 1299 || portIndex == kPortIndexOutput); 1300 1301 mPortBuffers[portIndex].clear(); 1302 1303 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 1304 1305 sp<RefBase> obj; 1306 CHECK(msg->findObject("portDesc", &obj)); 1307 1308 sp<CodecBase::PortDescription> portDesc = 1309 static_cast<CodecBase::PortDescription *>(obj.get()); 1310 1311 size_t numBuffers = portDesc->countBuffers(); 1312 1313 size_t totalSize = 0; 1314 for (size_t i = 0; i < numBuffers; ++i) { 1315 if (portIndex == kPortIndexInput && mCrypto != NULL) { 1316 totalSize += portDesc->bufferAt(i)->capacity(); 1317 } 1318 } 1319 1320 if (totalSize) { 1321 mDealer = new MemoryDealer(totalSize, "MediaCodec"); 1322 } 1323 1324 for (size_t i = 0; i < numBuffers; ++i) { 1325 BufferInfo info; 1326 info.mBufferID = portDesc->bufferIDAt(i); 1327 info.mOwnedByClient = false; 1328 info.mData = portDesc->bufferAt(i); 1329 1330 if (portIndex == kPortIndexInput && mCrypto != NULL) { 1331 sp<IMemory> mem = mDealer->allocate(info.mData->capacity()); 1332 info.mEncryptedData = 1333 new ABuffer(mem->pointer(), info.mData->capacity()); 1334 info.mSharedEncryptedBuffer = mem; 1335 } 1336 1337 buffers->push_back(info); 1338 } 1339 1340 if (portIndex == kPortIndexOutput) { 1341 if (mState == STARTING) { 1342 // We're always allocating output buffers after 1343 // allocating input buffers, so this is a good 1344 // indication that now all buffers are allocated. 1345 if (mIsVideo) { 1346 String8 subtype; 1347 addResource( 1348 String8(kResourceGraphicMemory), 1349 subtype, 1350 getGraphicBufferSize()); 1351 } 1352 setState(STARTED); 1353 (new AMessage)->postReply(mReplyID); 1354 } else { 1355 mFlags |= kFlagOutputBuffersChanged; 1356 postActivityNotificationIfPossible(); 1357 } 1358 } 1359 break; 1360 } 1361 1362 case CodecBase::kWhatOutputFormatChanged: 1363 { 1364 ALOGV("codec output format changed"); 1365 1366 if (mSoftRenderer == NULL && 1367 mSurface != NULL && 1368 (mFlags & kFlagUsesSoftwareRenderer)) { 1369 AString mime; 1370 CHECK(msg->findString("mime", &mime)); 1371 1372 if (mime.startsWithIgnoreCase("video/")) { 1373 mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees); 1374 } 1375 } 1376 1377 mOutputFormat = msg; 1378 1379 if (mFlags & kFlagIsEncoder) { 1380 // Before we announce the format change we should 1381 // collect codec specific data and amend the output 1382 // format as necessary. 1383 mFlags |= kFlagGatherCodecSpecificData; 1384 } else if (mFlags & kFlagIsAsync) { 1385 onOutputFormatChanged(); 1386 } else { 1387 mFlags |= kFlagOutputFormatChanged; 1388 postActivityNotificationIfPossible(); 1389 } 1390 1391 // Notify mCrypto of video resolution changes 1392 if (mCrypto != NULL) { 1393 int32_t left, top, right, bottom, width, height; 1394 if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) { 1395 mCrypto->notifyResolution(right - left + 1, bottom - top + 1); 1396 } else if (mOutputFormat->findInt32("width", &width) 1397 && mOutputFormat->findInt32("height", &height)) { 1398 mCrypto->notifyResolution(width, height); 1399 } 1400 } 1401 1402 break; 1403 } 1404 1405 case CodecBase::kWhatOutputFramesRendered: 1406 { 1407 // ignore these in all states except running, and check that we have a 1408 // notification set 1409 if (mState == STARTED && mOnFrameRenderedNotification != NULL) { 1410 sp<AMessage> notify = mOnFrameRenderedNotification->dup(); 1411 notify->setMessage("data", msg); 1412 notify->post(); 1413 } 1414 break; 1415 } 1416 1417 case CodecBase::kWhatFillThisBuffer: 1418 { 1419 /* size_t index = */updateBuffers(kPortIndexInput, msg); 1420 1421 if (mState == FLUSHING 1422 || mState == STOPPING 1423 || mState == RELEASING) { 1424 returnBuffersToCodecOnPort(kPortIndexInput); 1425 break; 1426 } 1427 1428 if (!mCSD.empty()) { 1429 ssize_t index = dequeuePortBuffer(kPortIndexInput); 1430 CHECK_GE(index, 0); 1431 1432 // If codec specific data had been specified as 1433 // part of the format in the call to configure and 1434 // if there's more csd left, we submit it here 1435 // clients only get access to input buffers once 1436 // this data has been exhausted. 1437 1438 status_t err = queueCSDInputBuffer(index); 1439 1440 if (err != OK) { 1441 ALOGE("queueCSDInputBuffer failed w/ error %d", 1442 err); 1443 1444 setStickyError(err); 1445 postActivityNotificationIfPossible(); 1446 1447 cancelPendingDequeueOperations(); 1448 } 1449 break; 1450 } 1451 1452 if (mFlags & kFlagIsAsync) { 1453 if (!mHaveInputSurface) { 1454 if (mState == FLUSHED) { 1455 mHavePendingInputBuffers = true; 1456 } else { 1457 onInputBufferAvailable(); 1458 } 1459 } 1460 } else if (mFlags & kFlagDequeueInputPending) { 1461 CHECK(handleDequeueInputBuffer(mDequeueInputReplyID)); 1462 1463 ++mDequeueInputTimeoutGeneration; 1464 mFlags &= ~kFlagDequeueInputPending; 1465 mDequeueInputReplyID = 0; 1466 } else { 1467 postActivityNotificationIfPossible(); 1468 } 1469 break; 1470 } 1471 1472 case CodecBase::kWhatDrainThisBuffer: 1473 { 1474 /* size_t index = */updateBuffers(kPortIndexOutput, msg); 1475 1476 if (mState == FLUSHING 1477 || mState == STOPPING 1478 || mState == RELEASING) { 1479 returnBuffersToCodecOnPort(kPortIndexOutput); 1480 break; 1481 } 1482 1483 sp<ABuffer> buffer; 1484 CHECK(msg->findBuffer("buffer", &buffer)); 1485 1486 int32_t omxFlags; 1487 CHECK(msg->findInt32("flags", &omxFlags)); 1488 1489 buffer->meta()->setInt32("omxFlags", omxFlags); 1490 1491 if (mFlags & kFlagGatherCodecSpecificData) { 1492 // This is the very first output buffer after a 1493 // format change was signalled, it'll either contain 1494 // the one piece of codec specific data we can expect 1495 // or there won't be codec specific data. 1496 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 1497 status_t err = 1498 amendOutputFormatWithCodecSpecificData(buffer); 1499 1500 if (err != OK) { 1501 ALOGE("Codec spit out malformed codec " 1502 "specific data!"); 1503 } 1504 } 1505 1506 mFlags &= ~kFlagGatherCodecSpecificData; 1507 if (mFlags & kFlagIsAsync) { 1508 onOutputFormatChanged(); 1509 } else { 1510 mFlags |= kFlagOutputFormatChanged; 1511 } 1512 } 1513 1514 if (mFlags & kFlagIsAsync) { 1515 onOutputBufferAvailable(); 1516 } else if (mFlags & kFlagDequeueOutputPending) { 1517 CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID)); 1518 1519 ++mDequeueOutputTimeoutGeneration; 1520 mFlags &= ~kFlagDequeueOutputPending; 1521 mDequeueOutputReplyID = 0; 1522 } else { 1523 postActivityNotificationIfPossible(); 1524 } 1525 1526 break; 1527 } 1528 1529 case CodecBase::kWhatEOS: 1530 { 1531 // We already notify the client of this by using the 1532 // corresponding flag in "onOutputBufferReady". 1533 break; 1534 } 1535 1536 case CodecBase::kWhatShutdownCompleted: 1537 { 1538 if (mState == STOPPING) { 1539 setState(INITIALIZED); 1540 } else { 1541 CHECK_EQ(mState, RELEASING); 1542 setState(UNINITIALIZED); 1543 mComponentName.clear(); 1544 } 1545 mFlags &= ~kFlagIsComponentAllocated; 1546 1547 mResourceManagerService->removeResource(getId(mResourceManagerClient)); 1548 1549 (new AMessage)->postReply(mReplyID); 1550 break; 1551 } 1552 1553 case CodecBase::kWhatFlushCompleted: 1554 { 1555 if (mState != FLUSHING) { 1556 ALOGW("received FlushCompleted message in state %d", 1557 mState); 1558 break; 1559 } 1560 1561 if (mFlags & kFlagIsAsync) { 1562 setState(FLUSHED); 1563 } else { 1564 setState(STARTED); 1565 mCodec->signalResume(); 1566 } 1567 1568 (new AMessage)->postReply(mReplyID); 1569 break; 1570 } 1571 1572 default: 1573 TRESPASS(); 1574 } 1575 break; 1576 } 1577 1578 case kWhatInit: 1579 { 1580 sp<AReplyToken> replyID; 1581 CHECK(msg->senderAwaitsResponse(&replyID)); 1582 1583 if (mState != UNINITIALIZED) { 1584 PostReplyWithError(replyID, INVALID_OPERATION); 1585 break; 1586 } 1587 1588 mReplyID = replyID; 1589 setState(INITIALIZING); 1590 1591 AString name; 1592 CHECK(msg->findString("name", &name)); 1593 1594 int32_t nameIsType; 1595 int32_t encoder = false; 1596 CHECK(msg->findInt32("nameIsType", &nameIsType)); 1597 if (nameIsType) { 1598 CHECK(msg->findInt32("encoder", &encoder)); 1599 } 1600 1601 sp<AMessage> format = new AMessage; 1602 1603 if (nameIsType) { 1604 format->setString("mime", name.c_str()); 1605 format->setInt32("encoder", encoder); 1606 } else { 1607 format->setString("componentName", name.c_str()); 1608 } 1609 1610 mCodec->initiateAllocateComponent(format); 1611 break; 1612 } 1613 1614 case kWhatSetNotification: 1615 { 1616 sp<AMessage> notify; 1617 if (msg->findMessage("on-frame-rendered", ¬ify)) { 1618 mOnFrameRenderedNotification = notify; 1619 } 1620 break; 1621 } 1622 1623 case kWhatSetCallback: 1624 { 1625 sp<AReplyToken> replyID; 1626 CHECK(msg->senderAwaitsResponse(&replyID)); 1627 1628 if (mState == UNINITIALIZED 1629 || mState == INITIALIZING 1630 || isExecuting()) { 1631 // callback can't be set after codec is executing, 1632 // or before it's initialized (as the callback 1633 // will be cleared when it goes to INITIALIZED) 1634 PostReplyWithError(replyID, INVALID_OPERATION); 1635 break; 1636 } 1637 1638 sp<AMessage> callback; 1639 CHECK(msg->findMessage("callback", &callback)); 1640 1641 mCallback = callback; 1642 1643 if (mCallback != NULL) { 1644 ALOGI("MediaCodec will operate in async mode"); 1645 mFlags |= kFlagIsAsync; 1646 } else { 1647 mFlags &= ~kFlagIsAsync; 1648 } 1649 1650 sp<AMessage> response = new AMessage; 1651 response->postReply(replyID); 1652 break; 1653 } 1654 1655 case kWhatConfigure: 1656 { 1657 sp<AReplyToken> replyID; 1658 CHECK(msg->senderAwaitsResponse(&replyID)); 1659 1660 if (mState != INITIALIZED) { 1661 PostReplyWithError(replyID, INVALID_OPERATION); 1662 break; 1663 } 1664 1665 sp<RefBase> obj; 1666 CHECK(msg->findObject("surface", &obj)); 1667 1668 sp<AMessage> format; 1669 CHECK(msg->findMessage("format", &format)); 1670 1671 int32_t push; 1672 if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) { 1673 mFlags |= kFlagPushBlankBuffersOnShutdown; 1674 } 1675 1676 if (obj != NULL) { 1677 format->setObject("native-window", obj); 1678 status_t err = handleSetSurface(static_cast<Surface *>(obj.get())); 1679 if (err != OK) { 1680 PostReplyWithError(replyID, err); 1681 break; 1682 } 1683 } else { 1684 handleSetSurface(NULL); 1685 } 1686 1687 mReplyID = replyID; 1688 setState(CONFIGURING); 1689 1690 void *crypto; 1691 if (!msg->findPointer("crypto", &crypto)) { 1692 crypto = NULL; 1693 } 1694 1695 mCrypto = static_cast<ICrypto *>(crypto); 1696 1697 uint32_t flags; 1698 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1699 1700 if (flags & CONFIGURE_FLAG_ENCODE) { 1701 format->setInt32("encoder", true); 1702 mFlags |= kFlagIsEncoder; 1703 } 1704 1705 extractCSD(format); 1706 1707 mCodec->initiateConfigureComponent(format); 1708 break; 1709 } 1710 1711 case kWhatSetSurface: 1712 { 1713 sp<AReplyToken> replyID; 1714 CHECK(msg->senderAwaitsResponse(&replyID)); 1715 1716 status_t err = OK; 1717 sp<Surface> surface; 1718 1719 switch (mState) { 1720 case CONFIGURED: 1721 case STARTED: 1722 case FLUSHED: 1723 { 1724 sp<RefBase> obj; 1725 (void)msg->findObject("surface", &obj); 1726 sp<Surface> surface = static_cast<Surface *>(obj.get()); 1727 if (mSurface == NULL) { 1728 // do not support setting surface if it was not set 1729 err = INVALID_OPERATION; 1730 } else if (obj == NULL) { 1731 // do not support unsetting surface 1732 err = BAD_VALUE; 1733 } else { 1734 err = connectToSurface(surface); 1735 if (err == BAD_VALUE) { 1736 // assuming reconnecting to same surface 1737 // TODO: check if it is the same surface 1738 err = OK; 1739 } else { 1740 if (err == OK) { 1741 if (mFlags & kFlagUsesSoftwareRenderer) { 1742 if (mSoftRenderer != NULL 1743 && (mFlags & kFlagPushBlankBuffersOnShutdown)) { 1744 pushBlankBuffersToNativeWindow(mSurface.get()); 1745 } 1746 mSoftRenderer = new SoftwareRenderer(surface); 1747 // TODO: check if this was successful 1748 } else { 1749 err = mCodec->setSurface(surface); 1750 } 1751 } 1752 if (err == OK) { 1753 (void)disconnectFromSurface(); 1754 mSurface = surface; 1755 } 1756 } 1757 } 1758 break; 1759 } 1760 1761 default: 1762 err = INVALID_OPERATION; 1763 break; 1764 } 1765 1766 PostReplyWithError(replyID, err); 1767 break; 1768 } 1769 1770 case kWhatCreateInputSurface: 1771 case kWhatSetInputSurface: 1772 { 1773 sp<AReplyToken> replyID; 1774 CHECK(msg->senderAwaitsResponse(&replyID)); 1775 1776 // Must be configured, but can't have been started yet. 1777 if (mState != CONFIGURED) { 1778 PostReplyWithError(replyID, INVALID_OPERATION); 1779 break; 1780 } 1781 1782 mReplyID = replyID; 1783 if (msg->what() == kWhatCreateInputSurface) { 1784 mCodec->initiateCreateInputSurface(); 1785 } else { 1786 sp<RefBase> obj; 1787 CHECK(msg->findObject("input-surface", &obj)); 1788 1789 mCodec->initiateSetInputSurface( 1790 static_cast<PersistentSurface *>(obj.get())); 1791 } 1792 break; 1793 } 1794 case kWhatStart: 1795 { 1796 sp<AReplyToken> replyID; 1797 CHECK(msg->senderAwaitsResponse(&replyID)); 1798 1799 if (mState == FLUSHED) { 1800 setState(STARTED); 1801 if (mHavePendingInputBuffers) { 1802 onInputBufferAvailable(); 1803 mHavePendingInputBuffers = false; 1804 } 1805 mCodec->signalResume(); 1806 PostReplyWithError(replyID, OK); 1807 break; 1808 } else if (mState != CONFIGURED) { 1809 PostReplyWithError(replyID, INVALID_OPERATION); 1810 break; 1811 } 1812 1813 mReplyID = replyID; 1814 setState(STARTING); 1815 1816 mCodec->initiateStart(); 1817 break; 1818 } 1819 1820 case kWhatStop: 1821 case kWhatRelease: 1822 { 1823 State targetState = 1824 (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED; 1825 1826 sp<AReplyToken> replyID; 1827 CHECK(msg->senderAwaitsResponse(&replyID)); 1828 1829 // already stopped/released 1830 if (mState == UNINITIALIZED && mReleasedByResourceManager) { 1831 sp<AMessage> response = new AMessage; 1832 response->setInt32("err", OK); 1833 response->postReply(replyID); 1834 break; 1835 } 1836 1837 int32_t reclaimed = 0; 1838 msg->findInt32("reclaimed", &reclaimed); 1839 if (reclaimed) { 1840 mReleasedByResourceManager = true; 1841 1842 int32_t force = 0; 1843 msg->findInt32("force", &force); 1844 if (!force && hasPendingBuffer()) { 1845 ALOGW("Can't reclaim codec right now due to pending buffers."); 1846 1847 // return WOULD_BLOCK to ask resource manager to retry later. 1848 sp<AMessage> response = new AMessage; 1849 response->setInt32("err", WOULD_BLOCK); 1850 response->postReply(replyID); 1851 1852 // notify the async client 1853 if (mFlags & kFlagIsAsync) { 1854 onError(DEAD_OBJECT, ACTION_CODE_FATAL); 1855 } 1856 break; 1857 } 1858 } 1859 1860 if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1 1861 && mState != INITIALIZED 1862 && mState != CONFIGURED && !isExecuting()) { 1863 // 1) Permit release to shut down the component if allocated. 1864 // 1865 // 2) We may be in "UNINITIALIZED" state already and 1866 // also shutdown the encoder/decoder without the 1867 // client being aware of this if media server died while 1868 // we were being stopped. The client would assume that 1869 // after stop() returned, it would be safe to call release() 1870 // and it should be in this case, no harm to allow a release() 1871 // if we're already uninitialized. 1872 sp<AMessage> response = new AMessage; 1873 // TODO: we shouldn't throw an exception for stop/release. Change this to wait until 1874 // the previous stop/release completes and then reply with OK. 1875 status_t err = mState == targetState ? OK : INVALID_OPERATION; 1876 response->setInt32("err", err); 1877 if (err == OK && targetState == UNINITIALIZED) { 1878 mComponentName.clear(); 1879 } 1880 response->postReply(replyID); 1881 break; 1882 } 1883 1884 if (mFlags & kFlagSawMediaServerDie) { 1885 // It's dead, Jim. Don't expect initiateShutdown to yield 1886 // any useful results now... 1887 setState(UNINITIALIZED); 1888 if (targetState == UNINITIALIZED) { 1889 mComponentName.clear(); 1890 } 1891 (new AMessage)->postReply(replyID); 1892 break; 1893 } 1894 1895 mReplyID = replyID; 1896 setState(msg->what() == kWhatStop ? STOPPING : RELEASING); 1897 1898 mCodec->initiateShutdown( 1899 msg->what() == kWhatStop /* keepComponentAllocated */); 1900 1901 returnBuffersToCodec(); 1902 1903 if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) { 1904 pushBlankBuffersToNativeWindow(mSurface.get()); 1905 } 1906 break; 1907 } 1908 1909 case kWhatDequeueInputBuffer: 1910 { 1911 sp<AReplyToken> replyID; 1912 CHECK(msg->senderAwaitsResponse(&replyID)); 1913 1914 if (mFlags & kFlagIsAsync) { 1915 ALOGE("dequeueOutputBuffer can't be used in async mode"); 1916 PostReplyWithError(replyID, INVALID_OPERATION); 1917 break; 1918 } 1919 1920 if (mHaveInputSurface) { 1921 ALOGE("dequeueInputBuffer can't be used with input surface"); 1922 PostReplyWithError(replyID, INVALID_OPERATION); 1923 break; 1924 } 1925 1926 if (handleDequeueInputBuffer(replyID, true /* new request */)) { 1927 break; 1928 } 1929 1930 int64_t timeoutUs; 1931 CHECK(msg->findInt64("timeoutUs", &timeoutUs)); 1932 1933 if (timeoutUs == 0ll) { 1934 PostReplyWithError(replyID, -EAGAIN); 1935 break; 1936 } 1937 1938 mFlags |= kFlagDequeueInputPending; 1939 mDequeueInputReplyID = replyID; 1940 1941 if (timeoutUs > 0ll) { 1942 sp<AMessage> timeoutMsg = 1943 new AMessage(kWhatDequeueInputTimedOut, this); 1944 timeoutMsg->setInt32( 1945 "generation", ++mDequeueInputTimeoutGeneration); 1946 timeoutMsg->post(timeoutUs); 1947 } 1948 break; 1949 } 1950 1951 case kWhatDequeueInputTimedOut: 1952 { 1953 int32_t generation; 1954 CHECK(msg->findInt32("generation", &generation)); 1955 1956 if (generation != mDequeueInputTimeoutGeneration) { 1957 // Obsolete 1958 break; 1959 } 1960 1961 CHECK(mFlags & kFlagDequeueInputPending); 1962 1963 PostReplyWithError(mDequeueInputReplyID, -EAGAIN); 1964 1965 mFlags &= ~kFlagDequeueInputPending; 1966 mDequeueInputReplyID = 0; 1967 break; 1968 } 1969 1970 case kWhatQueueInputBuffer: 1971 { 1972 sp<AReplyToken> replyID; 1973 CHECK(msg->senderAwaitsResponse(&replyID)); 1974 1975 if (!isExecuting()) { 1976 PostReplyWithError(replyID, INVALID_OPERATION); 1977 break; 1978 } else if (mFlags & kFlagStickyError) { 1979 PostReplyWithError(replyID, getStickyError()); 1980 break; 1981 } 1982 1983 status_t err = onQueueInputBuffer(msg); 1984 1985 PostReplyWithError(replyID, err); 1986 break; 1987 } 1988 1989 case kWhatDequeueOutputBuffer: 1990 { 1991 sp<AReplyToken> replyID; 1992 CHECK(msg->senderAwaitsResponse(&replyID)); 1993 1994 if (mFlags & kFlagIsAsync) { 1995 ALOGE("dequeueOutputBuffer can't be used in async mode"); 1996 PostReplyWithError(replyID, INVALID_OPERATION); 1997 break; 1998 } 1999 2000 if (handleDequeueOutputBuffer(replyID, true /* new request */)) { 2001 break; 2002 } 2003 2004 int64_t timeoutUs; 2005 CHECK(msg->findInt64("timeoutUs", &timeoutUs)); 2006 2007 if (timeoutUs == 0ll) { 2008 PostReplyWithError(replyID, -EAGAIN); 2009 break; 2010 } 2011 2012 mFlags |= kFlagDequeueOutputPending; 2013 mDequeueOutputReplyID = replyID; 2014 2015 if (timeoutUs > 0ll) { 2016 sp<AMessage> timeoutMsg = 2017 new AMessage(kWhatDequeueOutputTimedOut, this); 2018 timeoutMsg->setInt32( 2019 "generation", ++mDequeueOutputTimeoutGeneration); 2020 timeoutMsg->post(timeoutUs); 2021 } 2022 break; 2023 } 2024 2025 case kWhatDequeueOutputTimedOut: 2026 { 2027 int32_t generation; 2028 CHECK(msg->findInt32("generation", &generation)); 2029 2030 if (generation != mDequeueOutputTimeoutGeneration) { 2031 // Obsolete 2032 break; 2033 } 2034 2035 CHECK(mFlags & kFlagDequeueOutputPending); 2036 2037 PostReplyWithError(mDequeueOutputReplyID, -EAGAIN); 2038 2039 mFlags &= ~kFlagDequeueOutputPending; 2040 mDequeueOutputReplyID = 0; 2041 break; 2042 } 2043 2044 case kWhatReleaseOutputBuffer: 2045 { 2046 sp<AReplyToken> replyID; 2047 CHECK(msg->senderAwaitsResponse(&replyID)); 2048 2049 if (!isExecuting()) { 2050 PostReplyWithError(replyID, INVALID_OPERATION); 2051 break; 2052 } else if (mFlags & kFlagStickyError) { 2053 PostReplyWithError(replyID, getStickyError()); 2054 break; 2055 } 2056 2057 status_t err = onReleaseOutputBuffer(msg); 2058 2059 PostReplyWithError(replyID, err); 2060 break; 2061 } 2062 2063 case kWhatSignalEndOfInputStream: 2064 { 2065 sp<AReplyToken> replyID; 2066 CHECK(msg->senderAwaitsResponse(&replyID)); 2067 2068 if (!isExecuting()) { 2069 PostReplyWithError(replyID, INVALID_OPERATION); 2070 break; 2071 } else if (mFlags & kFlagStickyError) { 2072 PostReplyWithError(replyID, getStickyError()); 2073 break; 2074 } 2075 2076 mReplyID = replyID; 2077 mCodec->signalEndOfInputStream(); 2078 break; 2079 } 2080 2081 case kWhatGetBuffers: 2082 { 2083 sp<AReplyToken> replyID; 2084 CHECK(msg->senderAwaitsResponse(&replyID)); 2085 // Unfortunately widevine legacy source requires knowing all of the 2086 // codec input buffers, so we have to provide them even in async mode. 2087 int32_t widevine = 0; 2088 msg->findInt32("widevine", &widevine); 2089 2090 if (!isExecuting() || ((mFlags & kFlagIsAsync) && !widevine)) { 2091 PostReplyWithError(replyID, INVALID_OPERATION); 2092 break; 2093 } else if (mFlags & kFlagStickyError) { 2094 PostReplyWithError(replyID, getStickyError()); 2095 break; 2096 } 2097 2098 int32_t portIndex; 2099 CHECK(msg->findInt32("portIndex", &portIndex)); 2100 2101 Vector<sp<ABuffer> > *dstBuffers; 2102 CHECK(msg->findPointer("buffers", (void **)&dstBuffers)); 2103 2104 dstBuffers->clear(); 2105 const Vector<BufferInfo> &srcBuffers = mPortBuffers[portIndex]; 2106 2107 for (size_t i = 0; i < srcBuffers.size(); ++i) { 2108 const BufferInfo &info = srcBuffers.itemAt(i); 2109 2110 dstBuffers->push_back( 2111 (portIndex == kPortIndexInput && mCrypto != NULL) 2112 ? info.mEncryptedData : info.mData); 2113 } 2114 2115 (new AMessage)->postReply(replyID); 2116 break; 2117 } 2118 2119 case kWhatFlush: 2120 { 2121 sp<AReplyToken> replyID; 2122 CHECK(msg->senderAwaitsResponse(&replyID)); 2123 2124 if (!isExecuting()) { 2125 PostReplyWithError(replyID, INVALID_OPERATION); 2126 break; 2127 } else if (mFlags & kFlagStickyError) { 2128 PostReplyWithError(replyID, getStickyError()); 2129 break; 2130 } 2131 2132 mReplyID = replyID; 2133 // TODO: skip flushing if already FLUSHED 2134 setState(FLUSHING); 2135 2136 mCodec->signalFlush(); 2137 returnBuffersToCodec(); 2138 break; 2139 } 2140 2141 case kWhatGetInputFormat: 2142 case kWhatGetOutputFormat: 2143 { 2144 sp<AMessage> format = 2145 (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat); 2146 2147 sp<AReplyToken> replyID; 2148 CHECK(msg->senderAwaitsResponse(&replyID)); 2149 2150 if ((mState != CONFIGURED && mState != STARTING && 2151 mState != STARTED && mState != FLUSHING && 2152 mState != FLUSHED) 2153 || format == NULL) { 2154 PostReplyWithError(replyID, INVALID_OPERATION); 2155 break; 2156 } else if (mFlags & kFlagStickyError) { 2157 PostReplyWithError(replyID, getStickyError()); 2158 break; 2159 } 2160 2161 sp<AMessage> response = new AMessage; 2162 response->setMessage("format", format); 2163 response->postReply(replyID); 2164 break; 2165 } 2166 2167 case kWhatRequestIDRFrame: 2168 { 2169 mCodec->signalRequestIDRFrame(); 2170 break; 2171 } 2172 2173 case kWhatRequestActivityNotification: 2174 { 2175 CHECK(mActivityNotify == NULL); 2176 CHECK(msg->findMessage("notify", &mActivityNotify)); 2177 2178 postActivityNotificationIfPossible(); 2179 break; 2180 } 2181 2182 case kWhatGetName: 2183 { 2184 sp<AReplyToken> replyID; 2185 CHECK(msg->senderAwaitsResponse(&replyID)); 2186 2187 if (mComponentName.empty()) { 2188 PostReplyWithError(replyID, INVALID_OPERATION); 2189 break; 2190 } 2191 2192 sp<AMessage> response = new AMessage; 2193 response->setString("name", mComponentName.c_str()); 2194 response->postReply(replyID); 2195 break; 2196 } 2197 2198 case kWhatSetParameters: 2199 { 2200 sp<AReplyToken> replyID; 2201 CHECK(msg->senderAwaitsResponse(&replyID)); 2202 2203 sp<AMessage> params; 2204 CHECK(msg->findMessage("params", ¶ms)); 2205 2206 status_t err = onSetParameters(params); 2207 2208 PostReplyWithError(replyID, err); 2209 break; 2210 } 2211 2212 default: 2213 TRESPASS(); 2214 } 2215} 2216 2217void MediaCodec::extractCSD(const sp<AMessage> &format) { 2218 mCSD.clear(); 2219 2220 size_t i = 0; 2221 for (;;) { 2222 sp<ABuffer> csd; 2223 if (!format->findBuffer(AStringPrintf("csd-%u", i).c_str(), &csd)) { 2224 break; 2225 } 2226 2227 mCSD.push_back(csd); 2228 ++i; 2229 } 2230 2231 ALOGV("Found %zu pieces of codec specific data.", mCSD.size()); 2232} 2233 2234status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) { 2235 CHECK(!mCSD.empty()); 2236 2237 const BufferInfo *info = 2238 &mPortBuffers[kPortIndexInput].itemAt(bufferIndex); 2239 2240 sp<ABuffer> csd = *mCSD.begin(); 2241 mCSD.erase(mCSD.begin()); 2242 2243 const sp<ABuffer> &codecInputData = 2244 (mCrypto != NULL) ? info->mEncryptedData : info->mData; 2245 2246 if (csd->size() > codecInputData->capacity()) { 2247 return -EINVAL; 2248 } 2249 2250 memcpy(codecInputData->data(), csd->data(), csd->size()); 2251 2252 AString errorDetailMsg; 2253 2254 sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this); 2255 msg->setSize("index", bufferIndex); 2256 msg->setSize("offset", 0); 2257 msg->setSize("size", csd->size()); 2258 msg->setInt64("timeUs", 0ll); 2259 msg->setInt32("flags", BUFFER_FLAG_CODECCONFIG); 2260 msg->setPointer("errorDetailMsg", &errorDetailMsg); 2261 2262 return onQueueInputBuffer(msg); 2263} 2264 2265void MediaCodec::setState(State newState) { 2266 if (newState == INITIALIZED || newState == UNINITIALIZED) { 2267 delete mSoftRenderer; 2268 mSoftRenderer = NULL; 2269 2270 mCrypto.clear(); 2271 handleSetSurface(NULL); 2272 2273 mInputFormat.clear(); 2274 mOutputFormat.clear(); 2275 mFlags &= ~kFlagOutputFormatChanged; 2276 mFlags &= ~kFlagOutputBuffersChanged; 2277 mFlags &= ~kFlagStickyError; 2278 mFlags &= ~kFlagIsEncoder; 2279 mFlags &= ~kFlagGatherCodecSpecificData; 2280 mFlags &= ~kFlagIsAsync; 2281 mStickyError = OK; 2282 2283 mActivityNotify.clear(); 2284 mCallback.clear(); 2285 } 2286 2287 if (newState == UNINITIALIZED) { 2288 // return any straggling buffers, e.g. if we got here on an error 2289 returnBuffersToCodec(); 2290 2291 // The component is gone, mediaserver's probably back up already 2292 // but should definitely be back up should we try to instantiate 2293 // another component.. and the cycle continues. 2294 mFlags &= ~kFlagSawMediaServerDie; 2295 } 2296 2297 mState = newState; 2298 2299 cancelPendingDequeueOperations(); 2300 2301 updateBatteryStat(); 2302} 2303 2304void MediaCodec::returnBuffersToCodec() { 2305 returnBuffersToCodecOnPort(kPortIndexInput); 2306 returnBuffersToCodecOnPort(kPortIndexOutput); 2307} 2308 2309void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) { 2310 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 2311 Mutex::Autolock al(mBufferLock); 2312 2313 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 2314 2315 for (size_t i = 0; i < buffers->size(); ++i) { 2316 BufferInfo *info = &buffers->editItemAt(i); 2317 2318 if (info->mNotify != NULL) { 2319 sp<AMessage> msg = info->mNotify; 2320 info->mNotify = NULL; 2321 info->mOwnedByClient = false; 2322 2323 if (portIndex == kPortIndexInput) { 2324 /* no error, just returning buffers */ 2325 msg->setInt32("err", OK); 2326 } 2327 msg->post(); 2328 } 2329 } 2330 2331 mAvailPortBuffers[portIndex].clear(); 2332} 2333 2334size_t MediaCodec::updateBuffers( 2335 int32_t portIndex, const sp<AMessage> &msg) { 2336 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 2337 2338 uint32_t bufferID; 2339 CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); 2340 2341 Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; 2342 2343 for (size_t i = 0; i < buffers->size(); ++i) { 2344 BufferInfo *info = &buffers->editItemAt(i); 2345 2346 if (info->mBufferID == bufferID) { 2347 CHECK(info->mNotify == NULL); 2348 CHECK(msg->findMessage("reply", &info->mNotify)); 2349 2350 info->mFormat = 2351 (portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat; 2352 mAvailPortBuffers[portIndex].push_back(i); 2353 2354 return i; 2355 } 2356 } 2357 2358 TRESPASS(); 2359 2360 return 0; 2361} 2362 2363status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) { 2364 size_t index; 2365 size_t offset; 2366 size_t size; 2367 int64_t timeUs; 2368 uint32_t flags; 2369 CHECK(msg->findSize("index", &index)); 2370 CHECK(msg->findSize("offset", &offset)); 2371 CHECK(msg->findInt64("timeUs", &timeUs)); 2372 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 2373 2374 const CryptoPlugin::SubSample *subSamples; 2375 size_t numSubSamples; 2376 const uint8_t *key; 2377 const uint8_t *iv; 2378 CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted; 2379 2380 // We allow the simpler queueInputBuffer API to be used even in 2381 // secure mode, by fabricating a single unencrypted subSample. 2382 CryptoPlugin::SubSample ss; 2383 2384 if (msg->findSize("size", &size)) { 2385 if (mCrypto != NULL) { 2386 ss.mNumBytesOfClearData = size; 2387 ss.mNumBytesOfEncryptedData = 0; 2388 2389 subSamples = &ss; 2390 numSubSamples = 1; 2391 key = NULL; 2392 iv = NULL; 2393 } 2394 } else { 2395 if (mCrypto == NULL) { 2396 return -EINVAL; 2397 } 2398 2399 CHECK(msg->findPointer("subSamples", (void **)&subSamples)); 2400 CHECK(msg->findSize("numSubSamples", &numSubSamples)); 2401 CHECK(msg->findPointer("key", (void **)&key)); 2402 CHECK(msg->findPointer("iv", (void **)&iv)); 2403 2404 int32_t tmp; 2405 CHECK(msg->findInt32("mode", &tmp)); 2406 2407 mode = (CryptoPlugin::Mode)tmp; 2408 2409 size = 0; 2410 for (size_t i = 0; i < numSubSamples; ++i) { 2411 size += subSamples[i].mNumBytesOfClearData; 2412 size += subSamples[i].mNumBytesOfEncryptedData; 2413 } 2414 } 2415 2416 if (index >= mPortBuffers[kPortIndexInput].size()) { 2417 return -ERANGE; 2418 } 2419 2420 BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index); 2421 2422 if (info->mNotify == NULL || !info->mOwnedByClient) { 2423 return -EACCES; 2424 } 2425 2426 if (offset + size > info->mData->capacity()) { 2427 return -EINVAL; 2428 } 2429 2430 sp<AMessage> reply = info->mNotify; 2431 info->mData->setRange(offset, size); 2432 info->mData->meta()->setInt64("timeUs", timeUs); 2433 2434 if (flags & BUFFER_FLAG_EOS) { 2435 info->mData->meta()->setInt32("eos", true); 2436 } 2437 2438 if (flags & BUFFER_FLAG_CODECCONFIG) { 2439 info->mData->meta()->setInt32("csd", true); 2440 } 2441 2442 if (mCrypto != NULL) { 2443 if (size > info->mEncryptedData->capacity()) { 2444 return -ERANGE; 2445 } 2446 2447 AString *errorDetailMsg; 2448 CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg)); 2449 2450 ssize_t result = mCrypto->decrypt( 2451 (mFlags & kFlagIsSecure) != 0, 2452 key, 2453 iv, 2454 mode, 2455 info->mSharedEncryptedBuffer, 2456 offset, 2457 subSamples, 2458 numSubSamples, 2459 info->mData->base(), 2460 errorDetailMsg); 2461 2462 if (result < 0) { 2463 return result; 2464 } 2465 2466 info->mData->setRange(0, result); 2467 } 2468 2469 // synchronization boundary for getBufferAndFormat 2470 { 2471 Mutex::Autolock al(mBufferLock); 2472 info->mOwnedByClient = false; 2473 } 2474 reply->setBuffer("buffer", info->mData); 2475 reply->post(); 2476 2477 info->mNotify = NULL; 2478 2479 return OK; 2480} 2481 2482//static 2483size_t MediaCodec::CreateFramesRenderedMessage( 2484 const std::list<FrameRenderTracker::Info> &done, sp<AMessage> &msg) { 2485 size_t index = 0; 2486 2487 for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin(); 2488 it != done.cend(); ++it) { 2489 if (it->getRenderTimeNs() < 0) { 2490 continue; // dropped frame from tracking 2491 } 2492 msg->setInt64(AStringPrintf("%zu-media-time-us", index).c_str(), it->getMediaTimeUs()); 2493 msg->setInt64(AStringPrintf("%zu-system-nano", index).c_str(), it->getRenderTimeNs()); 2494 ++index; 2495 } 2496 return index; 2497} 2498 2499status_t MediaCodec::onReleaseOutputBuffer(const sp<AMessage> &msg) { 2500 size_t index; 2501 CHECK(msg->findSize("index", &index)); 2502 2503 int32_t render; 2504 if (!msg->findInt32("render", &render)) { 2505 render = 0; 2506 } 2507 2508 if (!isExecuting()) { 2509 return -EINVAL; 2510 } 2511 2512 if (index >= mPortBuffers[kPortIndexOutput].size()) { 2513 return -ERANGE; 2514 } 2515 2516 BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index); 2517 2518 if (info->mNotify == NULL || !info->mOwnedByClient) { 2519 return -EACCES; 2520 } 2521 2522 // synchronization boundary for getBufferAndFormat 2523 { 2524 Mutex::Autolock al(mBufferLock); 2525 info->mOwnedByClient = false; 2526 } 2527 2528 if (render && info->mData != NULL && info->mData->size() != 0) { 2529 info->mNotify->setInt32("render", true); 2530 2531 int64_t mediaTimeUs = -1; 2532 info->mData->meta()->findInt64("timeUs", &mediaTimeUs); 2533 2534 int64_t renderTimeNs = 0; 2535 if (!msg->findInt64("timestampNs", &renderTimeNs)) { 2536 // use media timestamp if client did not request a specific render timestamp 2537 ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs); 2538 renderTimeNs = mediaTimeUs * 1000; 2539 } 2540 info->mNotify->setInt64("timestampNs", renderTimeNs); 2541 2542 if (mSoftRenderer != NULL) { 2543 std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render( 2544 info->mData->data(), info->mData->size(), 2545 mediaTimeUs, renderTimeNs, NULL, info->mFormat); 2546 2547 // if we are running, notify rendered frames 2548 if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) { 2549 sp<AMessage> notify = mOnFrameRenderedNotification->dup(); 2550 sp<AMessage> data = new AMessage; 2551 if (CreateFramesRenderedMessage(doneFrames, data)) { 2552 notify->setMessage("data", data); 2553 notify->post(); 2554 } 2555 } 2556 } 2557 } 2558 2559 info->mNotify->post(); 2560 info->mNotify = NULL; 2561 2562 return OK; 2563} 2564 2565ssize_t MediaCodec::dequeuePortBuffer(int32_t portIndex) { 2566 CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); 2567 2568 List<size_t> *availBuffers = &mAvailPortBuffers[portIndex]; 2569 2570 if (availBuffers->empty()) { 2571 return -EAGAIN; 2572 } 2573 2574 size_t index = *availBuffers->begin(); 2575 availBuffers->erase(availBuffers->begin()); 2576 2577 BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index); 2578 CHECK(!info->mOwnedByClient); 2579 { 2580 Mutex::Autolock al(mBufferLock); 2581 info->mOwnedByClient = true; 2582 2583 // set image-data 2584 if (info->mFormat != NULL) { 2585 sp<ABuffer> imageData; 2586 if (info->mFormat->findBuffer("image-data", &imageData)) { 2587 info->mData->meta()->setBuffer("image-data", imageData); 2588 } 2589 int32_t left, top, right, bottom; 2590 if (info->mFormat->findRect("crop", &left, &top, &right, &bottom)) { 2591 info->mData->meta()->setRect("crop-rect", left, top, right, bottom); 2592 } 2593 } 2594 } 2595 2596 return index; 2597} 2598 2599status_t MediaCodec::connectToSurface(const sp<Surface> &surface) { 2600 status_t err = OK; 2601 if (surface != NULL) { 2602 err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA); 2603 if (err == BAD_VALUE) { 2604 ALOGI("native window already connected. Assuming no change of surface"); 2605 return err; 2606 } else if (err == OK) { 2607 // Require a fresh set of buffers after each connect by using a unique generation 2608 // number. Rely on the fact that max supported process id by Linux is 2^22. 2609 // PID is never 0 so we don't have to worry that we use the default generation of 0. 2610 // TODO: come up with a unique scheme if other producers also set the generation number. 2611 static uint32_t mSurfaceGeneration = 0; 2612 uint32_t generation = (getpid() << 10) | (++mSurfaceGeneration & ((1 << 10) - 1)); 2613 surface->setGenerationNumber(generation); 2614 ALOGI("[%s] setting surface generation to %u", mComponentName.c_str(), generation); 2615 2616 // HACK: clear any free buffers. Remove when connect will automatically do this. 2617 // This is needed as the consumer may be holding onto stale frames that it can reattach 2618 // to this surface after disconnect/connect, and those free frames would inherit the new 2619 // generation number. Disconnecting after setting a unique generation prevents this. 2620 native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_MEDIA); 2621 err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA); 2622 } 2623 2624 if (err != OK) { 2625 ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err); 2626 } 2627 } 2628 return err; 2629} 2630 2631status_t MediaCodec::disconnectFromSurface() { 2632 status_t err = OK; 2633 if (mSurface != NULL) { 2634 // Resetting generation is not technically needed, but there is no need to keep it either 2635 mSurface->setGenerationNumber(0); 2636 err = native_window_api_disconnect(mSurface.get(), NATIVE_WINDOW_API_MEDIA); 2637 if (err != OK) { 2638 ALOGW("native_window_api_disconnect returned an error: %s (%d)", strerror(-err), err); 2639 } 2640 // assume disconnected even on error 2641 mSurface.clear(); 2642 } 2643 return err; 2644} 2645 2646status_t MediaCodec::handleSetSurface(const sp<Surface> &surface) { 2647 status_t err = OK; 2648 if (mSurface != NULL) { 2649 (void)disconnectFromSurface(); 2650 } 2651 if (surface != NULL) { 2652 err = connectToSurface(surface); 2653 if (err == OK) { 2654 mSurface = surface; 2655 } 2656 } 2657 return err; 2658} 2659 2660void MediaCodec::onInputBufferAvailable() { 2661 int32_t index; 2662 while ((index = dequeuePortBuffer(kPortIndexInput)) >= 0) { 2663 sp<AMessage> msg = mCallback->dup(); 2664 msg->setInt32("callbackID", CB_INPUT_AVAILABLE); 2665 msg->setInt32("index", index); 2666 msg->post(); 2667 } 2668} 2669 2670void MediaCodec::onOutputBufferAvailable() { 2671 int32_t index; 2672 while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) { 2673 const sp<ABuffer> &buffer = 2674 mPortBuffers[kPortIndexOutput].itemAt(index).mData; 2675 sp<AMessage> msg = mCallback->dup(); 2676 msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE); 2677 msg->setInt32("index", index); 2678 msg->setSize("offset", buffer->offset()); 2679 msg->setSize("size", buffer->size()); 2680 2681 int64_t timeUs; 2682 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2683 2684 msg->setInt64("timeUs", timeUs); 2685 2686 int32_t omxFlags; 2687 CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags)); 2688 2689 uint32_t flags = 0; 2690 if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) { 2691 flags |= BUFFER_FLAG_SYNCFRAME; 2692 } 2693 if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) { 2694 flags |= BUFFER_FLAG_CODECCONFIG; 2695 } 2696 if (omxFlags & OMX_BUFFERFLAG_EOS) { 2697 flags |= BUFFER_FLAG_EOS; 2698 } 2699 2700 msg->setInt32("flags", flags); 2701 2702 msg->post(); 2703 } 2704} 2705 2706void MediaCodec::onError(status_t err, int32_t actionCode, const char *detail) { 2707 if (mCallback != NULL) { 2708 sp<AMessage> msg = mCallback->dup(); 2709 msg->setInt32("callbackID", CB_ERROR); 2710 msg->setInt32("err", err); 2711 msg->setInt32("actionCode", actionCode); 2712 2713 if (detail != NULL) { 2714 msg->setString("detail", detail); 2715 } 2716 2717 msg->post(); 2718 } 2719} 2720 2721void MediaCodec::onOutputFormatChanged() { 2722 if (mCallback != NULL) { 2723 sp<AMessage> msg = mCallback->dup(); 2724 msg->setInt32("callbackID", CB_OUTPUT_FORMAT_CHANGED); 2725 msg->setMessage("format", mOutputFormat); 2726 msg->post(); 2727 } 2728} 2729 2730 2731void MediaCodec::postActivityNotificationIfPossible() { 2732 if (mActivityNotify == NULL) { 2733 return; 2734 } 2735 2736 bool isErrorOrOutputChanged = 2737 (mFlags & (kFlagStickyError 2738 | kFlagOutputBuffersChanged 2739 | kFlagOutputFormatChanged)); 2740 2741 if (isErrorOrOutputChanged 2742 || !mAvailPortBuffers[kPortIndexInput].empty() 2743 || !mAvailPortBuffers[kPortIndexOutput].empty()) { 2744 mActivityNotify->setInt32("input-buffers", 2745 mAvailPortBuffers[kPortIndexInput].size()); 2746 2747 if (isErrorOrOutputChanged) { 2748 // we want consumer to dequeue as many times as it can 2749 mActivityNotify->setInt32("output-buffers", INT32_MAX); 2750 } else { 2751 mActivityNotify->setInt32("output-buffers", 2752 mAvailPortBuffers[kPortIndexOutput].size()); 2753 } 2754 mActivityNotify->post(); 2755 mActivityNotify.clear(); 2756 } 2757} 2758 2759status_t MediaCodec::setParameters(const sp<AMessage> ¶ms) { 2760 sp<AMessage> msg = new AMessage(kWhatSetParameters, this); 2761 msg->setMessage("params", params); 2762 2763 sp<AMessage> response; 2764 return PostAndAwaitResponse(msg, &response); 2765} 2766 2767status_t MediaCodec::onSetParameters(const sp<AMessage> ¶ms) { 2768 mCodec->signalSetParameters(params); 2769 2770 return OK; 2771} 2772 2773status_t MediaCodec::amendOutputFormatWithCodecSpecificData( 2774 const sp<ABuffer> &buffer) { 2775 AString mime; 2776 CHECK(mOutputFormat->findString("mime", &mime)); 2777 2778 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) { 2779 // Codec specific data should be SPS and PPS in a single buffer, 2780 // each prefixed by a startcode (0x00 0x00 0x00 0x01). 2781 // We separate the two and put them into the output format 2782 // under the keys "csd-0" and "csd-1". 2783 2784 unsigned csdIndex = 0; 2785 2786 const uint8_t *data = buffer->data(); 2787 size_t size = buffer->size(); 2788 2789 const uint8_t *nalStart; 2790 size_t nalSize; 2791 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { 2792 sp<ABuffer> csd = new ABuffer(nalSize + 4); 2793 memcpy(csd->data(), "\x00\x00\x00\x01", 4); 2794 memcpy(csd->data() + 4, nalStart, nalSize); 2795 2796 mOutputFormat->setBuffer( 2797 AStringPrintf("csd-%u", csdIndex).c_str(), csd); 2798 2799 ++csdIndex; 2800 } 2801 2802 if (csdIndex != 2) { 2803 return ERROR_MALFORMED; 2804 } 2805 } else { 2806 // For everything else we just stash the codec specific data into 2807 // the output format as a single piece of csd under "csd-0". 2808 mOutputFormat->setBuffer("csd-0", buffer); 2809 } 2810 2811 return OK; 2812} 2813 2814void MediaCodec::updateBatteryStat() { 2815 if (mState == CONFIGURED && !mBatteryStatNotified) { 2816 BatteryNotifier& notifier(BatteryNotifier::getInstance()); 2817 2818 if (mIsVideo) { 2819 notifier.noteStartVideo(); 2820 } else { 2821 notifier.noteStartAudio(); 2822 } 2823 2824 mBatteryStatNotified = true; 2825 } else if (mState == UNINITIALIZED && mBatteryStatNotified) { 2826 BatteryNotifier& notifier(BatteryNotifier::getInstance()); 2827 2828 if (mIsVideo) { 2829 notifier.noteStopVideo(); 2830 } else { 2831 notifier.noteStopAudio(); 2832 } 2833 2834 mBatteryStatNotified = false; 2835 } 2836} 2837 2838} // namespace android 2839