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