NuPlayer.cpp revision b58ce9f5e8d0696f9571a94ba5fc05f4500f663f
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 <surfaceflinger/Surface.h> 42#include <gui/ISurfaceTexture.h> 43 44#include "avc_utils.h" 45 46namespace android { 47 48//////////////////////////////////////////////////////////////////////////////// 49 50NuPlayer::NuPlayer() 51 : mUIDValid(false), 52 mVideoIsAVC(false), 53 mAudioEOS(false), 54 mVideoEOS(false), 55 mScanSourcesPending(false), 56 mScanSourcesGeneration(0), 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 LOGV("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 LOGV("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 LOGV("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 LOGV("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 LOGV("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 LOGV("got %s decoder EOS", audio ? "audio" : "video"); 288 } else { 289 LOGV("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 LOGV("decoder %s flush completed", audio ? "audio" : "video"); 309 310 if (needShutdown) { 311 LOGV("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 LOGV("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 LOGV("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 LOGV("%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 LOGE("Received error from %s decoder, aborting playback.", 386 audio ? "audio" : "video"); 387 388 mRenderer->queueEOS(audio, UNKNOWN_ERROR); 389 } else { 390 CHECK_EQ((int)what, (int)ACodec::kWhatDrainThisBuffer); 391 392 renderBuffer(audio, codecRequest); 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 LOGV("reached %s EOS", audio ? "audio" : "video"); 418 } else { 419 LOGE("%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 LOGV("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 LOGV("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 LOGV("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 if (mAudioDecoder != NULL) { 494 flushDecoder(true /* audio */, true /* needShutdown */); 495 } 496 497 if (mVideoDecoder != NULL) { 498 flushDecoder(false /* audio */, true /* needShutdown */); 499 } 500 501 mResetInProgress = true; 502 break; 503 } 504 505 case kWhatSeek: 506 { 507 int64_t seekTimeUs; 508 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 509 510 LOGV("kWhatSeek seekTimeUs=%lld us (%.2f secs)", 511 seekTimeUs, seekTimeUs / 1E6); 512 513 mSource->seekTo(seekTimeUs); 514 515 if (mDriver != NULL) { 516 sp<NuPlayerDriver> driver = mDriver.promote(); 517 if (driver != NULL) { 518 driver->notifySeekComplete(); 519 } 520 } 521 522 break; 523 } 524 525 case kWhatPause: 526 { 527 CHECK(mRenderer != NULL); 528 mRenderer->pause(); 529 break; 530 } 531 532 case kWhatResume: 533 { 534 CHECK(mRenderer != NULL); 535 mRenderer->resume(); 536 break; 537 } 538 539 default: 540 TRESPASS(); 541 break; 542 } 543} 544 545void NuPlayer::finishFlushIfPossible() { 546 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { 547 return; 548 } 549 550 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { 551 return; 552 } 553 554 LOGV("both audio and video are flushed now."); 555 556 mRenderer->signalTimeDiscontinuity(); 557 558 if (mAudioDecoder != NULL) { 559 mAudioDecoder->signalResume(); 560 } 561 562 if (mVideoDecoder != NULL) { 563 mVideoDecoder->signalResume(); 564 } 565 566 mFlushingAudio = NONE; 567 mFlushingVideo = NONE; 568 569 if (mResetInProgress) { 570 LOGV("reset completed"); 571 572 mResetInProgress = false; 573 finishReset(); 574 } else if (mResetPostponed) { 575 (new AMessage(kWhatReset, id()))->post(); 576 mResetPostponed = false; 577 } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 578 postScanSources(); 579 } 580} 581 582void NuPlayer::finishReset() { 583 CHECK(mAudioDecoder == NULL); 584 CHECK(mVideoDecoder == NULL); 585 586 ++mScanSourcesGeneration; 587 mScanSourcesPending = false; 588 589 mRenderer.clear(); 590 591 if (mSource != NULL) { 592 mSource->stop(); 593 mSource.clear(); 594 } 595 596 if (mDriver != NULL) { 597 sp<NuPlayerDriver> driver = mDriver.promote(); 598 if (driver != NULL) { 599 driver->notifyResetComplete(); 600 } 601 } 602} 603 604void NuPlayer::postScanSources() { 605 if (mScanSourcesPending) { 606 return; 607 } 608 609 sp<AMessage> msg = new AMessage(kWhatScanSources, id()); 610 msg->setInt32("generation", mScanSourcesGeneration); 611 msg->post(); 612 613 mScanSourcesPending = true; 614} 615 616status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 617 if (*decoder != NULL) { 618 return OK; 619 } 620 621 sp<MetaData> meta = mSource->getFormat(audio); 622 623 if (meta == NULL) { 624 return -EWOULDBLOCK; 625 } 626 627 if (!audio) { 628 const char *mime; 629 CHECK(meta->findCString(kKeyMIMEType, &mime)); 630 mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime); 631 } 632 633 sp<AMessage> notify = 634 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, 635 id()); 636 637 *decoder = audio ? new Decoder(notify) : 638 new Decoder(notify, mNativeWindow); 639 looper()->registerHandler(*decoder); 640 641 (*decoder)->configure(meta); 642 643 int64_t durationUs; 644 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 645 sp<NuPlayerDriver> driver = mDriver.promote(); 646 if (driver != NULL) { 647 driver->notifyDuration(durationUs); 648 } 649 } 650 651 return OK; 652} 653 654status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 655 sp<AMessage> reply; 656 CHECK(msg->findMessage("reply", &reply)); 657 658 if ((audio && IsFlushingState(mFlushingAudio)) 659 || (!audio && IsFlushingState(mFlushingVideo))) { 660 reply->setInt32("err", INFO_DISCONTINUITY); 661 reply->post(); 662 return OK; 663 } 664 665 sp<ABuffer> accessUnit; 666 667 bool dropAccessUnit; 668 do { 669 status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); 670 671 if (err == -EWOULDBLOCK) { 672 return err; 673 } else if (err != OK) { 674 if (err == INFO_DISCONTINUITY) { 675 int32_t type; 676 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 677 678 bool formatChange = 679 type == ATSParser::DISCONTINUITY_FORMATCHANGE; 680 681 LOGV("%s discontinuity (formatChange=%d)", 682 audio ? "audio" : "video", formatChange); 683 684 if (audio) { 685 mSkipRenderingAudioUntilMediaTimeUs = -1; 686 } else { 687 mSkipRenderingVideoUntilMediaTimeUs = -1; 688 } 689 690 sp<AMessage> extra; 691 if (accessUnit->meta()->findMessage("extra", &extra) 692 && extra != NULL) { 693 int64_t resumeAtMediaTimeUs; 694 if (extra->findInt64( 695 "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { 696 LOGI("suppressing rendering of %s until %lld us", 697 audio ? "audio" : "video", resumeAtMediaTimeUs); 698 699 if (audio) { 700 mSkipRenderingAudioUntilMediaTimeUs = 701 resumeAtMediaTimeUs; 702 } else { 703 mSkipRenderingVideoUntilMediaTimeUs = 704 resumeAtMediaTimeUs; 705 } 706 } 707 } 708 709 flushDecoder(audio, formatChange); 710 } 711 712 reply->setInt32("err", err); 713 reply->post(); 714 return OK; 715 } 716 717 if (!audio) { 718 ++mNumFramesTotal; 719 } 720 721 dropAccessUnit = false; 722 if (!audio 723 && mVideoLateByUs > 100000ll 724 && mVideoIsAVC 725 && !IsAVCReferenceFrame(accessUnit)) { 726 dropAccessUnit = true; 727 ++mNumFramesDropped; 728 } 729 } while (dropAccessUnit); 730 731 // LOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 732 733#if 0 734 int64_t mediaTimeUs; 735 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 736 LOGV("feeding %s input buffer at media time %.2f secs", 737 audio ? "audio" : "video", 738 mediaTimeUs / 1E6); 739#endif 740 741 reply->setObject("buffer", accessUnit); 742 reply->post(); 743 744 return OK; 745} 746 747void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 748 // LOGV("renderBuffer %s", audio ? "audio" : "video"); 749 750 sp<AMessage> reply; 751 CHECK(msg->findMessage("reply", &reply)); 752 753 if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { 754 // We're currently attempting to flush the decoder, in order 755 // to complete this, the decoder wants all its buffers back, 756 // so we don't want any output buffers it sent us (from before 757 // we initiated the flush) to be stuck in the renderer's queue. 758 759 LOGV("we're still flushing the %s decoder, sending its output buffer" 760 " right back.", audio ? "audio" : "video"); 761 762 reply->post(); 763 return; 764 } 765 766 sp<RefBase> obj; 767 CHECK(msg->findObject("buffer", &obj)); 768 769 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get()); 770 771 int64_t &skipUntilMediaTimeUs = 772 audio 773 ? mSkipRenderingAudioUntilMediaTimeUs 774 : mSkipRenderingVideoUntilMediaTimeUs; 775 776 if (skipUntilMediaTimeUs >= 0) { 777 int64_t mediaTimeUs; 778 CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); 779 780 if (mediaTimeUs < skipUntilMediaTimeUs) { 781 LOGV("dropping %s buffer at time %lld as requested.", 782 audio ? "audio" : "video", 783 mediaTimeUs); 784 785 reply->post(); 786 return; 787 } 788 789 skipUntilMediaTimeUs = -1; 790 } 791 792 mRenderer->queueBuffer(audio, buffer, reply); 793} 794 795void NuPlayer::notifyListener(int msg, int ext1, int ext2) { 796 if (mDriver == NULL) { 797 return; 798 } 799 800 sp<NuPlayerDriver> driver = mDriver.promote(); 801 802 if (driver == NULL) { 803 return; 804 } 805 806 driver->notifyListener(msg, ext1, ext2); 807} 808 809void NuPlayer::flushDecoder(bool audio, bool needShutdown) { 810 // Make sure we don't continue to scan sources until we finish flushing. 811 ++mScanSourcesGeneration; 812 mScanSourcesPending = false; 813 814 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); 815 mRenderer->flush(audio); 816 817 FlushStatus newStatus = 818 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 819 820 if (audio) { 821 CHECK(mFlushingAudio == NONE 822 || mFlushingAudio == AWAITING_DISCONTINUITY); 823 824 mFlushingAudio = newStatus; 825 826 if (mFlushingVideo == NONE) { 827 mFlushingVideo = (mVideoDecoder != NULL) 828 ? AWAITING_DISCONTINUITY 829 : FLUSHED; 830 } 831 } else { 832 CHECK(mFlushingVideo == NONE 833 || mFlushingVideo == AWAITING_DISCONTINUITY); 834 835 mFlushingVideo = newStatus; 836 837 if (mFlushingAudio == NONE) { 838 mFlushingAudio = (mAudioDecoder != NULL) 839 ? AWAITING_DISCONTINUITY 840 : FLUSHED; 841 } 842 } 843} 844 845} // namespace android 846