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