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