MediaCodecSource.cpp revision a5750e0dad9e90f2195ce36f2c4457fa04b2b83e
1/* 2 * Copyright 2014, 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 "MediaCodecSource" 19#define DEBUG_DRIFT_TIME 0 20 21#include <inttypes.h> 22 23#include <gui/IGraphicBufferProducer.h> 24#include <gui/Surface.h> 25#include <media/ICrypto.h> 26#include <media/stagefright/foundation/ABuffer.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/ALooper.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/MediaBuffer.h> 31#include <media/stagefright/MediaCodec.h> 32#include <media/stagefright/MetaData.h> 33#include <media/stagefright/MediaErrors.h> 34#include <media/stagefright/MediaSource.h> 35#include <media/stagefright/MediaCodecSource.h> 36#include <media/stagefright/Utils.h> 37 38namespace android { 39 40static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) { 41 void *mbuf; 42 if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) 43 && mbuf != NULL) { 44 ALOGV("releasing mbuf %p", mbuf); 45 46 accessUnit->meta()->setPointer("mediaBuffer", NULL); 47 48 static_cast<MediaBuffer *>(mbuf)->release(); 49 mbuf = NULL; 50 } 51} 52 53struct MediaCodecSource::Puller : public AHandler { 54 Puller(const sp<MediaSource> &source); 55 56 status_t start(const sp<MetaData> &meta, const sp<AMessage> ¬ify); 57 void stopAsync(); 58 59 void pause(); 60 void resume(); 61 62protected: 63 virtual void onMessageReceived(const sp<AMessage> &msg); 64 virtual ~Puller(); 65 66private: 67 enum { 68 kWhatStart = 'msta', 69 kWhatStop, 70 kWhatPull, 71 kWhatPause, 72 kWhatResume, 73 }; 74 75 sp<MediaSource> mSource; 76 sp<AMessage> mNotify; 77 sp<ALooper> mLooper; 78 int32_t mPullGeneration; 79 bool mIsAudio; 80 bool mPaused; 81 bool mReachedEOS; 82 83 status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg); 84 void schedulePull(); 85 void handleEOS(); 86 87 DISALLOW_EVIL_CONSTRUCTORS(Puller); 88}; 89 90MediaCodecSource::Puller::Puller(const sp<MediaSource> &source) 91 : mSource(source), 92 mLooper(new ALooper()), 93 mPullGeneration(0), 94 mIsAudio(false), 95 mPaused(false), 96 mReachedEOS(false) { 97 sp<MetaData> meta = source->getFormat(); 98 const char *mime; 99 CHECK(meta->findCString(kKeyMIMEType, &mime)); 100 101 mIsAudio = !strncasecmp(mime, "audio/", 6); 102 103 mLooper->setName("pull_looper"); 104} 105 106MediaCodecSource::Puller::~Puller() { 107 mLooper->unregisterHandler(id()); 108 mLooper->stop(); 109} 110 111status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError( 112 const sp<AMessage> &msg) { 113 sp<AMessage> response; 114 status_t err = msg->postAndAwaitResponse(&response); 115 116 if (err != OK) { 117 return err; 118 } 119 120 if (!response->findInt32("err", &err)) { 121 err = OK; 122 } 123 124 return err; 125} 126 127status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, 128 const sp<AMessage> ¬ify) { 129 ALOGV("puller (%s) start", mIsAudio ? "audio" : "video"); 130 mLooper->start( 131 false /* runOnCallingThread */, 132 false /* canCallJava */, 133 PRIORITY_AUDIO); 134 mLooper->registerHandler(this); 135 mNotify = notify; 136 137 sp<AMessage> msg = new AMessage(kWhatStart, id()); 138 msg->setObject("meta", meta); 139 return postSynchronouslyAndReturnError(msg); 140} 141 142void MediaCodecSource::Puller::stopAsync() { 143 ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video"); 144 (new AMessage(kWhatStop, id()))->post(); 145} 146 147void MediaCodecSource::Puller::pause() { 148 (new AMessage(kWhatPause, id()))->post(); 149} 150 151void MediaCodecSource::Puller::resume() { 152 (new AMessage(kWhatResume, id()))->post(); 153} 154 155void MediaCodecSource::Puller::schedulePull() { 156 sp<AMessage> msg = new AMessage(kWhatPull, id()); 157 msg->setInt32("generation", mPullGeneration); 158 msg->post(); 159} 160 161void MediaCodecSource::Puller::handleEOS() { 162 if (!mReachedEOS) { 163 ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video"); 164 mReachedEOS = true; 165 sp<AMessage> notify = mNotify->dup(); 166 notify->setPointer("accessUnit", NULL); 167 notify->post(); 168 } 169} 170 171void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) { 172 switch (msg->what()) { 173 case kWhatStart: 174 { 175 sp<RefBase> obj; 176 CHECK(msg->findObject("meta", &obj)); 177 178 mReachedEOS = false; 179 180 status_t err = mSource->start(static_cast<MetaData *>(obj.get())); 181 182 if (err == OK) { 183 schedulePull(); 184 } 185 186 sp<AMessage> response = new AMessage; 187 response->setInt32("err", err); 188 189 uint32_t replyID; 190 CHECK(msg->senderAwaitsResponse(&replyID)); 191 response->postReply(replyID); 192 break; 193 } 194 195 case kWhatStop: 196 { 197 ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); 198 mSource->stop(); 199 ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); 200 ++mPullGeneration; 201 202 handleEOS(); 203 break; 204 } 205 206 case kWhatPull: 207 { 208 int32_t generation; 209 CHECK(msg->findInt32("generation", &generation)); 210 211 if (generation != mPullGeneration) { 212 break; 213 } 214 215 MediaBuffer *mbuf; 216 status_t err = mSource->read(&mbuf); 217 218 if (mPaused) { 219 if (err == OK) { 220 mbuf->release(); 221 mbuf = NULL; 222 } 223 224 msg->post(); 225 break; 226 } 227 228 if (err != OK) { 229 if (err == ERROR_END_OF_STREAM) { 230 ALOGV("stream ended, mbuf %p", mbuf); 231 } else { 232 ALOGE("error %d reading stream.", err); 233 } 234 handleEOS(); 235 } else { 236 sp<AMessage> notify = mNotify->dup(); 237 238 notify->setPointer("accessUnit", mbuf); 239 notify->post(); 240 241 msg->post(); 242 } 243 break; 244 } 245 246 case kWhatPause: 247 { 248 mPaused = true; 249 break; 250 } 251 252 case kWhatResume: 253 { 254 mPaused = false; 255 break; 256 } 257 258 default: 259 TRESPASS(); 260 } 261} 262 263// static 264sp<MediaCodecSource> MediaCodecSource::Create( 265 const sp<ALooper> &looper, 266 const sp<AMessage> &format, 267 const sp<MediaSource> &source, 268 uint32_t flags) { 269 sp<MediaCodecSource> mediaSource = 270 new MediaCodecSource(looper, format, source, flags); 271 272 if (mediaSource->init() == OK) { 273 return mediaSource; 274 } 275 return NULL; 276} 277 278status_t MediaCodecSource::start(MetaData* params) { 279 sp<AMessage> msg = new AMessage(kWhatStart, mReflector->id()); 280 msg->setObject("meta", params); 281 return postSynchronouslyAndReturnError(msg); 282} 283 284status_t MediaCodecSource::stop() { 285 sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id()); 286 return postSynchronouslyAndReturnError(msg); 287} 288 289status_t MediaCodecSource::pause() { 290 (new AMessage(kWhatPause, mReflector->id()))->post(); 291 return OK; 292} 293 294sp<IGraphicBufferProducer> MediaCodecSource::getGraphicBufferProducer() { 295 CHECK(mFlags & FLAG_USE_SURFACE_INPUT); 296 return mGraphicBufferProducer; 297} 298 299status_t MediaCodecSource::read( 300 MediaBuffer** buffer, const ReadOptions* /* options */) { 301 Mutex::Autolock autolock(mOutputBufferLock); 302 303 *buffer = NULL; 304 while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) { 305 mOutputBufferCond.wait(mOutputBufferLock); 306 } 307 if (!mEncodedReachedEOS) { 308 *buffer = *mOutputBufferQueue.begin(); 309 mOutputBufferQueue.erase(mOutputBufferQueue.begin()); 310 return OK; 311 } 312 return mErrorCode; 313} 314 315void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) { 316 buffer->setObserver(0); 317 buffer->release(); 318} 319 320MediaCodecSource::MediaCodecSource( 321 const sp<ALooper> &looper, 322 const sp<AMessage> &outputFormat, 323 const sp<MediaSource> &source, 324 uint32_t flags) 325 : mLooper(looper), 326 mOutputFormat(outputFormat), 327 mMeta(new MetaData), 328 mFlags(flags), 329 mIsVideo(false), 330 mStarted(false), 331 mStopping(false), 332 mDoMoreWorkPending(false), 333 mPullerReachedEOS(false), 334 mFirstSampleTimeUs(-1ll), 335 mEncodedReachedEOS(false), 336 mErrorCode(OK) { 337 CHECK(mLooper != NULL); 338 339 AString mime; 340 CHECK(mOutputFormat->findString("mime", &mime)); 341 342 if (!strncasecmp("video/", mime.c_str(), 6)) { 343 mIsVideo = true; 344 } 345 346 if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { 347 mPuller = new Puller(source); 348 } 349} 350 351MediaCodecSource::~MediaCodecSource() { 352 releaseEncoder(); 353 354 mCodecLooper->stop(); 355 mLooper->unregisterHandler(mReflector->id()); 356} 357 358status_t MediaCodecSource::init() { 359 status_t err = initEncoder(); 360 361 if (err != OK) { 362 releaseEncoder(); 363 } 364 365 return err; 366} 367 368status_t MediaCodecSource::initEncoder() { 369 mReflector = new AHandlerReflector<MediaCodecSource>(this); 370 mLooper->registerHandler(mReflector); 371 372 mCodecLooper = new ALooper; 373 mCodecLooper->setName("codec_looper"); 374 mCodecLooper->start(); 375 376 if (mFlags & FLAG_USE_METADATA_INPUT) { 377 mOutputFormat->setInt32("store-metadata-in-buffers", 1); 378 } 379 380 if (mFlags & FLAG_USE_SURFACE_INPUT) { 381 mOutputFormat->setInt32("create-input-buffers-suspended", 1); 382 } 383 384 AString outputMIME; 385 CHECK(mOutputFormat->findString("mime", &outputMIME)); 386 387 mEncoder = MediaCodec::CreateByType( 388 mCodecLooper, outputMIME.c_str(), true /* encoder */); 389 390 if (mEncoder == NULL) { 391 return NO_INIT; 392 } 393 394 ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); 395 396 status_t err = mEncoder->configure( 397 mOutputFormat, 398 NULL /* nativeWindow */, 399 NULL /* crypto */, 400 MediaCodec::CONFIGURE_FLAG_ENCODE); 401 402 if (err != OK) { 403 return err; 404 } 405 406 mEncoder->getOutputFormat(&mOutputFormat); 407 convertMessageToMetaData(mOutputFormat, mMeta); 408 409 if (mFlags & FLAG_USE_SURFACE_INPUT) { 410 CHECK(mIsVideo); 411 412 err = mEncoder->createInputSurface(&mGraphicBufferProducer); 413 414 if (err != OK) { 415 return err; 416 } 417 } 418 419 err = mEncoder->start(); 420 421 if (err != OK) { 422 return err; 423 } 424 425 err = mEncoder->getInputBuffers(&mEncoderInputBuffers); 426 427 if (err != OK) { 428 return err; 429 } 430 431 err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers); 432 433 if (err != OK) { 434 return err; 435 } 436 437 mEncodedReachedEOS = false; 438 mErrorCode = OK; 439 440 return OK; 441} 442 443void MediaCodecSource::releaseEncoder() { 444 if (mEncoder == NULL) { 445 return; 446 } 447 448 mEncoder->release(); 449 mEncoder.clear(); 450 451 while (!mInputBufferQueue.empty()) { 452 MediaBuffer *mbuf = *mInputBufferQueue.begin(); 453 mInputBufferQueue.erase(mInputBufferQueue.begin()); 454 if (mbuf != NULL) { 455 mbuf->release(); 456 } 457 } 458 459 for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) { 460 sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i); 461 ReleaseMediaBufferReference(accessUnit); 462 } 463 464 mEncoderInputBuffers.clear(); 465 mEncoderOutputBuffers.clear(); 466} 467 468bool MediaCodecSource::reachedEOS() { 469 return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS); 470} 471 472status_t MediaCodecSource::postSynchronouslyAndReturnError( 473 const sp<AMessage> &msg) { 474 sp<AMessage> response; 475 status_t err = msg->postAndAwaitResponse(&response); 476 477 if (err != OK) { 478 return err; 479 } 480 481 if (!response->findInt32("err", &err)) { 482 err = OK; 483 } 484 485 return err; 486} 487 488void MediaCodecSource::signalEOS(status_t err) { 489 if (!mEncodedReachedEOS) { 490 ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); 491 { 492 Mutex::Autolock autoLock(mOutputBufferLock); 493 // release all unread media buffers 494 for (List<MediaBuffer*>::iterator it = mOutputBufferQueue.begin(); 495 it != mOutputBufferQueue.end(); it++) { 496 (*it)->release(); 497 } 498 mOutputBufferQueue.clear(); 499 mEncodedReachedEOS = true; 500 mErrorCode = err; 501 mOutputBufferCond.signal(); 502 } 503 504 releaseEncoder(); 505 } 506 if (mStopping && reachedEOS()) { 507 ALOGI("MediaCodecSource (%s) fully stopped", 508 mIsVideo ? "video" : "audio"); 509 // posting reply to everyone that's waiting 510 List<uint32_t>::iterator it; 511 for (it = mStopReplyIDQueue.begin(); 512 it != mStopReplyIDQueue.end(); it++) { 513 (new AMessage)->postReply(*it); 514 } 515 mStopReplyIDQueue.clear(); 516 mStopping = false; 517 } 518} 519 520void MediaCodecSource::suspend() { 521 CHECK(mFlags & FLAG_USE_SURFACE_INPUT); 522 if (mEncoder != NULL) { 523 sp<AMessage> params = new AMessage; 524 params->setInt32("drop-input-frames", true); 525 mEncoder->setParameters(params); 526 } 527} 528 529void MediaCodecSource::resume(int64_t skipFramesBeforeUs) { 530 CHECK(mFlags & FLAG_USE_SURFACE_INPUT); 531 if (mEncoder != NULL) { 532 sp<AMessage> params = new AMessage; 533 params->setInt32("drop-input-frames", false); 534 if (skipFramesBeforeUs > 0) { 535 params->setInt64("skip-frames-before", skipFramesBeforeUs); 536 } 537 mEncoder->setParameters(params); 538 } 539} 540 541void MediaCodecSource::scheduleDoMoreWork() { 542 if (mDoMoreWorkPending) { 543 return; 544 } 545 546 mDoMoreWorkPending = true; 547 548 if (mEncoderActivityNotify == NULL) { 549 mEncoderActivityNotify = new AMessage( 550 kWhatEncoderActivity, mReflector->id()); 551 } 552 mEncoder->requestActivityNotification(mEncoderActivityNotify); 553} 554 555status_t MediaCodecSource::feedEncoderInputBuffers() { 556 while (!mInputBufferQueue.empty() 557 && !mAvailEncoderInputIndices.empty()) { 558 MediaBuffer* mbuf = *mInputBufferQueue.begin(); 559 mInputBufferQueue.erase(mInputBufferQueue.begin()); 560 561 size_t bufferIndex = *mAvailEncoderInputIndices.begin(); 562 mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); 563 564 int64_t timeUs = 0ll; 565 uint32_t flags = 0; 566 size_t size = 0; 567 568 if (mbuf != NULL) { 569 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 570 571 // push decoding time for video, or drift time for audio 572 if (mIsVideo) { 573 mDecodingTimeQueue.push_back(timeUs); 574 } else { 575#if DEBUG_DRIFT_TIME 576 if (mFirstSampleTimeUs < 0ll) { 577 mFirstSampleTimeUs = timeUs; 578 } 579 580 int64_t driftTimeUs = 0; 581 if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs) 582 && driftTimeUs) { 583 driftTimeUs = timeUs - mFirstSampleTimeUs - driftTimeUs; 584 } 585 mDriftTimeQueue.push_back(driftTimeUs); 586#endif // DEBUG_DRIFT_TIME 587 } 588 589 size = mbuf->size(); 590 591 memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), 592 mbuf->data(), size); 593 594 if (mIsVideo) { 595 // video encoder will release MediaBuffer when done 596 // with underlying data. 597 mEncoderInputBuffers.itemAt(bufferIndex)->meta() 598 ->setPointer("mediaBuffer", mbuf); 599 } else { 600 mbuf->release(); 601 } 602 } else { 603 flags = MediaCodec::BUFFER_FLAG_EOS; 604 } 605 606 status_t err = mEncoder->queueInputBuffer( 607 bufferIndex, 0, size, timeUs, flags); 608 609 if (err != OK) { 610 return err; 611 } 612 } 613 614 return OK; 615} 616 617status_t MediaCodecSource::doMoreWork() { 618 status_t err; 619 620 if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { 621 for (;;) { 622 size_t bufferIndex; 623 err = mEncoder->dequeueInputBuffer(&bufferIndex); 624 625 if (err != OK) { 626 break; 627 } 628 629 mAvailEncoderInputIndices.push_back(bufferIndex); 630 } 631 632 feedEncoderInputBuffers(); 633 } 634 635 for (;;) { 636 size_t bufferIndex; 637 size_t offset; 638 size_t size; 639 int64_t timeUs; 640 uint32_t flags; 641 native_handle_t* handle = NULL; 642 err = mEncoder->dequeueOutputBuffer( 643 &bufferIndex, &offset, &size, &timeUs, &flags); 644 645 if (err != OK) { 646 if (err == INFO_FORMAT_CHANGED) { 647 continue; 648 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { 649 mEncoder->getOutputBuffers(&mEncoderOutputBuffers); 650 continue; 651 } 652 653 if (err == -EAGAIN) { 654 err = OK; 655 } 656 break; 657 } 658 if (!(flags & MediaCodec::BUFFER_FLAG_EOS)) { 659 sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex); 660 661 MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); 662 memcpy(mbuf->data(), outbuf->data(), outbuf->size()); 663 664 if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) { 665 if (mIsVideo) { 666 int64_t decodingTimeUs; 667 if (mFlags & FLAG_USE_SURFACE_INPUT) { 668 // GraphicBufferSource is supposed to discard samples 669 // queued before start, and offset timeUs by start time 670 CHECK_GE(timeUs, 0ll); 671 // TODO: 672 // Decoding time for surface source is unavailable, 673 // use presentation time for now. May need to move 674 // this logic into MediaCodec. 675 decodingTimeUs = timeUs; 676 } else { 677 CHECK(!mDecodingTimeQueue.empty()); 678 decodingTimeUs = *(mDecodingTimeQueue.begin()); 679 mDecodingTimeQueue.erase(mDecodingTimeQueue.begin()); 680 } 681 mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); 682 683 ALOGV("[video] time %" PRId64 " us (%.2f secs), dts/pts diff %" PRId64, 684 timeUs, timeUs / 1E6, decodingTimeUs - timeUs); 685 } else { 686 int64_t driftTimeUs = 0; 687#if DEBUG_DRIFT_TIME 688 CHECK(!mDriftTimeQueue.empty()); 689 driftTimeUs = *(mDriftTimeQueue.begin()); 690 mDriftTimeQueue.erase(mDriftTimeQueue.begin()); 691 mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs); 692#endif // DEBUG_DRIFT_TIME 693 ALOGV("[audio] time %" PRId64 " us (%.2f secs), drift %" PRId64, 694 timeUs, timeUs / 1E6, driftTimeUs); 695 } 696 mbuf->meta_data()->setInt64(kKeyTime, timeUs); 697 } else { 698 mbuf->meta_data()->setInt32(kKeyIsCodecConfig, true); 699 } 700 if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) { 701 mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true); 702 } 703 mbuf->setObserver(this); 704 mbuf->add_ref(); 705 706 { 707 Mutex::Autolock autoLock(mOutputBufferLock); 708 mOutputBufferQueue.push_back(mbuf); 709 mOutputBufferCond.signal(); 710 } 711 } 712 713 mEncoder->releaseOutputBuffer(bufferIndex); 714 715 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 716 err = ERROR_END_OF_STREAM; 717 break; 718 } 719 } 720 721 return err; 722} 723 724status_t MediaCodecSource::onStart(MetaData *params) { 725 if (mStopping) { 726 ALOGE("Failed to start while we're stopping"); 727 return INVALID_OPERATION; 728 } 729 730 if (mStarted) { 731 ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio"); 732 if (mFlags & FLAG_USE_SURFACE_INPUT) { 733 resume(); 734 } else { 735 CHECK(mPuller != NULL); 736 mPuller->resume(); 737 } 738 return OK; 739 } 740 741 ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio"); 742 743 status_t err = OK; 744 745 if (mFlags & FLAG_USE_SURFACE_INPUT) { 746 int64_t startTimeUs; 747 if (!params || !params->findInt64(kKeyTime, &startTimeUs)) { 748 startTimeUs = -1ll; 749 } 750 resume(startTimeUs); 751 scheduleDoMoreWork(); 752 } else { 753 CHECK(mPuller != NULL); 754 sp<AMessage> notify = new AMessage( 755 kWhatPullerNotify, mReflector->id()); 756 err = mPuller->start(params, notify); 757 if (err != OK) { 758 mPullerReachedEOS = true; 759 return err; 760 } 761 } 762 763 ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio"); 764 765 mStarted = true; 766 return OK; 767} 768 769void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { 770 switch (msg->what()) { 771 case kWhatPullerNotify: 772 { 773 MediaBuffer *mbuf; 774 CHECK(msg->findPointer("accessUnit", (void**)&mbuf)); 775 776 if (mbuf == NULL) { 777 ALOGI("puller (%s) reached EOS", 778 mIsVideo ? "video" : "audio"); 779 mPullerReachedEOS = true; 780 } 781 782 if (mEncoder == NULL) { 783 ALOGV("got msg '%s' after encoder shutdown.", 784 msg->debugString().c_str()); 785 786 if (mbuf != NULL) { 787 mbuf->release(); 788 } else { 789 signalEOS(); 790 } 791 break; 792 } 793 794 mInputBufferQueue.push_back(mbuf); 795 796 feedEncoderInputBuffers(); 797 scheduleDoMoreWork(); 798 799 break; 800 } 801 case kWhatEncoderActivity: 802 { 803 mDoMoreWorkPending = false; 804 805 if (mEncoder == NULL) { 806 break; 807 } 808 809 status_t err = doMoreWork(); 810 811 if (err == OK) { 812 scheduleDoMoreWork(); 813 } else { 814 // reached EOS, or error 815 signalEOS(err); 816 } 817 818 break; 819 } 820 case kWhatStart: 821 { 822 uint32_t replyID; 823 CHECK(msg->senderAwaitsResponse(&replyID)); 824 825 sp<RefBase> obj; 826 CHECK(msg->findObject("meta", &obj)); 827 MetaData *params = static_cast<MetaData *>(obj.get()); 828 829 sp<AMessage> response = new AMessage; 830 response->setInt32("err", onStart(params)); 831 response->postReply(replyID); 832 break; 833 } 834 case kWhatStop: 835 { 836 ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio"); 837 838 uint32_t replyID; 839 CHECK(msg->senderAwaitsResponse(&replyID)); 840 841 if (reachedEOS()) { 842 // if we already reached EOS, reply and return now 843 ALOGI("MediaCodecSource (%s) already stopped", 844 mIsVideo ? "video" : "audio"); 845 (new AMessage)->postReply(replyID); 846 break; 847 } 848 849 mStopReplyIDQueue.push_back(replyID); 850 if (mStopping) { 851 // nothing to do if we're already stopping, reply will be posted 852 // to all when we're stopped. 853 break; 854 } 855 856 mStopping = true; 857 858 // if using surface, signal source EOS and wait for EOS to come back. 859 // otherwise, release encoder and post EOS if haven't done already 860 if (mFlags & FLAG_USE_SURFACE_INPUT) { 861 mEncoder->signalEndOfInputStream(); 862 } else { 863 CHECK(mPuller != NULL); 864 mPuller->stopAsync(); 865 signalEOS(); 866 } 867 break; 868 } 869 case kWhatPause: 870 { 871 if (mFlags && FLAG_USE_SURFACE_INPUT) { 872 suspend(); 873 } else { 874 CHECK(mPuller != NULL); 875 mPuller->pause(); 876 } 877 break; 878 } 879 default: 880 TRESPASS(); 881 } 882} 883 884} // namespace android 885