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