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