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