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