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