NuPlayer.cpp revision df712ea86e6350f7005a02ab0e1c60c28a343ed0
1/* 2 * Copyright (C) 2010 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 "NuPlayer" 19#include <utils/Log.h> 20 21#include "NuPlayer.h" 22 23#include "HTTPLiveSource.h" 24#include "NuPlayerDecoder.h" 25#include "NuPlayerDriver.h" 26#include "NuPlayerRenderer.h" 27#include "NuPlayerSource.h" 28#include "RTSPSource.h" 29#include "StreamingSource.h" 30 31#include "ATSParser.h" 32 33#include <media/stagefright/foundation/hexdump.h> 34#include <media/stagefright/foundation/ABuffer.h> 35#include <media/stagefright/foundation/ADebug.h> 36#include <media/stagefright/foundation/AMessage.h> 37#include <media/stagefright/ACodec.h> 38#include <media/stagefright/MediaDefs.h> 39#include <media/stagefright/MediaErrors.h> 40#include <media/stagefright/MetaData.h> 41#include <gui/ISurfaceTexture.h> 42 43#include "avc_utils.h" 44 45namespace android { 46 47//////////////////////////////////////////////////////////////////////////////// 48 49NuPlayer::NuPlayer() 50 : mUIDValid(false), 51 mVideoIsAVC(false), 52 mAudioEOS(false), 53 mVideoEOS(false), 54 mScanSourcesPending(false), 55 mScanSourcesGeneration(0), 56 mTimeDiscontinuityPending(false), 57 mFlushingAudio(NONE), 58 mFlushingVideo(NONE), 59 mResetInProgress(false), 60 mResetPostponed(false), 61 mSkipRenderingAudioUntilMediaTimeUs(-1ll), 62 mSkipRenderingVideoUntilMediaTimeUs(-1ll), 63 mVideoLateByUs(0ll), 64 mNumFramesTotal(0ll), 65 mNumFramesDropped(0ll) { 66} 67 68NuPlayer::~NuPlayer() { 69} 70 71void NuPlayer::setUID(uid_t uid) { 72 mUIDValid = true; 73 mUID = uid; 74} 75 76void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) { 77 mDriver = driver; 78} 79 80void NuPlayer::setDataSource(const sp<IStreamSource> &source) { 81 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 82 83 msg->setObject("source", new StreamingSource(source)); 84 msg->post(); 85} 86 87void NuPlayer::setDataSource( 88 const char *url, const KeyedVector<String8, String8> *headers) { 89 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 90 91 if (!strncasecmp(url, "rtsp://", 7)) { 92 msg->setObject( 93 "source", new RTSPSource(url, headers, mUIDValid, mUID)); 94 } else { 95 msg->setObject( 96 "source", new HTTPLiveSource(url, headers, mUIDValid, mUID)); 97 } 98 99 msg->post(); 100} 101 102void NuPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 103 sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id()); 104 sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ? 105 new SurfaceTextureClient(surfaceTexture) : NULL); 106 msg->setObject("native-window", new NativeWindowWrapper(surfaceTextureClient)); 107 msg->post(); 108} 109 110void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { 111 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id()); 112 msg->setObject("sink", sink); 113 msg->post(); 114} 115 116void NuPlayer::start() { 117 (new AMessage(kWhatStart, id()))->post(); 118} 119 120void NuPlayer::pause() { 121 (new AMessage(kWhatPause, id()))->post(); 122} 123 124void NuPlayer::resume() { 125 (new AMessage(kWhatResume, id()))->post(); 126} 127 128void NuPlayer::resetAsync() { 129 (new AMessage(kWhatReset, id()))->post(); 130} 131 132void NuPlayer::seekToAsync(int64_t seekTimeUs) { 133 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 134 msg->setInt64("seekTimeUs", seekTimeUs); 135 msg->post(); 136} 137 138// static 139bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { 140 switch (state) { 141 case FLUSHING_DECODER: 142 if (needShutdown != NULL) { 143 *needShutdown = false; 144 } 145 return true; 146 147 case FLUSHING_DECODER_SHUTDOWN: 148 if (needShutdown != NULL) { 149 *needShutdown = true; 150 } 151 return true; 152 153 default: 154 return false; 155 } 156} 157 158void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { 159 switch (msg->what()) { 160 case kWhatSetDataSource: 161 { 162 ALOGV("kWhatSetDataSource"); 163 164 CHECK(mSource == NULL); 165 166 sp<RefBase> obj; 167 CHECK(msg->findObject("source", &obj)); 168 169 mSource = static_cast<Source *>(obj.get()); 170 break; 171 } 172 173 case kWhatSetVideoNativeWindow: 174 { 175 ALOGV("kWhatSetVideoNativeWindow"); 176 177 sp<RefBase> obj; 178 CHECK(msg->findObject("native-window", &obj)); 179 180 mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get()); 181 break; 182 } 183 184 case kWhatSetAudioSink: 185 { 186 ALOGV("kWhatSetAudioSink"); 187 188 sp<RefBase> obj; 189 CHECK(msg->findObject("sink", &obj)); 190 191 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); 192 break; 193 } 194 195 case kWhatStart: 196 { 197 ALOGV("kWhatStart"); 198 199 mVideoIsAVC = false; 200 mAudioEOS = false; 201 mVideoEOS = false; 202 mSkipRenderingAudioUntilMediaTimeUs = -1; 203 mSkipRenderingVideoUntilMediaTimeUs = -1; 204 mVideoLateByUs = 0; 205 mNumFramesTotal = 0; 206 mNumFramesDropped = 0; 207 208 mSource->start(); 209 210 mRenderer = new Renderer( 211 mAudioSink, 212 new AMessage(kWhatRendererNotify, id())); 213 214 looper()->registerHandler(mRenderer); 215 216 postScanSources(); 217 break; 218 } 219 220 case kWhatScanSources: 221 { 222 int32_t generation; 223 CHECK(msg->findInt32("generation", &generation)); 224 if (generation != mScanSourcesGeneration) { 225 // Drop obsolete msg. 226 break; 227 } 228 229 mScanSourcesPending = false; 230 231 ALOGV("scanning sources haveAudio=%d, haveVideo=%d", 232 mAudioDecoder != NULL, mVideoDecoder != NULL); 233 234 instantiateDecoder(false, &mVideoDecoder); 235 236 if (mAudioSink != NULL) { 237 instantiateDecoder(true, &mAudioDecoder); 238 } 239 240 status_t err; 241 if ((err = mSource->feedMoreTSData()) != OK) { 242 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 243 // We're not currently decoding anything (no audio or 244 // video tracks found) and we just ran out of input data. 245 246 if (err == ERROR_END_OF_STREAM) { 247 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 248 } else { 249 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 250 } 251 } 252 break; 253 } 254 255 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 256 msg->post(100000ll); 257 mScanSourcesPending = true; 258 } 259 break; 260 } 261 262 case kWhatVideoNotify: 263 case kWhatAudioNotify: 264 { 265 bool audio = msg->what() == kWhatAudioNotify; 266 267 sp<AMessage> codecRequest; 268 CHECK(msg->findMessage("codec-request", &codecRequest)); 269 270 int32_t what; 271 CHECK(codecRequest->findInt32("what", &what)); 272 273 if (what == ACodec::kWhatFillThisBuffer) { 274 status_t err = feedDecoderInputData( 275 audio, codecRequest); 276 277 if (err == -EWOULDBLOCK) { 278 if (mSource->feedMoreTSData() == OK) { 279 msg->post(10000ll); 280 } 281 } 282 } else if (what == ACodec::kWhatEOS) { 283 int32_t err; 284 CHECK(codecRequest->findInt32("err", &err)); 285 286 if (err == ERROR_END_OF_STREAM) { 287 ALOGV("got %s decoder EOS", audio ? "audio" : "video"); 288 } else { 289 ALOGV("got %s decoder EOS w/ error %d", 290 audio ? "audio" : "video", 291 err); 292 } 293 294 mRenderer->queueEOS(audio, err); 295 } else if (what == ACodec::kWhatFlushCompleted) { 296 bool needShutdown; 297 298 if (audio) { 299 CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); 300 mFlushingAudio = FLUSHED; 301 } else { 302 CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); 303 mFlushingVideo = FLUSHED; 304 305 mVideoLateByUs = 0; 306 } 307 308 ALOGV("decoder %s flush completed", audio ? "audio" : "video"); 309 310 if (needShutdown) { 311 ALOGV("initiating %s decoder shutdown", 312 audio ? "audio" : "video"); 313 314 (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); 315 316 if (audio) { 317 mFlushingAudio = SHUTTING_DOWN_DECODER; 318 } else { 319 mFlushingVideo = SHUTTING_DOWN_DECODER; 320 } 321 } 322 323 finishFlushIfPossible(); 324 } else if (what == ACodec::kWhatOutputFormatChanged) { 325 if (audio) { 326 int32_t numChannels; 327 CHECK(codecRequest->findInt32("channel-count", &numChannels)); 328 329 int32_t sampleRate; 330 CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); 331 332 ALOGV("Audio output format changed to %d Hz, %d channels", 333 sampleRate, numChannels); 334 335 mAudioSink->close(); 336 CHECK_EQ(mAudioSink->open( 337 sampleRate, 338 numChannels, 339 AUDIO_FORMAT_PCM_16_BIT, 340 8 /* bufferCount */), 341 (status_t)OK); 342 mAudioSink->start(); 343 344 mRenderer->signalAudioSinkChanged(); 345 } else { 346 // video 347 348 int32_t width, height; 349 CHECK(codecRequest->findInt32("width", &width)); 350 CHECK(codecRequest->findInt32("height", &height)); 351 352 int32_t cropLeft, cropTop, cropRight, cropBottom; 353 CHECK(codecRequest->findRect( 354 "crop", 355 &cropLeft, &cropTop, &cropRight, &cropBottom)); 356 357 ALOGV("Video output format changed to %d x %d " 358 "(crop: %d x %d @ (%d, %d))", 359 width, height, 360 (cropRight - cropLeft + 1), 361 (cropBottom - cropTop + 1), 362 cropLeft, cropTop); 363 364 notifyListener( 365 MEDIA_SET_VIDEO_SIZE, 366 cropRight - cropLeft + 1, 367 cropBottom - cropTop + 1); 368 } 369 } else if (what == ACodec::kWhatShutdownCompleted) { 370 ALOGV("%s shutdown completed", audio ? "audio" : "video"); 371 if (audio) { 372 mAudioDecoder.clear(); 373 374 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); 375 mFlushingAudio = SHUT_DOWN; 376 } else { 377 mVideoDecoder.clear(); 378 379 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); 380 mFlushingVideo = SHUT_DOWN; 381 } 382 383 finishFlushIfPossible(); 384 } else if (what == ACodec::kWhatError) { 385 ALOGE("Received error from %s decoder, aborting playback.", 386 audio ? "audio" : "video"); 387 388 mRenderer->queueEOS(audio, UNKNOWN_ERROR); 389 } else if (what == ACodec::kWhatDrainThisBuffer) { 390 renderBuffer(audio, codecRequest); 391 } else { 392 ALOGV("Unhandled codec notification %d.", what); 393 } 394 395 break; 396 } 397 398 case kWhatRendererNotify: 399 { 400 int32_t what; 401 CHECK(msg->findInt32("what", &what)); 402 403 if (what == Renderer::kWhatEOS) { 404 int32_t audio; 405 CHECK(msg->findInt32("audio", &audio)); 406 407 int32_t finalResult; 408 CHECK(msg->findInt32("finalResult", &finalResult)); 409 410 if (audio) { 411 mAudioEOS = true; 412 } else { 413 mVideoEOS = true; 414 } 415 416 if (finalResult == ERROR_END_OF_STREAM) { 417 ALOGV("reached %s EOS", audio ? "audio" : "video"); 418 } else { 419 ALOGE("%s track encountered an error (%d)", 420 audio ? "audio" : "video", finalResult); 421 422 notifyListener( 423 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); 424 } 425 426 if ((mAudioEOS || mAudioDecoder == NULL) 427 && (mVideoEOS || mVideoDecoder == NULL)) { 428 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 429 } 430 } else if (what == Renderer::kWhatPosition) { 431 int64_t positionUs; 432 CHECK(msg->findInt64("positionUs", &positionUs)); 433 434 CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); 435 436 if (mDriver != NULL) { 437 sp<NuPlayerDriver> driver = mDriver.promote(); 438 if (driver != NULL) { 439 driver->notifyPosition(positionUs); 440 441 driver->notifyFrameStats( 442 mNumFramesTotal, mNumFramesDropped); 443 } 444 } 445 } else if (what == Renderer::kWhatFlushComplete) { 446 CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete); 447 448 int32_t audio; 449 CHECK(msg->findInt32("audio", &audio)); 450 451 ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); 452 } 453 break; 454 } 455 456 case kWhatMoreDataQueued: 457 { 458 break; 459 } 460 461 case kWhatReset: 462 { 463 ALOGV("kWhatReset"); 464 465 if (mRenderer != NULL) { 466 // There's an edge case where the renderer owns all output 467 // buffers and is paused, therefore the decoder will not read 468 // more input data and will never encounter the matching 469 // discontinuity. To avoid this, we resume the renderer. 470 471 if (mFlushingAudio == AWAITING_DISCONTINUITY 472 || mFlushingVideo == AWAITING_DISCONTINUITY) { 473 mRenderer->resume(); 474 } 475 } 476 477 if (mFlushingAudio != NONE || mFlushingVideo != NONE) { 478 // We're currently flushing, postpone the reset until that's 479 // completed. 480 481 ALOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d", 482 mFlushingAudio, mFlushingVideo); 483 484 mResetPostponed = true; 485 break; 486 } 487 488 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 489 finishReset(); 490 break; 491 } 492 493 mTimeDiscontinuityPending = true; 494 495 if (mAudioDecoder != NULL) { 496 flushDecoder(true /* audio */, true /* needShutdown */); 497 } 498 499 if (mVideoDecoder != NULL) { 500 flushDecoder(false /* audio */, true /* needShutdown */); 501 } 502 503 mResetInProgress = true; 504 break; 505 } 506 507 case kWhatSeek: 508 { 509 int64_t seekTimeUs; 510 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 511 512 ALOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)", 513 seekTimeUs, seekTimeUs / 1E6); 514 515 mSource->seekTo(seekTimeUs); 516 517 if (mDriver != NULL) { 518 sp<NuPlayerDriver> driver = mDriver.promote(); 519 if (driver != NULL) { 520 driver->notifySeekComplete(); 521 } 522 } 523 524 break; 525 } 526 527 case kWhatPause: 528 { 529 CHECK(mRenderer != NULL); 530 mRenderer->pause(); 531 break; 532 } 533 534 case kWhatResume: 535 { 536 CHECK(mRenderer != NULL); 537 mRenderer->resume(); 538 break; 539 } 540 541 default: 542 TRESPASS(); 543 break; 544 } 545} 546 547void NuPlayer::finishFlushIfPossible() { 548 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { 549 return; 550 } 551 552 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { 553 return; 554 } 555 556 ALOGV("both audio and video are flushed now."); 557 558 if (mTimeDiscontinuityPending) { 559 mRenderer->signalTimeDiscontinuity(); 560 mTimeDiscontinuityPending = false; 561 } 562 563 if (mAudioDecoder != NULL) { 564 mAudioDecoder->signalResume(); 565 } 566 567 if (mVideoDecoder != NULL) { 568 mVideoDecoder->signalResume(); 569 } 570 571 mFlushingAudio = NONE; 572 mFlushingVideo = NONE; 573 574 if (mResetInProgress) { 575 ALOGV("reset completed"); 576 577 mResetInProgress = false; 578 finishReset(); 579 } else if (mResetPostponed) { 580 (new AMessage(kWhatReset, id()))->post(); 581 mResetPostponed = false; 582 } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 583 postScanSources(); 584 } 585} 586 587void NuPlayer::finishReset() { 588 CHECK(mAudioDecoder == NULL); 589 CHECK(mVideoDecoder == NULL); 590 591 ++mScanSourcesGeneration; 592 mScanSourcesPending = false; 593 594 mRenderer.clear(); 595 596 if (mSource != NULL) { 597 mSource->stop(); 598 mSource.clear(); 599 } 600 601 if (mDriver != NULL) { 602 sp<NuPlayerDriver> driver = mDriver.promote(); 603 if (driver != NULL) { 604 driver->notifyResetComplete(); 605 } 606 } 607} 608 609void NuPlayer::postScanSources() { 610 if (mScanSourcesPending) { 611 return; 612 } 613 614 sp<AMessage> msg = new AMessage(kWhatScanSources, id()); 615 msg->setInt32("generation", mScanSourcesGeneration); 616 msg->post(); 617 618 mScanSourcesPending = true; 619} 620 621status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 622 if (*decoder != NULL) { 623 return OK; 624 } 625 626 sp<MetaData> meta = mSource->getFormat(audio); 627 628 if (meta == NULL) { 629 return -EWOULDBLOCK; 630 } 631 632 if (!audio) { 633 const char *mime; 634 CHECK(meta->findCString(kKeyMIMEType, &mime)); 635 mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime); 636 } 637 638 sp<AMessage> notify = 639 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, 640 id()); 641 642 *decoder = audio ? new Decoder(notify) : 643 new Decoder(notify, mNativeWindow); 644 looper()->registerHandler(*decoder); 645 646 (*decoder)->configure(meta); 647 648 int64_t durationUs; 649 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 650 sp<NuPlayerDriver> driver = mDriver.promote(); 651 if (driver != NULL) { 652 driver->notifyDuration(durationUs); 653 } 654 } 655 656 return OK; 657} 658 659status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 660 sp<AMessage> reply; 661 CHECK(msg->findMessage("reply", &reply)); 662 663 if ((audio && IsFlushingState(mFlushingAudio)) 664 || (!audio && IsFlushingState(mFlushingVideo))) { 665 reply->setInt32("err", INFO_DISCONTINUITY); 666 reply->post(); 667 return OK; 668 } 669 670 sp<ABuffer> accessUnit; 671 672 bool dropAccessUnit; 673 do { 674 status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); 675 676 if (err == -EWOULDBLOCK) { 677 return err; 678 } else if (err != OK) { 679 if (err == INFO_DISCONTINUITY) { 680 int32_t type; 681 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 682 683 bool formatChange = 684 (audio && 685 (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) 686 || (!audio && 687 (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); 688 689 bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; 690 691 ALOGI("%s discontinuity (formatChange=%d, time=%d)", 692 audio ? "audio" : "video", formatChange, timeChange); 693 694 if (audio) { 695 mSkipRenderingAudioUntilMediaTimeUs = -1; 696 } else { 697 mSkipRenderingVideoUntilMediaTimeUs = -1; 698 } 699 700 if (timeChange) { 701 sp<AMessage> extra; 702 if (accessUnit->meta()->findMessage("extra", &extra) 703 && extra != NULL) { 704 int64_t resumeAtMediaTimeUs; 705 if (extra->findInt64( 706 "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { 707 ALOGI("suppressing rendering of %s until %lld us", 708 audio ? "audio" : "video", resumeAtMediaTimeUs); 709 710 if (audio) { 711 mSkipRenderingAudioUntilMediaTimeUs = 712 resumeAtMediaTimeUs; 713 } else { 714 mSkipRenderingVideoUntilMediaTimeUs = 715 resumeAtMediaTimeUs; 716 } 717 } 718 } 719 } 720 721 mTimeDiscontinuityPending = 722 mTimeDiscontinuityPending || timeChange; 723 724 if (formatChange || timeChange) { 725 flushDecoder(audio, formatChange); 726 } else { 727 // This stream is unaffected by the discontinuity 728 729 if (audio) { 730 mFlushingAudio = FLUSHED; 731 } else { 732 mFlushingVideo = FLUSHED; 733 } 734 735 finishFlushIfPossible(); 736 737 return -EWOULDBLOCK; 738 } 739 } 740 741 reply->setInt32("err", err); 742 reply->post(); 743 return OK; 744 } 745 746 if (!audio) { 747 ++mNumFramesTotal; 748 } 749 750 dropAccessUnit = false; 751 if (!audio 752 && mVideoLateByUs > 100000ll 753 && mVideoIsAVC 754 && !IsAVCReferenceFrame(accessUnit)) { 755 dropAccessUnit = true; 756 ++mNumFramesDropped; 757 } 758 } while (dropAccessUnit); 759 760 // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 761 762#if 0 763 int64_t mediaTimeUs; 764 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 765 ALOGV("feeding %s input buffer at media time %.2f secs", 766 audio ? "audio" : "video", 767 mediaTimeUs / 1E6); 768#endif 769 770 reply->setBuffer("buffer", accessUnit); 771 reply->post(); 772 773 return OK; 774} 775 776void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 777 // ALOGV("renderBuffer %s", audio ? "audio" : "video"); 778 779 sp<AMessage> reply; 780 CHECK(msg->findMessage("reply", &reply)); 781 782 if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { 783 // We're currently attempting to flush the decoder, in order 784 // to complete this, the decoder wants all its buffers back, 785 // so we don't want any output buffers it sent us (from before 786 // we initiated the flush) to be stuck in the renderer's queue. 787 788 ALOGV("we're still flushing the %s decoder, sending its output buffer" 789 " right back.", audio ? "audio" : "video"); 790 791 reply->post(); 792 return; 793 } 794 795 sp<ABuffer> buffer; 796 CHECK(msg->findBuffer("buffer", &buffer)); 797 798 int64_t &skipUntilMediaTimeUs = 799 audio 800 ? mSkipRenderingAudioUntilMediaTimeUs 801 : mSkipRenderingVideoUntilMediaTimeUs; 802 803 if (skipUntilMediaTimeUs >= 0) { 804 int64_t mediaTimeUs; 805 CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); 806 807 if (mediaTimeUs < skipUntilMediaTimeUs) { 808 ALOGV("dropping %s buffer at time %lld as requested.", 809 audio ? "audio" : "video", 810 mediaTimeUs); 811 812 reply->post(); 813 return; 814 } 815 816 skipUntilMediaTimeUs = -1; 817 } 818 819 mRenderer->queueBuffer(audio, buffer, reply); 820} 821 822void NuPlayer::notifyListener(int msg, int ext1, int ext2) { 823 if (mDriver == NULL) { 824 return; 825 } 826 827 sp<NuPlayerDriver> driver = mDriver.promote(); 828 829 if (driver == NULL) { 830 return; 831 } 832 833 driver->notifyListener(msg, ext1, ext2); 834} 835 836void NuPlayer::flushDecoder(bool audio, bool needShutdown) { 837 if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { 838 ALOGI("flushDecoder %s without decoder present", 839 audio ? "audio" : "video"); 840 } 841 842 // Make sure we don't continue to scan sources until we finish flushing. 843 ++mScanSourcesGeneration; 844 mScanSourcesPending = false; 845 846 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); 847 mRenderer->flush(audio); 848 849 FlushStatus newStatus = 850 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 851 852 if (audio) { 853 CHECK(mFlushingAudio == NONE 854 || mFlushingAudio == AWAITING_DISCONTINUITY); 855 856 mFlushingAudio = newStatus; 857 858 if (mFlushingVideo == NONE) { 859 mFlushingVideo = (mVideoDecoder != NULL) 860 ? AWAITING_DISCONTINUITY 861 : FLUSHED; 862 } 863 } else { 864 CHECK(mFlushingVideo == NONE 865 || mFlushingVideo == AWAITING_DISCONTINUITY); 866 867 mFlushingVideo = newStatus; 868 869 if (mFlushingAudio == NONE) { 870 mFlushingAudio = (mAudioDecoder != NULL) 871 ? AWAITING_DISCONTINUITY 872 : FLUSHED; 873 } 874 } 875} 876 877} // namespace android 878