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